kushi-agents 5.4.3 → 5.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/package.json +2 -2
- package/plugin/agents/kushi.agent.md +1 -0
- package/plugin/instructions/bootstrap-status-format.instructions.md +14 -13
- package/plugin/instructions/multi-user-shared-files.instructions.md +117 -87
- package/plugin/plugin.json +7 -4
- package/plugin/prompts/bootstrap.prompt.md +2 -1
- package/plugin/prompts/consolidate.prompt.md +4 -1
- package/plugin/prompts/migrate-files.prompt.md +29 -0
- package/plugin/skills/aggregate-project/SKILL.md +3 -3
- package/plugin/skills/bootstrap-project/SKILL.md +6 -6
- package/plugin/skills/consolidate-evidence/SKILL.md +94 -1
- package/plugin/skills/doctor/doctor.ps1 +101 -11
- package/plugin/skills/migrate-per-user-files/SKILL.md +47 -0
- package/plugin/skills/migrate-per-user-files/evals/evals.json +41 -0
- package/plugin/skills/migrate-per-user-files/migrate.ps1 +136 -0
- package/plugin/skills/migrate-per-user-files/references/migration-strategy.md +23 -0
- package/plugin/skills/pull-ado/SKILL.md +1 -1
- package/plugin/skills/pull-crm/SKILL.md +1 -1
- package/plugin/skills/pull-email/SKILL.md +1 -1
- package/plugin/skills/pull-loop/SKILL.md +1 -1
- package/plugin/skills/pull-meetings/SKILL.md +1 -1
- package/plugin/skills/pull-misc/SKILL.md +3 -3
- package/plugin/skills/pull-onenote/SKILL.md +1 -1
- package/plugin/skills/pull-sharepoint/SKILL.md +1 -1
- package/plugin/skills/pull-teams/SKILL.md +1 -1
- package/plugin/skills/refresh-project/SKILL.md +5 -5
- package/plugin/skills/self-check/SKILL.md +4 -2
- package/plugin/skills/self-check/run.ps1 +235 -1
- package/src/hooks-dispatcher.test.mjs +2 -2
- package/src/layout-portable.test.mjs +89 -0
- package/src/per-user-files.test.mjs +137 -0
- package/src/profile-coverage.test.mjs +84 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "consolidate-evidence"
|
|
3
|
-
version: "3.
|
|
3
|
+
version: "3.1.0"
|
|
4
4
|
description: "USE WHEN multiple contributors have pulled the same project AND the orchestrator (refresh-project / aggregate-project) needs a merged view at Evidence/_Consolidated/ for downstream skills (build-state, link-entities, ask-project). DO NOT USE manually — it's an internal pass. Capability: merges per-contributor Evidence/<alias>/<source>/ into Evidence/_Consolidated/ for a window using the 3-step reader fallback (_index → weekly → legacy). Latest-fact-wins; cites originating alias."
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -59,6 +59,98 @@ Snapshots are mostly per-source-of-truth (one canonical entity), so consolidatio
|
|
|
59
59
|
|
|
60
60
|
Append a `consolidation_runs:` entry: `{ window, contributors, files_written }`.
|
|
61
61
|
|
|
62
|
+
### Step 5 — Consolidate per-user authored files (v5.4.4+)
|
|
63
|
+
|
|
64
|
+
Per `multi-user-shared-files.instructions.md` § "Per-user authored files", three artifacts are written per-user under `Evidence/<alias>/<file>`. This step emits the cross-contributor rollup under `_Consolidated/<file>` for each. Deterministic merge — NO LLM. Idempotent: same input set produces byte-identical output.
|
|
65
|
+
|
|
66
|
+
This step **always runs** (even with a single contributor — a single-alias rollup is just a verbatim copy with an attribution header).
|
|
67
|
+
|
|
68
|
+
For each of the three files (`bootstrap-status.md`, `FOLLOW-UPS.md`, `OPEN-QUESTIONS-DRAFT.md`):
|
|
69
|
+
|
|
70
|
+
1. Walk `<project>/Evidence/<alias>/<file>` for every alias listed in `Evidence/contributors.yml` (skip aliases that don't have the file).
|
|
71
|
+
2. Apply the merge rules below.
|
|
72
|
+
3. Write the result atomically to `<project>/_Consolidated/<file>` (write to `<file>.tmp`, then rename).
|
|
73
|
+
|
|
74
|
+
#### `_Consolidated/bootstrap-status.md`
|
|
75
|
+
|
|
76
|
+
Shape:
|
|
77
|
+
|
|
78
|
+
```markdown
|
|
79
|
+
# Bootstrap Status (consolidated, <N> contributors)
|
|
80
|
+
|
|
81
|
+
> Auto-generated by `consolidate-evidence` Step 5 at <ISO-ts>. Source of truth lives under each `Evidence/<alias>/bootstrap-status.md`. Do not edit by hand.
|
|
82
|
+
|
|
83
|
+
## Contributors who have bootstrapped this project
|
|
84
|
+
|
|
85
|
+
| Alias | Display Name | Last Run | Mode | Outcome |
|
|
86
|
+
|---|---|---|---|---|
|
|
87
|
+
| <alias> | ... | ... | ... | ... |
|
|
88
|
+
|
|
89
|
+
## Latest discovery sweep results (most recent resolved per source, across all contributors)
|
|
90
|
+
|
|
91
|
+
| Source | Status | Discovered by | Discovered at |
|
|
92
|
+
|---|---|---|---|
|
|
93
|
+
| crm | resolved | ushak | 2026-05-27 09:42 EDT |
|
|
94
|
+
| ado | resolved | stand | 2026-05-25 11:01 EDT |
|
|
95
|
+
...
|
|
96
|
+
|
|
97
|
+
## Per-contributor bootstrap-status snapshots
|
|
98
|
+
|
|
99
|
+
### ushak — `Evidence/ushak/bootstrap-status.md`
|
|
100
|
+
|
|
101
|
+
<verbatim copy of that file's body, demoted one heading level>
|
|
102
|
+
|
|
103
|
+
### stand — `Evidence/stand/bootstrap-status.md`
|
|
104
|
+
|
|
105
|
+
<verbatim copy>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- The "Contributors" table is harvested from each per-user file's `## Run summary` row.
|
|
109
|
+
- The "Latest discovery sweep results" table is harvested from each per-user file's `## Context Artifact Status` table; per source, keep the row whose Status is `resolved` (or `populated`) with the most recent timestamp.
|
|
110
|
+
- Per-contributor snapshot bodies are copied verbatim with heading levels demoted (`#` → `##`, etc.) for unambiguous Markdown nesting.
|
|
111
|
+
|
|
112
|
+
#### `_Consolidated/FOLLOW-UPS.md`
|
|
113
|
+
|
|
114
|
+
Shape:
|
|
115
|
+
|
|
116
|
+
```markdown
|
|
117
|
+
# Follow-ups (consolidated, <N> contributors)
|
|
118
|
+
|
|
119
|
+
> Auto-generated by `consolidate-evidence` Step 5 at <ISO-ts>. Source of truth lives under each `Evidence/<alias>/FOLLOW-UPS.md`. Do not edit by hand.
|
|
120
|
+
|
|
121
|
+
## Open follow-ups
|
|
122
|
+
|
|
123
|
+
### <source> · <YYYY-MM-DD> · <alias> (also reported by: <other-alias>, ...)
|
|
124
|
+
|
|
125
|
+
<verbatim 5-field block from the originating alias's `Evidence/<alias>/FOLLOW-UPS.md`>
|
|
126
|
+
|
|
127
|
+
## Resolved follow-ups
|
|
128
|
+
|
|
129
|
+
<dedup-merged blocks tagged with originating alias>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- Dedup key per row: `(source, normalized first line of "Next-time-do")`. When two aliases report the same gap, keep the earliest-dated block and append "also reported by: <alias>" to the heading.
|
|
133
|
+
- Resolution status is per-alias — a row stays in "Open" if ANY contributor still has it Open.
|
|
134
|
+
|
|
135
|
+
#### `_Consolidated/OPEN-QUESTIONS-DRAFT.md`
|
|
136
|
+
|
|
137
|
+
Shape:
|
|
138
|
+
|
|
139
|
+
```markdown
|
|
140
|
+
# Open questions (consolidated, <N> contributors)
|
|
141
|
+
|
|
142
|
+
> Auto-generated by `consolidate-evidence` Step 5 at <ISO-ts>. Source of truth lives under each `Evidence/<alias>/OPEN-QUESTIONS-DRAFT.md`. Do not edit by hand.
|
|
143
|
+
|
|
144
|
+
| # | Question | Source | Earliest asked | Asked by | Status |
|
|
145
|
+
|---|---|---|---|---|---|
|
|
146
|
+
| 1 | ... | ... | 2026-05-20 | ushak, stand | open |
|
|
147
|
+
| 2 | ... | ... | 2026-05-22 | stand | open |
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- Dedup key: lowercase + whitespace-collapsed question text.
|
|
151
|
+
- Earliest-asked = MIN(per-alias asked-on date).
|
|
152
|
+
- Asked-by column = sorted union of every alias that asked it.
|
|
153
|
+
|
|
62
154
|
## Triggers
|
|
63
155
|
|
|
64
156
|
- "consolidate `<X>` last `<N>` days"
|
|
@@ -71,6 +163,7 @@ When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mi
|
|
|
71
163
|
|
|
72
164
|
## Changelog
|
|
73
165
|
|
|
166
|
+
- **v3.1.0 (kushi v5.4.4, 2026-05-27)**: Step 5 added — consolidate per-user authored files (`bootstrap-status.md`, `FOLLOW-UPS.md`, `OPEN-QUESTIONS-DRAFT.md`) into `_Consolidated/<file>`. Deterministic merge, no LLM. Always runs (even single-contributor). Cross-references per-user truth at `Evidence/<alias>/<file>`.
|
|
74
167
|
- **v3.0.0 (kushi v4.9.0, 2026-05-26)**: 3-step reader fallback chain (`_index/entities.yml` → `weekly/*.md` → legacy `snapshot/` + `stream/`). New citation form `weekly/<YYYY-MM-DD>_<source>-csc.md#<anchor>`. Legacy citations suffixed `(legacy pre-v4.9.0 layout)`. Output marked with `Source-layout:` footer.
|
|
75
168
|
|
|
76
169
|
## Validation loop
|
|
@@ -27,12 +27,51 @@ pwsh plugin/skills/doctor/doctor.ps1 -Json
|
|
|
27
27
|
param(
|
|
28
28
|
[string]$Repo = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..")).Path,
|
|
29
29
|
[switch]$Json,
|
|
30
|
-
[switch]$Strict
|
|
30
|
+
[switch]$Strict,
|
|
31
|
+
[ValidateSet('auto','source','install')] [string]$LayoutMode = 'auto'
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
$ErrorActionPreference = 'Continue'
|
|
34
35
|
$sections = New-Object System.Collections.Generic.List[object]
|
|
35
36
|
|
|
37
|
+
# === v5.4.5: layout-portable doctor ===
|
|
38
|
+
function Resolve-KushiLayout([string]$RootPath) {
|
|
39
|
+
if (Test-Path (Join-Path $RootPath 'plugin')) {
|
|
40
|
+
return @{ Mode='source'; Plugin=(Join-Path $RootPath 'plugin'); Repo=$RootPath; HasPluginJson=$true }
|
|
41
|
+
}
|
|
42
|
+
if (Test-Path (Join-Path $RootPath 'skills')) {
|
|
43
|
+
$pj = Join-Path $RootPath 'kushi-install.json'
|
|
44
|
+
return @{ Mode='install'; Plugin=$RootPath; Repo=$RootPath; HasPluginJson=(Test-Path $pj) }
|
|
45
|
+
}
|
|
46
|
+
throw "Not a kushi layout: $RootPath (need either plugin/ or skills/)."
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function Get-KushiInstallHost([string]$InstallRoot) {
|
|
50
|
+
$norm = ($InstallRoot -replace '\\','/').ToLower()
|
|
51
|
+
if ($norm -match '/\.copilot/') { return 'clawpilot' }
|
|
52
|
+
if ($norm -match '/\.vscode/') { return 'vscode' }
|
|
53
|
+
return 'unknown'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
$Layout = Resolve-KushiLayout $Repo
|
|
57
|
+
if ($LayoutMode -ne 'auto' -and $Layout.Mode -ne $LayoutMode) {
|
|
58
|
+
if ($LayoutMode -eq 'source') {
|
|
59
|
+
if (-not (Test-Path (Join-Path $Repo 'plugin'))) { Write-Error "LayoutMode=source requested but no plugin/ under $Repo."; exit 2 }
|
|
60
|
+
$Layout = @{ Mode='source'; Plugin=(Join-Path $Repo 'plugin'); Repo=$Repo; HasPluginJson=$true }
|
|
61
|
+
} else {
|
|
62
|
+
if (-not (Test-Path (Join-Path $Repo 'skills'))) { Write-Error "LayoutMode=install requested but no skills/ under $Repo."; exit 2 }
|
|
63
|
+
$Layout = @{ Mode='install'; Plugin=$Repo; Repo=$Repo; HasPluginJson=(Test-Path (Join-Path $Repo 'kushi-install.json')) }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (-not $Json) {
|
|
68
|
+
if ($Layout.Mode -eq 'install') {
|
|
69
|
+
Write-Host ("[layout=install (host={0})]" -f (Get-KushiInstallHost $Layout.Repo))
|
|
70
|
+
} else {
|
|
71
|
+
Write-Host "[layout=source]"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
36
75
|
function Add-Section {
|
|
37
76
|
param(
|
|
38
77
|
[string]$Name,
|
|
@@ -90,9 +129,15 @@ if ($envProblems.Count -eq 0) {
|
|
|
90
129
|
|
|
91
130
|
# ── Section 2: self-check -Deep ─────────────────────────────────────────────
|
|
92
131
|
Write-Banner "2. self-check -Deep" "Cyan"
|
|
93
|
-
$
|
|
132
|
+
if ($Layout.Mode -eq 'source') {
|
|
133
|
+
$selfCheckPath = Join-Path $Layout.Plugin 'skills\self-check\run.ps1'
|
|
134
|
+
} else {
|
|
135
|
+
$selfCheckPath = Join-Path $Layout.Plugin 'skills\self-check\run.ps1'
|
|
136
|
+
}
|
|
94
137
|
if (Test-Path $selfCheckPath) {
|
|
95
|
-
$
|
|
138
|
+
$scArgs = @('-NoProfile','-File',$selfCheckPath,'-Deep','-Json','-Root',$Layout.Repo)
|
|
139
|
+
if ($Layout.Mode -eq 'install') { $scArgs += @('-LayoutMode','install') }
|
|
140
|
+
$scJson = & pwsh @scArgs 2>$null
|
|
96
141
|
$scExit = $LASTEXITCODE
|
|
97
142
|
$scFindings = @()
|
|
98
143
|
try { $scFindings = $scJson | ConvertFrom-Json } catch {}
|
|
@@ -106,15 +151,24 @@ if (Test-Path $selfCheckPath) {
|
|
|
106
151
|
Write-Host " ⚠️ $scCount finding(s)" -ForegroundColor Yellow
|
|
107
152
|
foreach ($f in $scFindings) { Write-Host " [$($f.code)] $($f.message)" -ForegroundColor DarkYellow }
|
|
108
153
|
}
|
|
109
|
-
Add-Section 'self-check' 'yellow' "$scCount finding(s)" 'pwsh
|
|
154
|
+
Add-Section 'self-check' 'yellow' "$scCount finding(s)" 'pwsh skills/self-check/run.ps1 -Deep # then fix each [code]'
|
|
110
155
|
}
|
|
111
156
|
} else {
|
|
112
157
|
if (-not $Json) { Write-Host " ❌ run.ps1 missing" -ForegroundColor Red }
|
|
113
|
-
|
|
158
|
+
if ($Layout.Mode -eq 'install') {
|
|
159
|
+
$hostFlag = switch (Get-KushiInstallHost $Layout.Repo) { 'clawpilot' { '--clawpilot' } 'vscode' { '--vscode' } default { '--all-hosts' } }
|
|
160
|
+
Add-Section 'self-check' 'red' 'run.ps1 not found in install' "Re-install: ``npx kushi-agents@latest $hostFlag --force``"
|
|
161
|
+
} else {
|
|
162
|
+
Add-Section 'self-check' 'red' 'run.ps1 not found' "Restore plugin/skills/self-check/run.ps1 from git."
|
|
163
|
+
}
|
|
114
164
|
}
|
|
115
165
|
|
|
116
166
|
# ── Section 3: canary evals ─────────────────────────────────────────────────
|
|
117
167
|
Write-Banner "3. canary evals" "Cyan"
|
|
168
|
+
if ($Layout.Mode -eq 'install') {
|
|
169
|
+
if (-not $Json) { Write-Host " ℹ️ skipped in install mode (no eval baseline shipped)" -ForegroundColor Gray }
|
|
170
|
+
Add-Section 'canary-evals' 'green' 'skipped (install mode)' ''
|
|
171
|
+
} else {
|
|
118
172
|
Push-Location $Repo
|
|
119
173
|
$canaryOut = & npm run --silent eval:canary 2>&1
|
|
120
174
|
$canaryExit = $LASTEXITCODE
|
|
@@ -141,31 +195,66 @@ if ($canaryExit -eq 0) {
|
|
|
141
195
|
Add-Section 'canary-evals' 'red' "FAIL exit=$canaryExit" 'npm run eval:canary # investigate failing case'
|
|
142
196
|
}
|
|
143
197
|
}
|
|
198
|
+
}
|
|
144
199
|
|
|
145
200
|
# ── Section 4: skill-checker -All ───────────────────────────────────────────
|
|
146
201
|
Write-Banner "4. skill-checker -All" "Cyan"
|
|
147
|
-
$checkerPath = Join-Path $
|
|
202
|
+
$checkerPath = Join-Path $Layout.Plugin 'skills\skill-checker\check-skill.ps1'
|
|
148
203
|
if (Test-Path $checkerPath) {
|
|
149
|
-
$ckOut = & pwsh -NoProfile -File $checkerPath -All -Root $Repo 2>&1
|
|
204
|
+
$ckOut = & pwsh -NoProfile -File $checkerPath -All -Root $Layout.Repo 2>&1
|
|
150
205
|
$ckExit = $LASTEXITCODE
|
|
151
206
|
if ($ckExit -eq 0) {
|
|
152
207
|
if (-not $Json) { Write-Host " ✅ all skills compliant" -ForegroundColor Green }
|
|
153
208
|
Add-Section 'skill-checker' 'green' 'all skills pass blueprint' ''
|
|
154
209
|
} else {
|
|
155
210
|
if (-not $Json) { Write-Host " ⚠️ blueprint violations (exit=$ckExit)" -ForegroundColor Yellow }
|
|
156
|
-
Add-Section 'skill-checker' 'yellow' "exit=$ckExit" 'pwsh
|
|
211
|
+
Add-Section 'skill-checker' 'yellow' "exit=$ckExit" 'pwsh skills/skill-checker/check-skill.ps1 -All # review output'
|
|
157
212
|
}
|
|
158
213
|
} else {
|
|
159
|
-
|
|
214
|
+
if ($Layout.Mode -eq 'install') {
|
|
215
|
+
if (-not $Json) { Write-Host " ⚠️ skill-checker not installed in this profile (full only)" -ForegroundColor Yellow }
|
|
216
|
+
Add-Section 'skill-checker' 'yellow' 'not installed (full profile only)' "Re-install with full profile: ``npx kushi-agents@latest --all-hosts --profile full --force``"
|
|
217
|
+
} else {
|
|
218
|
+
Add-Section 'skill-checker' 'red' 'check-skill.ps1 not found' "Restore plugin/skills/skill-checker/check-skill.ps1"
|
|
219
|
+
}
|
|
160
220
|
}
|
|
161
221
|
|
|
162
222
|
# ── Section 5: Live-install drift ───────────────────────────────────────────
|
|
163
223
|
Write-Banner "5. live-install drift" "Cyan"
|
|
224
|
+
if ($Layout.Mode -eq 'install') {
|
|
225
|
+
# Install mode: compare installed version (from kushi-install.json) to npm latest.
|
|
226
|
+
$installPjPath = Join-Path $Layout.Repo 'kushi-install.json'
|
|
227
|
+
$installedVer = $null
|
|
228
|
+
if (Test-Path $installPjPath) {
|
|
229
|
+
try { $installedVer = (Get-Content -Raw $installPjPath | ConvertFrom-Json).version } catch {}
|
|
230
|
+
}
|
|
231
|
+
$npmOk = $false
|
|
232
|
+
try { $null = & npm --version 2>$null; if ($LASTEXITCODE -eq 0) { $npmOk = $true } } catch {}
|
|
233
|
+
if (-not $npmOk) {
|
|
234
|
+
if (-not $Json) { Write-Host " ℹ️ npm not on PATH (skipped)" -ForegroundColor Gray }
|
|
235
|
+
Add-Section 'live-install' 'green' 'npm not on PATH (skipped)' ''
|
|
236
|
+
} elseif (-not $installedVer) {
|
|
237
|
+
if (-not $Json) { Write-Host " ⚠️ no kushi-install.json version field" -ForegroundColor Yellow }
|
|
238
|
+
$hostFlag = switch (Get-KushiInstallHost $Layout.Repo) { 'clawpilot' { '--clawpilot' } 'vscode' { '--vscode' } default { '--all-hosts' } }
|
|
239
|
+
Add-Section 'live-install' 'yellow' 'install manifest missing version' "Re-install: ``npx kushi-agents@latest $hostFlag --force``"
|
|
240
|
+
} else {
|
|
241
|
+
$latest = $null
|
|
242
|
+
try { $latest = (& npm view kushi-agents version 2>$null).Trim() } catch {}
|
|
243
|
+
if ($latest -and $latest -ne $installedVer) {
|
|
244
|
+
if (-not $Json) { Write-Host " ⚠️ installed=v$installedVer latest=v$latest" -ForegroundColor Yellow }
|
|
245
|
+
$hostFlag = switch (Get-KushiInstallHost $Layout.Repo) { 'clawpilot' { '--clawpilot' } 'vscode' { '--vscode' } default { '--all-hosts' } }
|
|
246
|
+
Add-Section 'live-install' 'yellow' "installed=v$installedVer latest=v$latest" "Re-install: ``npx kushi-agents@latest $hostFlag --force``"
|
|
247
|
+
} else {
|
|
248
|
+
if (-not $Json) { Write-Host " ✅ install matches npm latest" -ForegroundColor Green }
|
|
249
|
+
Add-Section 'live-install' 'green' "installed=v$installedVer (matches npm latest)" ''
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
164
253
|
$liveSkill = Join-Path $userHome '.copilot\m-skills\kushi\SKILL.md'
|
|
165
|
-
$agentFile = Join-Path $
|
|
254
|
+
$agentFile = Join-Path $Layout.Plugin 'agents\kushi.agent.md'
|
|
166
255
|
$metaPath = Join-Path $userHome '.copilot\m-skills\skills-metadata.json'
|
|
167
256
|
$repoVersion = $null
|
|
168
|
-
try { $repoVersion = (Get-Content -Raw (Join-Path $Repo 'package.json') | ConvertFrom-Json).version } catch {}
|
|
257
|
+
try { $repoVersion = (Get-Content -Raw (Join-Path $Layout.Repo 'package.json') | ConvertFrom-Json).version } catch {}
|
|
169
258
|
$liveVersion = $null
|
|
170
259
|
if (Test-Path $metaPath) {
|
|
171
260
|
try {
|
|
@@ -204,6 +293,7 @@ if (-not (Test-Path $liveSkill)) {
|
|
|
204
293
|
}
|
|
205
294
|
}
|
|
206
295
|
}
|
|
296
|
+
}
|
|
207
297
|
|
|
208
298
|
# ── Section 6: Global wiki shape ────────────────────────────────────────────
|
|
209
299
|
Write-Banner "6. global wiki shape" "Cyan"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "migrate-per-user-files"
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
description: "USE WHEN a project was bootstrapped under kushi ≤ v5.4.3 and the three root files (`bootstrap-status.md`, `FOLLOW-UPS.md`, `OPEN-QUESTIONS-DRAFT.md`) need to be relocated to per-user `Evidence/<alias>/` paths AND the user is ready to commit the move. DO NOT USE for routine refreshes (refresh-project already writes to new paths in v5.4.4+) or for shared root files (integrations.yml, kushi.yaml, .settings.yml) which stay at the project root."
|
|
5
|
+
profile: "standard"
|
|
6
|
+
verb: "migrate-files"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# migrate-per-user-files
|
|
10
|
+
|
|
11
|
+
USE WHEN: A project repo was bootstrapped/refreshed under kushi ≤ v5.4.3 and the three previously-shared root files (`bootstrap-status.md`, `FOLLOW-UPS.md`, `OPEN-QUESTIONS-DRAFT.md`) exist at `<project>/`. v5.4.4 promotes those three files to per-user truth at `<project>/Evidence/<alias>/<file>`, with auto-consolidated rollups at `<project>/_Consolidated/<file>` emitted by `consolidate-evidence`. This skill performs the one-time relocation safely.
|
|
12
|
+
|
|
13
|
+
DO NOT USE FOR: routine refreshes (`refresh-project` already writes to the new paths in v5.4.4+) or for the shared files that stay at the root (`integrations.yml`, `kushi.yaml`, `.settings.yml`).
|
|
14
|
+
|
|
15
|
+
## Steps
|
|
16
|
+
|
|
17
|
+
1. **Resolve alias** — `Get-KushiConfig -Name 'project-evidence'` returns the current user's alias. Refuse to run if no alias is configured.
|
|
18
|
+
2. **Discover sources** — For each of the three basenames, check whether `<project>/<file>` exists at the root.
|
|
19
|
+
3. **Check destination** — For each found source, check whether `<project>/Evidence/<alias>/<file>` already exists.
|
|
20
|
+
- **No destination** → planned action: `move` (root → per-user).
|
|
21
|
+
- **Destination exists with byte-identical content** → planned action: `delete-root-duplicate` (per-user is authoritative, root is stale copy).
|
|
22
|
+
- **Destination exists with different content** → planned action: `needs-merge`. **Defensive: never overwrite.** Emit a `[needs-merge]` row, exit 1 in `--apply` mode (in dry-run, still report and exit 0 so the user sees the full plan).
|
|
23
|
+
4. **Print the plan** — One row per file: `<basename> | <action> | <reason>`. With `--apply`, also print the destination path that was written.
|
|
24
|
+
5. **Execute or no-op**:
|
|
25
|
+
- Without `--apply`: dry-run only. Print plan, exit 0.
|
|
26
|
+
- With `--apply`: for each `move` or `delete-root-duplicate`, perform the filesystem operation. Re-running with `--apply` after a successful run is a no-op (nothing to migrate).
|
|
27
|
+
6. **Log to run-log** — Append a `migrations:` entry to `Evidence/run-log.yml` with timestamp, alias, files moved, files needing merge.
|
|
28
|
+
|
|
29
|
+
## Arguments
|
|
30
|
+
|
|
31
|
+
- `-ProjectRoot <path>` (required) — Absolute path to the project folder.
|
|
32
|
+
- `-Apply` (switch) — Perform the migration. Without this flag, the script is dry-run only.
|
|
33
|
+
- `-StrictExit` (switch) — Exit 1 on any `needs-merge` row, even in dry-run mode.
|
|
34
|
+
|
|
35
|
+
## Validation loop
|
|
36
|
+
|
|
37
|
+
After `--apply`, the script self-verifies by re-listing the three root files. If any of them still exists (other than because of a `needs-merge` row), exit 2 with a `[verify]` error.
|
|
38
|
+
|
|
39
|
+
## Idempotency contract
|
|
40
|
+
|
|
41
|
+
Running with `--apply` on an already-migrated repo MUST be a no-op (exit 0, plan-table prints `nothing-to-do` for all three rows).
|
|
42
|
+
|
|
43
|
+
## See also
|
|
44
|
+
|
|
45
|
+
- `plugin/instructions/multi-user-shared-files.instructions.md` — the v5.4.4 doctrine.
|
|
46
|
+
- `plugin/skills/consolidate-evidence/SKILL.md` Step 5 — the auto-rollup that consumes per-user files.
|
|
47
|
+
- `references/migration-strategy.md` — why defensive, why content-hash compare, why dry-run by default.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "migrate-per-user-files",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Migration script + SKILL.md ship together and document the three target basenames.",
|
|
5
|
+
"cases": [
|
|
6
|
+
{
|
|
7
|
+
"id": "skill-md-exists",
|
|
8
|
+
"name": "SKILL.md and migrate.ps1 are present",
|
|
9
|
+
"input": "verify migrate-per-user-files SKILL.md and migrate.ps1 exist",
|
|
10
|
+
"canary": true,
|
|
11
|
+
"grader_type": "script",
|
|
12
|
+
"expected_assertions": [
|
|
13
|
+
{ "type": "file-exists", "path": "plugin/skills/migrate-per-user-files/SKILL.md" },
|
|
14
|
+
{ "type": "file-exists", "path": "plugin/skills/migrate-per-user-files/migrate.ps1" }
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "skill-documents-three-basenames",
|
|
19
|
+
"name": "SKILL.md documents all three target basenames",
|
|
20
|
+
"input": "verify SKILL.md mentions bootstrap-status.md, FOLLOW-UPS.md, and OPEN-QUESTIONS-DRAFT.md",
|
|
21
|
+
"canary": false,
|
|
22
|
+
"grader_type": "script",
|
|
23
|
+
"expected_assertions": [
|
|
24
|
+
{ "type": "file-contains", "path": "plugin/skills/migrate-per-user-files/SKILL.md", "needle": "bootstrap-status.md" },
|
|
25
|
+
{ "type": "file-contains", "path": "plugin/skills/migrate-per-user-files/SKILL.md", "needle": "FOLLOW-UPS.md" },
|
|
26
|
+
{ "type": "file-contains", "path": "plugin/skills/migrate-per-user-files/SKILL.md", "needle": "OPEN-QUESTIONS-DRAFT.md" }
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "strategy-reference-ships",
|
|
31
|
+
"name": "references/migration-strategy.md documents the defensive contract",
|
|
32
|
+
"input": "verify migration-strategy.md exists and mentions content-hash",
|
|
33
|
+
"canary": false,
|
|
34
|
+
"grader_type": "script",
|
|
35
|
+
"expected_assertions": [
|
|
36
|
+
{ "type": "file-exists", "path": "plugin/skills/migrate-per-user-files/references/migration-strategy.md" },
|
|
37
|
+
{ "type": "file-contains", "path": "plugin/skills/migrate-per-user-files/references/migration-strategy.md", "needle": "content-hash" }
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#requires -Version 7.0
|
|
2
|
+
<#
|
|
3
|
+
.SYNOPSIS
|
|
4
|
+
Migrate root-level bootstrap-status.md / FOLLOW-UPS.md / OPEN-QUESTIONS-DRAFT.md
|
|
5
|
+
to per-user Evidence/<alias>/ paths (kushi v5.4.4+ doctrine).
|
|
6
|
+
|
|
7
|
+
.PARAMETER ProjectRoot
|
|
8
|
+
Absolute path to the project folder.
|
|
9
|
+
|
|
10
|
+
.PARAMETER Apply
|
|
11
|
+
Perform the migration. Without this switch, the script is dry-run only.
|
|
12
|
+
|
|
13
|
+
.PARAMETER StrictExit
|
|
14
|
+
Exit 1 on any needs-merge row, even in dry-run mode.
|
|
15
|
+
#>
|
|
16
|
+
[CmdletBinding()]
|
|
17
|
+
param(
|
|
18
|
+
[Parameter(Mandatory)] [string] $ProjectRoot,
|
|
19
|
+
[switch] $Apply,
|
|
20
|
+
[switch] $StrictExit
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
$ErrorActionPreference = 'Stop'
|
|
24
|
+
$basenames = @('bootstrap-status.md','FOLLOW-UPS.md','OPEN-QUESTIONS-DRAFT.md')
|
|
25
|
+
|
|
26
|
+
if (-not (Test-Path -LiteralPath $ProjectRoot -PathType Container)) {
|
|
27
|
+
Write-Error "[migrate-per-user-files] ProjectRoot not found: $ProjectRoot"
|
|
28
|
+
exit 2
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# --- Resolve alias --------------------------------------------------------
|
|
32
|
+
# Read directly from the project's user config — keeps this script standalone
|
|
33
|
+
# and avoids dot-sourcing helpers that have mandatory parameters.
|
|
34
|
+
$alias = $null
|
|
35
|
+
$cfgPath = Join-Path $ProjectRoot '.kushi/config/user/project-evidence.yml'
|
|
36
|
+
if (Test-Path -LiteralPath $cfgPath) {
|
|
37
|
+
$aliasLine = (Get-Content -LiteralPath $cfgPath) | Where-Object { $_ -match '^\s*alias\s*:\s*(\S+)' } | Select-Object -First 1
|
|
38
|
+
if ($aliasLine -and $aliasLine -match '^\s*alias\s*:\s*(\S+)') { $alias = $Matches[1].Trim('"').Trim("'") }
|
|
39
|
+
}
|
|
40
|
+
if (-not $alias) {
|
|
41
|
+
Write-Error "[migrate-per-user-files] No alias configured at $cfgPath. Run setup or set the project-evidence alias before migrating."
|
|
42
|
+
exit 2
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
$perUserDir = Join-Path $ProjectRoot "Evidence\$alias"
|
|
46
|
+
$plan = @()
|
|
47
|
+
$needsMergeCount = 0
|
|
48
|
+
$actedCount = 0
|
|
49
|
+
|
|
50
|
+
foreach ($name in $basenames) {
|
|
51
|
+
$src = Join-Path $ProjectRoot $name
|
|
52
|
+
$dst = Join-Path $perUserDir $name
|
|
53
|
+
$hasSrc = Test-Path -LiteralPath $src -PathType Leaf
|
|
54
|
+
$hasDst = Test-Path -LiteralPath $dst -PathType Leaf
|
|
55
|
+
|
|
56
|
+
if (-not $hasSrc -and -not $hasDst) {
|
|
57
|
+
$plan += [pscustomobject]@{ file=$name; action='nothing-to-do'; reason='neither root nor per-user copy present' }
|
|
58
|
+
continue
|
|
59
|
+
}
|
|
60
|
+
if (-not $hasSrc -and $hasDst) {
|
|
61
|
+
$plan += [pscustomobject]@{ file=$name; action='nothing-to-do'; reason='already migrated' }
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
if ($hasSrc -and -not $hasDst) {
|
|
65
|
+
if ($Apply) {
|
|
66
|
+
if (-not (Test-Path -LiteralPath $perUserDir -PathType Container)) {
|
|
67
|
+
New-Item -ItemType Directory -Path $perUserDir -Force | Out-Null
|
|
68
|
+
}
|
|
69
|
+
Move-Item -LiteralPath $src -Destination $dst
|
|
70
|
+
$actedCount++
|
|
71
|
+
$plan += [pscustomobject]@{ file=$name; action='moved'; reason="-> Evidence/$alias/$name" }
|
|
72
|
+
} else {
|
|
73
|
+
$plan += [pscustomobject]@{ file=$name; action='move'; reason="would move root -> Evidence/$alias/$name" }
|
|
74
|
+
}
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
77
|
+
# Both exist — compare content hashes.
|
|
78
|
+
$srcHash = (Get-FileHash -LiteralPath $src -Algorithm SHA256).Hash
|
|
79
|
+
$dstHash = (Get-FileHash -LiteralPath $dst -Algorithm SHA256).Hash
|
|
80
|
+
if ($srcHash -eq $dstHash) {
|
|
81
|
+
if ($Apply) {
|
|
82
|
+
Remove-Item -LiteralPath $src -Force
|
|
83
|
+
$actedCount++
|
|
84
|
+
$plan += [pscustomobject]@{ file=$name; action='deleted-root-duplicate'; reason='per-user copy is byte-identical' }
|
|
85
|
+
} else {
|
|
86
|
+
$plan += [pscustomobject]@{ file=$name; action='delete-root-duplicate'; reason='would delete byte-identical root copy' }
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
$needsMergeCount++
|
|
90
|
+
$plan += [pscustomobject]@{ file=$name; action='needs-merge'; reason='root and per-user copies differ — manual merge required, will not overwrite' }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
Write-Host ""
|
|
95
|
+
Write-Host "[migrate-per-user-files] alias = $alias" -ForegroundColor Cyan
|
|
96
|
+
Write-Host "[migrate-per-user-files] project = $ProjectRoot" -ForegroundColor Cyan
|
|
97
|
+
Write-Host "[migrate-per-user-files] mode = $(if ($Apply) {'APPLY'} else {'DRY-RUN'})" -ForegroundColor Cyan
|
|
98
|
+
Write-Host ""
|
|
99
|
+
$plan | Format-Table -AutoSize | Out-String | Write-Host
|
|
100
|
+
|
|
101
|
+
# --- Run-log append (apply mode only) ------------------------------------
|
|
102
|
+
if ($Apply -and $actedCount -gt 0) {
|
|
103
|
+
$evDir = Join-Path $ProjectRoot 'Evidence'
|
|
104
|
+
if (-not (Test-Path -LiteralPath $evDir -PathType Container)) {
|
|
105
|
+
New-Item -ItemType Directory -Path $evDir -Force | Out-Null
|
|
106
|
+
}
|
|
107
|
+
$log = Join-Path $evDir 'run-log.yml'
|
|
108
|
+
$ts = (Get-Date).ToString('s') + 'Z'
|
|
109
|
+
$moved = ($plan | Where-Object { $_.action -in @('moved','deleted-root-duplicate') } | ForEach-Object { $_.file }) -join ', '
|
|
110
|
+
$merge = ($plan | Where-Object { $_.action -eq 'needs-merge' } | ForEach-Object { $_.file }) -join ', '
|
|
111
|
+
$entry = @(
|
|
112
|
+
"migrations:",
|
|
113
|
+
" - timestamp: $ts",
|
|
114
|
+
" alias: $alias",
|
|
115
|
+
" skill: migrate-per-user-files",
|
|
116
|
+
" files_migrated: [$moved]",
|
|
117
|
+
" files_needs_merge: [$merge]"
|
|
118
|
+
) -join "`r`n"
|
|
119
|
+
Add-Content -LiteralPath $log -Value $entry
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# --- Verify (apply mode only) --------------------------------------------
|
|
123
|
+
if ($Apply) {
|
|
124
|
+
foreach ($name in $basenames) {
|
|
125
|
+
$src = Join-Path $ProjectRoot $name
|
|
126
|
+
$stillThere = Test-Path -LiteralPath $src -PathType Leaf
|
|
127
|
+
$row = $plan | Where-Object { $_.file -eq $name } | Select-Object -First 1
|
|
128
|
+
if ($stillThere -and $row.action -notin @('needs-merge','nothing-to-do')) {
|
|
129
|
+
Write-Error "[verify] $name still present at root after migration"
|
|
130
|
+
exit 2
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if ($needsMergeCount -gt 0 -and ($Apply -or $StrictExit)) { exit 1 }
|
|
136
|
+
exit 0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Migration strategy — per-user file relocation
|
|
2
|
+
|
|
3
|
+
## Why defensive (refuse to overwrite)
|
|
4
|
+
|
|
5
|
+
The three migrated files are authored artifacts that may have hand edits, accumulated follow-ups, or carefully-curated open-question wording. A naive `Move-Item -Force` could silently destroy hours of work if a per-user copy already exists. We instead detect the collision and refuse — the user must decide which copy wins (or hand-merge them).
|
|
6
|
+
|
|
7
|
+
## Why content-hash compare
|
|
8
|
+
|
|
9
|
+
If both copies exist with byte-identical content, the per-user copy is authoritative (v5.4.4+) and the root copy is a stale duplicate left behind by some workflow. Deleting it is safe and quiet — no manual merge needed.
|
|
10
|
+
|
|
11
|
+
If the content differs by even one byte, we cannot know which copy is newer, so we emit `[needs-merge]` and stop.
|
|
12
|
+
|
|
13
|
+
## Why dry-run by default
|
|
14
|
+
|
|
15
|
+
Mass filesystem operations should always print a plan first. The `--apply` flag is the explicit "yes, do it" gate. This matches the pattern used by `apply-ado-update` (preview profile) and the v5.4.3 lessons learned from the profile-allowlist catch-up.
|
|
16
|
+
|
|
17
|
+
## Why one-time (not part of `refresh-project`)
|
|
18
|
+
|
|
19
|
+
v5.4.4 `refresh-project` already writes to the new per-user paths. The migration is a one-time data move for repos initialized under ≤ v5.4.3. Folding it into refresh would mean checking-and-migrating on every refresh — wasteful and potentially destructive if the user has not yet decided how to handle a `needs-merge` situation.
|
|
20
|
+
|
|
21
|
+
## Why log to run-log.yml
|
|
22
|
+
|
|
23
|
+
Every project-touching kushi action logs to `Evidence/run-log.yml`. The migration is a project-touching action and follows the same convention so a future `doctor` or `project-status` run can see when the migration happened and which files were affected.
|
|
@@ -311,7 +311,7 @@ After successful pass:
|
|
|
311
311
|
## References (v4.4.7)
|
|
312
312
|
|
|
313
313
|
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
314
|
-
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
314
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write Evidence/<alias>/FOLLOW-UPS.md per v5.4.4+ per-user files doctrine; consolidated at _Consolidated/FOLLOW-UPS.md).
|
|
315
315
|
|
|
316
316
|
|
|
317
317
|
## Issue Recovery
|
|
@@ -202,7 +202,7 @@ After successful pass:
|
|
|
202
202
|
## References (v4.4.7)
|
|
203
203
|
|
|
204
204
|
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
205
|
-
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
205
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write Evidence/<alias>/FOLLOW-UPS.md per v5.4.4+ per-user files doctrine; consolidated at _Consolidated/FOLLOW-UPS.md).
|
|
206
206
|
|
|
207
207
|
|
|
208
208
|
## Issue Recovery
|
|
@@ -193,7 +193,7 @@ An entity that cannot meet the threshold is flagged `low_signal: true` in `_inde
|
|
|
193
193
|
## References (v4.4.7)
|
|
194
194
|
|
|
195
195
|
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
196
|
-
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
196
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write Evidence/<alias>/FOLLOW-UPS.md per v5.4.4+ per-user files doctrine; consolidated at _Consolidated/FOLLOW-UPS.md).
|
|
197
197
|
|
|
198
198
|
|
|
199
199
|
## Issue Recovery
|
|
@@ -124,7 +124,7 @@ Per `loop-bootstrap-discovery.instructions.md`:
|
|
|
124
124
|
| Pre-flight | Failure action |
|
|
125
125
|
|---|---|
|
|
126
126
|
| **A. Workspaces registered** for the resolved project | Refuse to run. Instruct user to run `@Kushi setup --reconfigure`. |
|
|
127
|
-
| **B. Pages registered** OR `loop_pages_status: to-be-enumerated` | Run page enumeration via WorkIQ first; on enumerate-fail, write FOLLOW-UPS.md per the gate. |
|
|
127
|
+
| **B. Pages registered** OR `loop_pages_status: to-be-enumerated` | Run page enumeration via WorkIQ first; on enumerate-fail, write Evidence/<alias>/FOLLOW-UPS.md per the gate (v5.4.4+; rollup at _Consolidated/FOLLOW-UPS.md). |
|
|
128
128
|
| **C. Playwright profile exists** at `~/.kushi/playwright-profile/m365/` or `.../onenote/` | Refuse; instruct: `node plugin/skills/pull-onenote/runner.mjs --bootstrap`. |
|
|
129
129
|
| **D. URLs are canonical** (matches Loop URL grammar; not synthesized) | Refuse + log to learnings/loop.md per `issue-recovery.instructions.md`. |
|
|
130
130
|
|
|
@@ -171,7 +171,7 @@ After the pass:
|
|
|
171
171
|
## References (v4.4.7)
|
|
172
172
|
|
|
173
173
|
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
174
|
-
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
174
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write Evidence/<alias>/FOLLOW-UPS.md per v5.4.4+ per-user files doctrine; consolidated at _Consolidated/FOLLOW-UPS.md).
|
|
175
175
|
|
|
176
176
|
|
|
177
177
|
## Issue Recovery
|
|
@@ -98,7 +98,7 @@ For each project, the bootstrap step:
|
|
|
98
98
|
1. **Locates `<project>/external-links.txt`.** If absent, write a starter template (same format as ABN AMRO has today) and mark `boundaries.misc.externalLinksPath` in `integrations.yml`.
|
|
99
99
|
2. **Parses the file.** Skip comments, skip blank lines, skip placeholder URLs (`<PASTE_*_URL>`, `<TODO*>`).
|
|
100
100
|
3. **Initializes `misc_links[]`** in `m365-mutable.json#knownSections.<projectKey>` with one entry per non-placeholder link, all `last_status: not-yet-attempted`.
|
|
101
|
-
4. **Records** `boundaries.misc.linkCount` and `placeholderCount` to `bootstrap-status.md
|
|
101
|
+
4. **Records** `boundaries.misc.linkCount` and `placeholderCount` to `Evidence/<alias>/bootstrap-status.md` (per-user, v5.4.4+; consolidated rollup at `_Consolidated/bootstrap-status.md`).
|
|
102
102
|
|
|
103
103
|
## Step A — enumerate (every refresh)
|
|
104
104
|
|
|
@@ -117,7 +117,7 @@ The runner branches per `type`:
|
|
|
117
117
|
|
|
118
118
|
Skip fetch. Write registry entry with `captured_via: delegated`, `delegated_to: pull-loop`. The actual workspace/page capture happens in `pull-loop` (see `plugin/skills/pull-loop/SKILL.md`), which uses the canonical Loop boundary in `<project>/integrations.yml#boundaries.loop.workspace_ids[]` rather than free-text `external-links.txt` URLs.
|
|
119
119
|
|
|
120
|
-
If the Loop URL pasted into `external-links.txt` references a workspace NOT registered in `boundaries.loop.workspace_ids[]`, `pull-misc` records `last_status: unregistered-loop-workspace` and notes the URL in `<project>/OPEN-QUESTIONS-DRAFT.md` so the user can decide whether to register it via `@Kushi setup --reconfigure`.
|
|
120
|
+
If the Loop URL pasted into `external-links.txt` references a workspace NOT registered in `boundaries.loop.workspace_ids[]`, `pull-misc` records `last_status: unregistered-loop-workspace` and notes the URL in `<project>/Evidence/<alias>/OPEN-QUESTIONS-DRAFT.md` (per-user, v5.4.4+; consolidated rollup at `_Consolidated/OPEN-QUESTIONS-DRAFT.md`) so the user can decide whether to register it via `@Kushi setup --reconfigure`.
|
|
121
121
|
|
|
122
122
|
### B.2 `web` / `confluence` / `learn` / `docs` / `github` / unknown — HTTP
|
|
123
123
|
|
|
@@ -263,7 +263,7 @@ Example: `[source: misc/loop/ABN-Core-Team-Sync-2026-03-27 · 2026-05-14]`
|
|
|
263
263
|
## References (v4.4.7)
|
|
264
264
|
|
|
265
265
|
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
266
|
-
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
266
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write Evidence/<alias>/FOLLOW-UPS.md per v5.4.4+ per-user files doctrine; consolidated at _Consolidated/FOLLOW-UPS.md).
|
|
267
267
|
|
|
268
268
|
|
|
269
269
|
## Issue Recovery
|
|
@@ -171,7 +171,7 @@ Every refresh writes `Evidence/<alias>/refresh-reports/<YYYY-MM-DD>-<HHMM>-oneno
|
|
|
171
171
|
## References (v4.4.7)
|
|
172
172
|
|
|
173
173
|
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
174
|
-
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
174
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write Evidence/<alias>/FOLLOW-UPS.md per v5.4.4+ per-user files doctrine; consolidated at _Consolidated/FOLLOW-UPS.md).
|
|
175
175
|
|
|
176
176
|
|
|
177
177
|
## Issue Recovery
|
|
@@ -183,7 +183,7 @@ An entity that cannot meet the threshold is flagged `low_signal: true` in `_inde
|
|
|
183
183
|
## References (v4.4.7)
|
|
184
184
|
|
|
185
185
|
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
186
|
-
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
186
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write Evidence/<alias>/FOLLOW-UPS.md per v5.4.4+ per-user files doctrine; consolidated at _Consolidated/FOLLOW-UPS.md).
|
|
187
187
|
|
|
188
188
|
|
|
189
189
|
## Issue Recovery
|