Skip to content

Commit eaee7e0

Browse files
Merge remote-tracking branch 'origin/main' into docs-72-stacked-pull-request-workflow
# Conflicts: # src/docs/Ways-of-Working/Branching-and-Merging.md
2 parents 8a04d13 + 7df16fd commit eaee7e0

68 files changed

Lines changed: 3359 additions & 1215 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/scripts/Update-DocumentationIndex.ps1

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,21 @@ $Start = '<!-- INDEX:START -->'
4444
$End = '<!-- INDEX:END -->'
4545
$Utf8 = [System.Text.UTF8Encoding]::new($false)
4646

47+
function ConvertTo-LineEnding {
48+
param(
49+
[string]$Text,
50+
[string]$NewLine
51+
)
52+
return [regex]::Replace($Text, '\r\n|\r|\n', $NewLine)
53+
}
54+
55+
function Get-LineEnding {
56+
param([string]$Text)
57+
$match = [regex]::Match($Text, '\r\n|\r|\n')
58+
if ($match.Success) { return $match.Value }
59+
return [Environment]::NewLine
60+
}
61+
4762
function Read-FrontMatter {
4863
param([string]$Path)
4964
$meta = @{}
@@ -97,7 +112,7 @@ function Get-RelKey {
97112
}
98113

99114
function Get-IndexTable {
100-
param([string]$IndexPath, [hashtable]$Order)
115+
param([string]$IndexPath, [hashtable]$Order, [string]$NewLine)
101116
$dir = Split-Path -Parent $IndexPath
102117
$subdirs = @(Get-ChildItem -LiteralPath $dir -Directory |
103118
Where-Object { Test-Path (Join-Path $_.FullName 'index.md') } | Sort-Object Name)
@@ -133,24 +148,27 @@ function Get-IndexTable {
133148
$lines.Add("| $header | Description |")
134149
$lines.Add('| --- | --- |')
135150
foreach ($r in $sorted) { $lines.Add("| [$($r.Title)]($($r.Link)) | $($r.Desc) |") }
136-
return ($lines -join "`n")
151+
return ($lines -join $NewLine)
137152
}
138153

139154
function Get-Rendered {
140155
param([string]$IndexPath, [hashtable]$Order)
141156
$text = [System.IO.File]::ReadAllText($IndexPath)
142157
if (($text -notlike "*$Start*") -or ($text -notlike "*$End*")) { return $null }
158+
$newLine = Get-LineEnding $text
159+
$text = ConvertTo-LineEnding $text $newLine
143160
$head = $text.Substring(0, $text.IndexOf($Start) + $Start.Length)
144161
$tail = $text.Substring($text.IndexOf($End))
145-
return "$head`n`n$(Get-IndexTable $IndexPath $Order)`n`n$tail"
162+
return "$head$newLine$newLine$(Get-IndexTable $IndexPath $Order $newLine)$newLine$newLine$tail"
146163
}
147164

148165
$order = Get-NavOrder
149166
$stale = [System.Collections.Generic.List[string]]::new()
150167
foreach ($index in (Get-ChildItem -LiteralPath $Docs -Recurse -File -Filter index.md | Sort-Object FullName)) {
151168
$rendered = Get-Rendered $index.FullName $order
152169
if ($null -eq $rendered) { continue }
153-
if ($rendered -eq [System.IO.File]::ReadAllText($index.FullName)) { continue }
170+
$current = [System.IO.File]::ReadAllText($index.FullName)
171+
if ((ConvertTo-LineEnding $rendered "`n") -eq (ConvertTo-LineEnding $current "`n")) { continue }
154172
$stale.Add((($index.FullName.Substring($Root.Length).TrimStart('\', '/')) -replace '\\', '/'))
155173
if (-not $Check) { [System.IO.File]::WriteAllText($index.FullName, $rendered, $Utf8) }
156174
}

bootstrap/AGENTS.template.md

Lines changed: 129 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,134 @@
22

33
The single starting point for any agent, in any repository. Before doing anything else, make sure the central workspace exists locally, then read from it.
44

5+
## Main directive
6+
7+
Everything is a work in progress and can be updated and improved. Fix a small problem when it is directly in scope; register a larger or unrelated problem as an issue in the repository that owns it.
8+
59
## First — bootstrap the workspace
610

7-
The workspace is a git-isolated clone of the central repositories under `~/.msx`. Set it up (idempotent — clones what is missing, attempts to fast-forward the rest):
11+
The workspace is a git-isolated clone of the central repositories under `~/.msx`. Set it up before reading context. Existing context repositories must be clean, on their default branch, and exactly synchronized with the remote:
812

913
```powershell
10-
$docs = Join-Path $HOME '.msx/docs'
14+
$workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msx' }
15+
$docsUrl = if ($env:MSX_DOCS_URL) { $env:MSX_DOCS_URL } else { 'https://github.com/MSXOrg/docs.git' }
16+
$memoryUrl = if ($env:MSX_MEMORY_URL) { $env:MSX_MEMORY_URL } else { 'https://github.com/MSXOrg/memory.git' }
17+
$docs = Join-Path $workspaceRoot 'docs'
18+
$docsBacking = "$docs.git"
1119
if ((Test-Path $docs) -and -not (Test-Path (Join-Path $docs '.git'))) {
1220
throw "$docs exists but is not a git repository. Remove it and re-run."
1321
}
1422
if (-not (Test-Path (Join-Path $docs '.git'))) {
15-
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null
16-
git clone https://github.com/MSXOrg/docs.git $docs
23+
if (-not (Test-Path $docsBacking)) {
24+
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null
25+
git clone --bare $docsUrl $docsBacking
26+
if ($LASTEXITCODE -ne 0) {
27+
throw "Bare clone of MSXOrg/docs failed (exit $LASTEXITCODE). Check network access and credentials."
28+
}
29+
}
30+
if ((git --git-dir=$docsBacking rev-parse --is-bare-repository) -ne 'true') {
31+
throw "$docsBacking exists but is not a bare repository."
32+
}
33+
if ((git --git-dir=$docsBacking remote get-url origin) -ne $docsUrl) {
34+
throw "$docsBacking origin does not match canonical $docsUrl."
35+
}
36+
$refspec = '+refs/heads/*:refs/remotes/origin/*'
37+
if ($refspec -notin @(git --git-dir=$docsBacking config --get-all remote.origin.fetch)) {
38+
git --git-dir=$docsBacking config --add remote.origin.fetch $refspec
39+
if ($LASTEXITCODE -ne 0) { throw "Could not configure $docsBacking." }
40+
}
41+
git --git-dir=$docsBacking fetch origin --prune --quiet
42+
if ($LASTEXITCODE -ne 0) { throw "Could not refresh $docsBacking. Do not use stale context." }
43+
git --git-dir=$docsBacking remote set-head origin --auto | Out-Null
44+
if ($LASTEXITCODE -ne 0) { throw "Could not detect the MSXOrg/docs default branch." }
45+
$defaultRef = (git --git-dir=$docsBacking symbolic-ref --short refs/remotes/origin/HEAD | Out-String).Trim()
46+
if ($LASTEXITCODE -ne 0) { throw "Could not resolve origin/HEAD in $docsBacking." }
47+
$defaultBranch = $defaultRef -replace '^origin/', ''
48+
$remoteHead = (git --git-dir=$docsBacking rev-parse $defaultRef | Out-String).Trim()
49+
if ($LASTEXITCODE -ne 0) { throw "Could not resolve $defaultRef in $docsBacking." }
50+
$localRef = "refs/heads/$defaultBranch"
51+
$localHead = (git --git-dir=$docsBacking rev-parse --verify $localRef 2>$null | Out-String).Trim()
52+
if ($LASTEXITCODE -eq 128) {
53+
git --git-dir=$docsBacking update-ref $localRef $remoteHead
54+
} elseif ($LASTEXITCODE -ne 0) {
55+
throw "Could not inspect $localRef in $docsBacking."
56+
} elseif ($localHead -ne $remoteHead) {
57+
git --git-dir=$docsBacking merge-base --is-ancestor $localHead $remoteHead
58+
if ($LASTEXITCODE -ne 0) { throw "$localRef is ahead or diverged in $docsBacking." }
59+
if ("branch $localRef" -in @(git --git-dir=$docsBacking worktree list --porcelain)) {
60+
throw "$localRef is checked out elsewhere. Update that worktree first."
61+
}
62+
git --git-dir=$docsBacking update-ref $localRef $remoteHead $localHead
63+
}
64+
if ($LASTEXITCODE -ne 0 -or (git --git-dir=$docsBacking rev-parse $localRef) -ne $remoteHead) {
65+
throw "$localRef is not exactly synchronized with $defaultRef."
66+
}
67+
git --git-dir=$docsBacking worktree add $docs $defaultBranch
68+
if ($LASTEXITCODE -ne 0) {
69+
throw "Could not create the canonical MSXOrg/docs worktree at $docs."
70+
}
71+
} else {
72+
if ((git -C $docs remote get-url origin) -ne $docsUrl) {
73+
throw "$docs origin does not match canonical $docsUrl."
74+
}
75+
$refspec = '+refs/heads/*:refs/remotes/origin/*'
76+
if ($refspec -notin @(git -C $docs config --get-all remote.origin.fetch)) {
77+
git -C $docs config --add remote.origin.fetch $refspec
78+
if ($LASTEXITCODE -ne 0) {
79+
throw "Could not configure remote tracking branches for MSXOrg/docs (exit $LASTEXITCODE)."
80+
}
81+
}
82+
git -C $docs fetch origin --prune --quiet
1783
if ($LASTEXITCODE -ne 0) {
18-
throw "git clone of MSXOrg/docs failed (exit $LASTEXITCODE). Check network access and github.com credentials, then re-run."
84+
throw "git fetch of MSXOrg/docs failed (exit $LASTEXITCODE). Do not use stale context."
85+
}
86+
git -C $docs remote set-head origin --auto | Out-Null
87+
if ($LASTEXITCODE -ne 0) { throw "Could not detect the MSXOrg/docs default branch." }
88+
$defaultRef = (git -C $docs symbolic-ref --short refs/remotes/origin/HEAD | Out-String).Trim()
89+
if ($LASTEXITCODE -ne 0) { throw "Could not resolve origin/HEAD in $docs." }
90+
$defaultBranch = $defaultRef -replace '^origin/', ''
91+
$branch = (git -C $docs branch --show-current | Out-String).Trim()
92+
if ($branch -ne $defaultBranch) {
93+
throw "$docs is on '$branch', not '$defaultBranch'. Switch branches before using this context."
94+
}
95+
if (@(git -C $docs status --porcelain).Count -gt 0) {
96+
throw "$docs has uncommitted changes. Resolve them before using this context."
97+
}
98+
git -C $docs merge --ff-only --quiet $defaultRef
99+
if ($LASTEXITCODE -ne 0) {
100+
throw "MSXOrg/docs cannot fast-forward to $defaultRef. Do not use stale context."
101+
}
102+
if ((git -C $docs rev-parse HEAD) -ne (git -C $docs rev-parse $defaultRef)) {
103+
throw "$docs is not exactly synchronized with $defaultRef. Reconcile local commits before using this context."
19104
}
20105
}
21-
pwsh (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1')
106+
$projects = @(
107+
@{
108+
Name = 'MSXOrg'
109+
Path = ''
110+
DocsUrl = $docsUrl
111+
MemoryUrl = $memoryUrl
112+
}
113+
# Add project-specific entries when this template is adopted there:
114+
# @{
115+
# Name = 'PSModule'
116+
# Path = 'projects/PSModule'
117+
# DocsUrl = 'https://github.com/PSModule/docs.git'
118+
# MemoryUrl = 'https://github.com/PSModule/memory.git'
119+
# }
120+
)
121+
& (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Root $workspaceRoot -Project $projects
122+
if ($LASTEXITCODE -ne 0) {
123+
throw "Context synchronization failed. Do not read context until every project is current."
124+
}
22125
```
23126

127+
Keep the MSXOrg entry and add only the additional project coordinates required by repositories that inherit this template. Every project reuses the same synchronization and validation implementation.
128+
24129
This produces:
25130

26-
- `~/.msx/docs` — how work is done: ways of working, coding standards, and agent roles. The same content published at <https://msxorg.github.io/docs/>.
131+
- `~/.msx/docs.git` — bare backing repository for central docs.
132+
- `~/.msx/docs` — clean, readable main worktree containing ways of working, standards, and workflow guidance.
27133
- `~/.msx/memory` — what has been learned before: durable notes and prior session context.
28134

29135
Each clone has repository-local git config only; it never modifies the global git config or the repository being worked in (git still reads them, but only repository-local config is written).
@@ -32,10 +138,22 @@ Each clone has repository-local git config only; it never modifies the global gi
32138
33139
## Then — read before acting
34140

35-
1. Read the relevant pages under `~/.msx/docs` for the task at hand.
36-
2. Read `~/.msx/memory` for prior decisions, pitfalls, and context.
141+
1. Start at `~/.msx/docs/src/docs/index.md`.
142+
2. Follow the Ways of Working index to `Workflow.md`.
143+
3. Infer the current stage from the task and its artifacts, then read the linked stage procedure.
144+
4. Read the relevant standards, repository context, and `~/.msx/memory`.
145+
146+
Clear task language may shortcut the index trail: `Review this PR <link>` enters Review, `Make this issue <description>` enters Define, and `Implement <issue>` enters Implement. The linked documentation owns each procedure; this file does not define a separate agent or skill.
147+
148+
## Work in the selected repository
149+
150+
1. Read its `README.md` to understand the repository and its build.
151+
2. Read its `CONTRIBUTING.md` for the contribution and review contract.
152+
3. Use a dedicated worktree and the branch naming defined by the canonical Ways of Working.
153+
4. Make small, descriptive micro-commits and push every commit so remote state, CI, and the draft pull request stay current.
154+
5. Capture verified reusable lessons in organization memory, following that repository's own instructions.
37155

38156
## Two write rules
39157

40-
- **Docs change through pull requests.** Branch inside `~/.msx/docs` and open a pull request; never push its `main`.
41-
- **Memory pushes to main.** Commit and push notes directly inside `~/.msx/memory`; no pull request.
158+
- **Docs change through topic worktrees and pull requests.** Create a topic worktree from `~/.msx/docs.git`; never branch or work inside the canonical `~/.msx/docs` main worktree.
159+
- **Memory follows repository policy.** Read the selected memory repository's `AGENTS.md` and `CONTRIBUTING.md` before writing.

0 commit comments

Comments
 (0)