Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/instructions/dotnet-framework.instructions.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
---
description: 'Guidance for working with .NET Framework projects. Includes project structure, C# language version, NuGet management, and best practices.'
applyTo: '**/*.csproj, **/*.cs'
---
Expand All @@ -18,7 +18,7 @@ applyTo: '**/*.csproj, **/*.cs'
- Example: `<Compile Include="Path\To\NewFile.cs" />`

- **No Implicit Imports**: Unlike SDK-style projects, .NET Framework projects do not automatically import common namespaces or assemblies

- **Build Configuration**: Contains explicit `<PropertyGroup>` sections for Debug/Release configurations

- **Output Paths**: Explicit `<OutputPath>` and `<IntermediateOutputPath>` definitions
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/patch-installer-cd.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Patch Installer
name: Patch Installer

# Builds the FieldWorks Patch Installer on the specified `base_release`
# If `make_release` is true, uploads installers to https://flex-updates.s3.amazonaws.com/?prefix=jobs/FieldWorks-Win-all-Release-Patch.
Expand Down Expand Up @@ -151,7 +151,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
dotnet-version: |
3.1.x
5.0.x

Expand All @@ -166,7 +166,7 @@ jobs:
choco install wixtoolset --version 3.11.2 --allow-downgrade --force
echo "C:\Program Files (x86)\WiX Toolset v3.11\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
if: github.event_name != 'pull_request'

- name: Import Base Build Artifacts
shell: pwsh
run: |
Expand Down Expand Up @@ -211,7 +211,7 @@ jobs:
)
$valueName = "Switch.System.DisableTempFileCollectionDirectoryFeature"
$expectedValue = "true"

foreach ($path in $regPaths) {
Write-Host "Adding or updating registry value in $path..."
if (-not (Test-Path $path)) {
Expand All @@ -238,11 +238,11 @@ jobs:
$results = Select-String -Path "build.log" -Pattern "^\s*[1-9][0-9]* Error\(s\)"
if ($results) {
foreach ($result in $results) {
Write-Host "Found errors in build.log $($result.LineNumber): $($result.Line)" -ForegroundColor red
Write-Host "Found errors in build.log $($result.LineNumber): $($result.Line)" -ForegroundColor red
}
exit 1
} else {
Write-Host "No errors found" -ForegroundColor green
Write-Host "No errors found" -ForegroundColor green
exit 0
}

Expand Down
11 changes: 5 additions & 6 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"chat.promptFilesRecommendations": {
"speckit.constitution": true,
"speckit.specify": true,
Expand Down Expand Up @@ -95,11 +95,7 @@
// Tasks not listed require manual confirmation.
// ============================================================================
"chat.tools.tasks.allowedTasks": [
// Build tasks (safe - only produce artifacts)
"Build",
"Build Release",

// Test tasks (safe - no external changes)
// Test tasks remain auto-approved so Linux hosts surface the not-supported message.
"Test",
"Test (no build)",

Expand All @@ -125,6 +121,9 @@
]
// ============================================================================
// TASKS REQUIRING MANUAL APPROVAL (not in allowedTasks):
// - Build (Windows only)
// - Build Release (Windows only)
// - Build Tests (Windows only)
// - Test (with filter) (has user input prompt)
// - Test (specific project) (has user input prompt)
// - Agent: Propose updates (modifies files)
Expand Down
15 changes: 7 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# AI Agent Playbook for FieldWorks
# AI Agent Playbook for FieldWorks

Minimal, high-signal guidance for coding agents in this repository.

Expand All @@ -8,10 +8,6 @@ Minimal, high-signal guidance for coding agents in this repository.
- Build with `.\build.ps1`.
- Test with `.\test.ps1`.
- Do not bypass repository scripts for normal build/test work.
- Before committing or pushing, run the existing VS Code task `CI: Full local check`.
- After any rebase, merge, cherry-pick, or manual conflict resolution, run `CI: Whitespace check` before committing.
- If `CI: Whitespace check` rewrites files, review and restage those files, then rerun the task until it passes cleanly.
- When commit history changes, run `CI: Commit messages` before pushing.

## Critical constraints

Expand All @@ -25,6 +21,10 @@ Minimal, high-signal guidance for coding agents in this repository.
- Apply `.github/instructions/navigation.instructions.md` for structural navigation and hidden-dependency handling.
- Use `Src/AGENTS.md`, `.github/AGENTS.md`, `FLExInstaller/AGENTS.md`, and `openspec/AGENTS.md` for area-specific guidance.

## External Dependencies (LibLcm)

FieldWorks is built upon the `liblcm` (Language & Culture Model) repository, which provides the main data model and FDO (FieldWorks Data Objects) layers used by FieldWorks. The liblcm library is the core FieldWorks model for language and culture data and includes interfaces like `IScrFootnoteFactory` that FieldWorks consumes. If you cannot find a core data model definition within this workspace, ask for access to the `liblcm` repository to reference the source.

## Serena navigation

- Prefer Serena symbolic tools for code discovery/navigation before broad file reads.
Expand All @@ -40,6 +40,5 @@ Minimal, high-signal guidance for coding agents in this repository.
## Validation checklist

1. Run the relevant build/test scripts for touched areas.
2. Run `CI: Full local check` before commit/push; use `CI: Whitespace check` immediately after conflict resolution.
3. Keep edits scoped and avoid unrelated refactors.
4. Update docs only when behavior/contracts/process changed.
2. Keep edits scoped and avoid unrelated refactors.
3. Update docs only when behavior/contracts/process changed.
111 changes: 109 additions & 2 deletions Build/Agent/FwBuildHelpers.psm1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<#
<#
.SYNOPSIS
Shared helper functions for FieldWorks build and test scripts.

Expand Down Expand Up @@ -474,6 +474,110 @@ function Test-GitTrackedFile {
}
}

function Get-NewestWriteTimeUtc {
<#!
.SYNOPSIS
Returns the newest LastWriteTimeUtc among matching files under one or more roots.
#>
param(
[Parameter(Mandatory)][string[]]$Paths,
[string[]]$IncludePatterns = @()
)

$latest = [datetime]::MinValue
foreach ($path in $Paths) {
if (-not (Test-Path $path)) {
continue
}

$items = Get-ChildItem -Path $path -Recurse -File -ErrorAction SilentlyContinue
if ($IncludePatterns.Count -gt 0) {
$items = $items | Where-Object {
$fileName = $_.Name
foreach ($pattern in $IncludePatterns) {
if ($fileName -like $pattern) {
return $true
}
}
return $false
}
}
Comment on lines +493 to +504

foreach ($item in $items) {
if ($item.LastWriteTimeUtc -gt $latest) {
$latest = $item.LastWriteTimeUtc
}
}
}

return $latest
}

function Get-OldestWriteTimeUtc {
<#!
.SYNOPSIS
Returns the oldest LastWriteTimeUtc across a set of required artifact files.
Returns $null if any required artifact is missing.
#>
param(
[Parameter(Mandatory)][string[]]$Paths
)

$oldest = [datetime]::MaxValue
$foundAny = $false
foreach ($path in $Paths) {
if (-not (Test-Path $path)) {
return $null
}

$item = Get-Item -LiteralPath $path -ErrorAction Stop
$foundAny = $true
if ($item.LastWriteTimeUtc -lt $oldest) {
$oldest = $item.LastWriteTimeUtc
}
}

if (-not $foundAny) {
return $null
}

return $oldest
}

function Test-ViewsNativeArtifactsStale {
<#!
.SYNOPSIS
Returns $true when the Views/FwKernel native artifacts are missing or older than relevant native inputs.
#>
param(
[Parameter(Mandatory)][string]$RepoRoot,
[Parameter(Mandatory)][string]$Configuration
)

$sourceRoots = @(
(Join-Path $RepoRoot 'Src\views'),
(Join-Path $RepoRoot 'Src\Kernel'),
(Join-Path $RepoRoot 'Src\Generic'),
(Join-Path $RepoRoot 'Include')
)
$sourcePatterns = @('*.cpp', '*.c', '*.cc', '*.h', '*.hpp', '*.ixx', '*.idl', '*.rc', '*.mak', '*.def', '*.bat')
$artifactPaths = @(
(Join-Path $RepoRoot "Output\$Configuration\Views.dll"),
(Join-Path $RepoRoot "Output\$Configuration\views.lib"),
(Join-Path $RepoRoot "Output\$Configuration\Common\FwKernelTlb.h"),
(Join-Path $RepoRoot "Obj\$Configuration\Views\autopch\VwRootBox.obj")
)

$latestSource = Get-NewestWriteTimeUtc -Paths $sourceRoots -IncludePatterns $sourcePatterns
$oldestArtifact = Get-OldestWriteTimeUtc -Paths $artifactPaths

if ($oldestArtifact -eq $null) {
return $true
}

return $latestSource -gt $oldestArtifact
}

# =============================================================================
# Module Exports
# =============================================================================
Expand All @@ -493,5 +597,8 @@ Export-ModuleMember -Function @(
'Exit-WorktreeLock',
'Remove-StaleObjFolders',
'Test-IsFileLockError',
'Invoke-WithFileLockRetry'
'Invoke-WithFileLockRetry',
'Get-NewestWriteTimeUtc',
'Get-OldestWriteTimeUtc',
'Test-ViewsNativeArtifactsStale'
)
3 changes: 2 additions & 1 deletion Build/Agent/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Build/Agent Scripts
# Build/Agent Scripts

PowerShell scripts for build, test, and CI orchestration.

Expand All @@ -11,6 +11,7 @@ PowerShell scripts for build, test, and CI orchestration.

| Script | Purpose |
|--------|---------|
| `Run-AllRenders.ps1` | Runs the DetailControls and RootSite render suites sequentially from one command without adding a meta test project. |
| `Summarize-NativeTestResults.ps1` | Parses native Unit++ logs and appends a pass/fail summary table to GitHub step summary. |

## GitHub Actions usage
Expand Down
18 changes: 10 additions & 8 deletions Build/Agent/Verify-FwDependencies.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<#
<#
.SYNOPSIS
Verifies that all FieldWorks build dependencies are available.

Expand Down Expand Up @@ -71,6 +71,8 @@ function Test-Dependency {
[string]$Required = "Required"
)

$isRequired = ($Required -eq "Required")

try {
$result = & $Check
if ($result) {
Expand All @@ -80,18 +82,18 @@ function Test-Dependency {
Write-Host " $result" -ForegroundColor DarkGray
}
}
return @{ Name = $Name; Found = $true; IsRequired = ($Required -eq "Required"); Info = $result }
return @{ Name = $Name; Found = $true; IsRequired = $isRequired; Info = $result }
}
else {
throw "Check returned null/false"
}
}
catch {
$color = if ($Required -eq "Required") { "Red" } else { "Yellow" }
$status = if ($Required -eq "Required") { "[FAIL]" } else { "[WARN]" }
$color = if ($isRequired) { "Red" } else { "Yellow" }
$status = if ($isRequired) { "[FAIL]" } else { "[WARN]" }
Write-Host "$status $Name" -ForegroundColor $color
Write-Host " $_" -ForegroundColor DarkGray
return @{ Name = $Name; Found = $false; IsRequired = ($Required -eq "Required"); Error = $_.ToString() }
return @{ Name = $Name; Found = $false; IsRequired = $isRequired; Error = $_.ToString() }
}
}

Expand Down Expand Up @@ -304,9 +306,9 @@ if ($Detailed) {
Write-Host "=== Summary ===" -ForegroundColor Cyan
}

$required = $results | Where-Object { $_.IsRequired -ne $false }
$missing = $required | Where-Object { -not $_.Found }
$optional = $results | Where-Object { $_.IsRequired -eq $false }
$required = @($results | Where-Object { $_.IsRequired -ne $false })
$missing = @($required | Where-Object { -not $_.Found })
$optional = @($results | Where-Object { $_.IsRequired -eq $false })

$totalRequired = ($required | Measure-Object).Count
$foundRequired = ($required | Where-Object { $_.Found } | Measure-Object).Count
Expand Down
36 changes: 3 additions & 33 deletions Build/Agent/fix-whitespace.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env pwsh
#!/usr/bin/env pwsh
$ErrorActionPreference = 'Stop'

# Import shared git helpers
Expand All @@ -10,39 +10,10 @@ function Get-BaseRef {
return (Get-DefaultBranchRef)
}

function Test-HasUtf8Bom {
param([Parameter(Mandatory)][string]$Path)

# Read only the first three bytes to check for a UTF-8 BOM to avoid loading the entire file.
$buffer = [byte[]]::new(3)
$stream = [System.IO.File]::OpenRead($Path)
try {
$bytesRead = $stream.Read($buffer, 0, 3)
}
finally {
$stream.Dispose()
}

if ($bytesRead -lt 3) { return $false }
return $buffer[0] -eq 0xEF -and $buffer[1] -eq 0xBB -and $buffer[2] -eq 0xBF
}

function Write-Utf8Text {
param(
[Parameter(Mandatory)][string]$Path,
[Parameter(Mandatory)][string]$Content,
[Parameter(Mandatory)][bool]$EmitBom
)

$encoding = New-Object System.Text.UTF8Encoding($EmitBom)
[System.IO.File]::WriteAllText($Path, $Content, $encoding)
}

function Format-FileWhitespace {
param([Parameter(Mandatory)][string]$Path)
if (-not (Test-Path -LiteralPath $Path)) { return }
try {
$hasUtf8Bom = Test-HasUtf8Bom -Path $Path
$raw = Get-Content -LiteralPath $Path -Raw -Encoding utf8
}
catch {
Expand All @@ -62,7 +33,7 @@ function Format-FileWhitespace {
# Join back and ensure exactly one trailing newline
$new = ($lines -join "`n") + "`n"
if ($new -ne $orig) {
Write-Utf8Text -Path $Path -Content $new -EmitBom $hasUtf8Bom
Set-Content -LiteralPath $Path -Value $new -Encoding utf8 -NoNewline
Write-Host "Fixed whitespace: $Path"
}
}
Expand All @@ -85,6 +56,5 @@ $files = $fixFiles | Where-Object { $_ -and (Test-Path $_) }

foreach ($f in $files) { Format-FileWhitespace -Path $f }

Write-Host "Whitespace fix completed. Review and stage the updated files before committing."
Write-Host "If check-whitespace reported an older commit in origin/main..HEAD, rewrite history with amend, squash, or rebase so that offending commit is no longer part of the branch."
Write-Host "Whitespace fix completed. Review changes, commit, and rebase as needed."
exit 0
6 changes: 5 additions & 1 deletion Build/Installer.legacy.targets
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Current">
<!-- ########################################################################################################## -->
<!-- ### Configuration properties - Review and edit these values as needed. ### -->
Expand Down Expand Up @@ -280,6 +280,10 @@
<!-- REVIEW (Hasso) 2018.04: not sure if this is files or a folder -->
<MergeModules Include="$(OutputDirForConfig)\Python\**\*" />
<!-- REVIEW (Hasso) 2018.04: not sure if this is files or a folder -->
<MergeModules Include="$(OutputDirForConfig)\ScrChecks.dll" />
<!-- this will be taken from DistFiles\Editorial Checks -->
<MergeModules Include="$(OutputDirForConfig)\ScrChecks.pdb" />
<!-- this will be taken from DistFiles\Editorial Checks -->
<MergeModules Include="$(OutputDirForConfig)\SilEncConverters40.dll" />
<MergeModules Include="$(OutputDirForConfig)\SilEncConverters40.tlb" />
<MergeModules Include="$(OutputDirForConfig)\Temp\**\*" />
Expand Down
Loading
Loading