principles-disciple 1.81.0 → 1.83.0

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.
Files changed (60) hide show
  1. package/openclaw.plugin.json +1 -1
  2. package/package.json +4 -4
  3. package/src/commands/strategy.ts +0 -18
  4. package/src/i18n/commands.ts +0 -12
  5. package/src/index.ts +4 -22
  6. package/templates/langs/en/core/BOOTSTRAP.md +4 -18
  7. package/templates/langs/en/skills/bootstrap-tools/SKILL.md +1 -1
  8. package/templates/langs/en/skills/init-strategy/SKILL.md +1 -1
  9. package/templates/langs/en/skills/pd-mentor/SKILL.md +8 -23
  10. package/templates/langs/zh/core/BOOTSTRAP.md +2 -15
  11. package/templates/langs/zh/skills/bootstrap-tools/SKILL.md +1 -1
  12. package/templates/langs/zh/skills/init-strategy/SKILL.md +1 -1
  13. package/templates/langs/zh/skills/pd-mentor/SKILL.md +7 -22
  14. package/tests/commands/strategy.test.ts +3 -18
  15. package/templates/langs/en/skills/ai-sprint-orchestration/EXAMPLES.md +0 -63
  16. package/templates/langs/en/skills/ai-sprint-orchestration/REFERENCE.md +0 -136
  17. package/templates/langs/en/skills/ai-sprint-orchestration/SKILL.md +0 -67
  18. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +0 -143
  19. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +0 -107
  20. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +0 -107
  21. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +0 -95
  22. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +0 -98
  23. package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +0 -58
  24. package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +0 -190
  25. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +0 -310
  26. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +0 -683
  27. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +0 -604
  28. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +0 -32
  29. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +0 -707
  30. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +0 -3455
  31. package/templates/langs/en/skills/evolve-system/SKILL.md +0 -46
  32. package/templates/langs/en/skills/manage-okr/SKILL.md +0 -96
  33. package/templates/langs/en/skills/pd-daily/SKILL.md +0 -199
  34. package/templates/langs/en/skills/pd-grooming/SKILL.md +0 -46
  35. package/templates/langs/zh/skills/ai-sprint-orchestration/EXAMPLES.md +0 -63
  36. package/templates/langs/zh/skills/ai-sprint-orchestration/REFERENCE.md +0 -136
  37. package/templates/langs/zh/skills/ai-sprint-orchestration/SKILL.md +0 -67
  38. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +0 -143
  39. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +0 -107
  40. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +0 -107
  41. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +0 -111
  42. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +0 -95
  43. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +0 -98
  44. package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +0 -58
  45. package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +0 -190
  46. package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +0 -2
  47. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +0 -310
  48. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +0 -683
  49. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +0 -604
  50. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +0 -32
  51. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +0 -707
  52. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +0 -3455
  53. package/templates/langs/zh/skills/ai-sprint-orchestration/test/archive.test.mjs +0 -230
  54. package/templates/langs/zh/skills/ai-sprint-orchestration/test/contract-enforcement.test.mjs +0 -672
  55. package/templates/langs/zh/skills/ai-sprint-orchestration/test/decision.test.mjs +0 -1321
  56. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +0 -1435
  57. package/templates/langs/zh/skills/evolve-system/SKILL.md +0 -46
  58. package/templates/langs/zh/skills/manage-okr/SKILL.md +0 -109
  59. package/templates/langs/zh/skills/pd-daily/SKILL.md +0 -283
  60. package/templates/langs/zh/skills/pd-grooming/SKILL.md +0 -46
@@ -1,58 +0,0 @@
1
- # Workflow v1 Acceptance Checklist
2
-
3
- ## Purpose
4
-
5
- Use this checklist to validate that the packaged workflow is readable, executable, and safe to hand off to another agent.
6
-
7
- ## Acceptance gates
8
-
9
- - [ ] Baseline tests are green
10
- - [ ] `workflow-validation-minimal` completes and writes package-local artifacts
11
- - [ ] `workflow-validation-minimal-verify` completes and validates the previous run
12
- - [ ] Every failure is classified into the approved four-category taxonomy
13
-
14
- ## Commands
15
-
16
- ```powershell
17
- node scripts/run.mjs --self-check
18
- node scripts/run.mjs --help
19
- node scripts/run.mjs --task workflow-validation-minimal
20
- node scripts/run.mjs --task workflow-validation-minimal-verify
21
- ```
22
-
23
- ## Run result record
24
-
25
- | Field | Value |
26
- |------|------|
27
- | runId | |
28
- | outcome | |
29
- | outputQuality | |
30
- | validation | |
31
- | nextRunRecommendation | |
32
- | failure classification | |
33
-
34
- ## Required artifact checks
35
-
36
- - `decision.md` contains `outputQuality`
37
- - `decision.md` contains `qualityReasons`
38
- - `decision.md` contains readable validation status
39
- - `scorecard.json` contains `outputQuality`
40
- - `scorecard.json` contains `qualityReasons`
41
- - `scorecard.json` contains `validation`
42
- - `scorecard.json` contains `nextRunRecommendation`
43
-
44
- ## Failure classification
45
-
46
- - `workflow bug`
47
- - `agent behavior issue`
48
- - `environment issue`
49
- - `sample-spec issue`
50
-
51
- ## Stop conditions
52
-
53
- If the run exposes a sample-side or product-side issue:
54
-
55
- - classify it
56
- - record evidence
57
- - stop the run review
58
- - do not continue into product closure work
@@ -1,190 +0,0 @@
1
- # Workflow v1.4 Work-Unit Upgrade Handoff
2
-
3
- ## Goal
4
-
5
- Use the packaged `ai-sprint-orchestration` skill to implement the next architecture upgrade of the workflow itself.
6
-
7
- This upgrade is **not** about product-side closure. It is about making the orchestrator better at long-running, high-value coding tasks by introducing a finer-grained execution model.
8
-
9
- The target direction is:
10
-
11
- - move from `stage -> producer/reviewer`
12
- - toward `stage -> work units -> producer/reviewer/decision`
13
-
14
- The key design goal is:
15
-
16
- - smaller execution units
17
- - explicit checkpointing
18
- - forced context reload between units
19
- - less long-context drift
20
-
21
- ## Current confirmed state
22
-
23
- The packaged skill is already usable as an internal tool:
24
-
25
- - package path:
26
- - `D:/Code/principles/packages/openclaw-plugin/templates/langs/zh/skills/ai-sprint-orchestration`
27
- - installed path:
28
- - `C:/Users/Administrator/.agents/skills/ai-sprint-orchestration`
29
- - self-check works
30
- - package-local validation runs work
31
- - failure classification is persisted to:
32
- - `latest-summary.md`
33
- - `scorecard.json`
34
- - complex task templates and minimum task contract already exist
35
-
36
- Remaining instability is mostly:
37
-
38
- - `agent behavior issue`
39
-
40
- It is **not** primarily:
41
-
42
- - pathing
43
- - packaging
44
- - runtime-root layout
45
- - missing acceptance artifacts
46
-
47
- ## Why v1.4 is needed
48
-
49
- The current workflow already externalizes state and can resume from artifacts, but its granularity is still too coarse for very complex tasks.
50
-
51
- Today it mainly refreshes context at:
52
-
53
- - stage level
54
- - role level
55
- - round level
56
-
57
- That is useful, but not yet enough for difficult long-running work where one producer pass can still become too large, too noisy, or too drift-prone.
58
-
59
- The next upgrade should add a smaller unit below stage:
60
-
61
- - `workUnitId`
62
- - `workUnitGoal`
63
- - `allowedFiles`
64
- - `unitChecks`
65
- - `unitDeliverables`
66
- - `unitSummary`
67
- - `carryForwardSummary`
68
-
69
- ## Scope
70
-
71
- ### In scope
72
-
73
- - `packages/openclaw-plugin/templates/langs/zh/skills/ai-sprint-orchestration`
74
- - `packages/openclaw-plugin/templates/langs/en/skills/ai-sprint-orchestration`
75
- - workflow docs, specs, prompts, state shape, and summary artifacts
76
- - package-local validation and workflow-only tests
77
-
78
- ### Out of scope
79
-
80
- - `packages/openclaw-plugin`
81
- - `D:/Code/openclaw`
82
- - product-side/sample-side closure
83
- - dashboard
84
- - stageGraph
85
- - self-optimizing sprint
86
- - parallel orchestrator expansion
87
-
88
- If validation or implementation exposes product-side or sample-side issues, classify them and stop. Do not drift back into product closure work.
89
-
90
- ## Architectural hypothesis
91
-
92
- The most valuable next step is **not** a full rewrite.
93
-
94
- The most valuable next step is to implement a high-value foundation slice:
95
-
96
- 1. define the work-unit contract
97
- 2. define how a stage declares work units
98
- 3. add package-local templates and docs for work-unit-aware tasks
99
- 4. add checkpoint/carry-forward artifacts that are short enough to be reused safely
100
- 5. update prompts so each unit starts from minimal context, not long historical text
101
-
102
- This means the first v1.4 sprint should prioritize:
103
-
104
- - work-unit interfaces
105
- - unit-level artifacts
106
- - unit-level carry-forward
107
- - validation of the new context-reload behavior
108
-
109
- It should **not** try to finish every future v1.4 feature in one pass.
110
-
111
- ## Recommended implementation order
112
-
113
- ### Phase 1: foundation interfaces
114
-
115
- Define and document the unit contract in specs and references:
116
-
117
- - `workUnitId`
118
- - `workUnitGoal`
119
- - `allowedFiles`
120
- - `unitChecks`
121
- - `unitDeliverables`
122
- - `unitSummary`
123
- - `carryForwardSummary`
124
-
125
- Add minimal schema/contract validation for these fields where appropriate.
126
-
127
- ### Phase 2: unit-scoped prompt inputs
128
-
129
- Update producer/reviewer prompt construction so a unit run receives:
130
-
131
- - current unit goal
132
- - allowed files
133
- - expected checks
134
- - expected deliverables
135
- - prior carry-forward summary
136
-
137
- Prefer short checkpoint summaries over replaying long decision history.
138
-
139
- ### Phase 3: checkpoint and continuation tightening
140
-
141
- Standardize the artifact that one unit leaves behind for the next:
142
-
143
- - accomplished
144
- - blockers
145
- - next focus
146
- - verified files
147
-
148
- Make continuation/revise paths prefer this short artifact.
149
-
150
- ### Phase 4: validation
151
-
152
- Add or update validation specs and tests so the workflow can prove:
153
-
154
- - missing task contract is rejected
155
- - work-unit metadata is loaded correctly
156
- - continuation reads compact carry-forward context
157
- - failures still classify cleanly
158
-
159
- ## Success criteria
160
-
161
- The first v1.4 slice is successful if all of these are true:
162
-
163
- 1. The workflow can express work-unit metadata in package-local specs or templates.
164
- 2. Prompts clearly scope a run to a smaller work unit, not a broad stage-only brief.
165
- 3. Continuation uses compact carry-forward summaries by default.
166
- 4. Baseline tests pass.
167
- 5. Package-local self-check still passes.
168
- 6. Validation runs either pass, or fail with explicit classification that is not a workflow-plumbing ambiguity.
169
-
170
- ## Guardrails
171
-
172
- - Do not rewrite the orchestrator from scratch.
173
- - Do not introduce a second orchestration system.
174
- - Do not move back into product/sample closure.
175
- - Do not increase scope to unrelated features.
176
- - Prefer one workflow-only architectural improvement per iteration.
177
- - Preserve the packaged skill as the primary operator entry point.
178
-
179
- ## Suggested starting point for the next thread
180
-
181
- In the next thread, the first sprint should focus on:
182
-
183
- - implementing the work-unit contract and carry-forward foundation
184
- - not the entire future v1.4 roadmap
185
-
186
- Treat this as a bounded architecture slice:
187
-
188
- - high value
189
- - low drift
190
- - directly useful for future complex coding tasks
@@ -1,310 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { ensureDir, readJson, writeJson, writeText, fileExists } from './state-store.mjs';
5
-
6
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
- const packageRoot = path.resolve(__dirname, '..', '..');
8
-
9
- function resolveRoots() {
10
- const runtimeRoot = process.env.AI_SPRINT_RUNTIME_ROOT
11
- ? path.resolve(process.env.AI_SPRINT_RUNTIME_ROOT)
12
- : path.join(packageRoot, 'runtime');
13
- return {
14
- runtimeRoot,
15
- sprintRoot: path.join(runtimeRoot, 'runs'),
16
- archiveRoot: path.join(runtimeRoot, 'archive'),
17
- };
18
- }
19
-
20
- function nowIso() {
21
- return new Date().toISOString();
22
- }
23
-
24
- function shouldArchiveEntry(srcPath, runDir) {
25
- const relative = path.relative(runDir, srcPath);
26
- if (!relative || relative === '') return true;
27
-
28
- const normalized = relative.split(path.sep).join('/');
29
- const base = path.basename(srcPath);
30
-
31
- if (base === 'orchestrator.lock') return false;
32
- if (base.startsWith('.ai-sprint-prompt-')) return false;
33
- if (normalized.includes('/worktrees/')) return false;
34
- if (normalized.startsWith('worktrees/')) return false;
35
- if (normalized.includes('/runtime/')) return false;
36
- if (normalized.startsWith('runtime/')) return false;
37
-
38
- return true;
39
- }
40
-
41
- /**
42
- * Archive a completed/halted sprint run by run ID.
43
- * CLI entry point for --archive <run-id>.
44
- */
45
- export function archiveRunById(runId) {
46
- const { sprintRoot } = resolveRoots();
47
- const runDir = path.join(sprintRoot, runId);
48
- const sprintFile = path.join(runDir, 'sprint.json');
49
- if (!fileExists(sprintFile)) {
50
- throw new Error(`Run not found: ${runId}`);
51
- }
52
- return archiveRun(runDir, runId);
53
- }
54
-
55
- /**
56
- * Core archive function. Copies all artifacts, captures git info, generates summary.
57
- * @param {string} runDir - Path to the sprint run directory
58
- * @param {string} runId - The run ID
59
- * @returns {string} Path to the archive directory
60
- */
61
- export function archiveRun(runDir, runId) {
62
- const { archiveRoot } = resolveRoots();
63
- const destDir = path.join(archiveRoot, runId);
64
-
65
- // Idempotency: check if already successfully archived
66
- const metaPath = path.join(destDir, 'archive-meta.json');
67
- if (fileExists(metaPath)) {
68
- const meta = readJson(metaPath);
69
- if (meta.status === 'completed') {
70
- throw new Error(`Already archived: ${destDir}`);
71
- }
72
- // Partial/failed archive — clean up and re-run
73
- fs.rmSync(destDir, { recursive: true, force: true });
74
- }
75
-
76
- // Read sprint state
77
- const state = readJson(path.join(runDir, 'sprint.json'));
78
-
79
- // Warn if archiving a live run
80
- if (state.status === 'running' || state.status === 'paused') {
81
- console.error(`Warning: run ${runId} has status '${state.status}'. Archiving a live run may produce incomplete artifacts.`);
82
- }
83
-
84
- // Step 1: Copy all run artifacts recursively
85
- ensureDir(destDir);
86
- try {
87
- fs.cpSync(runDir, destDir, {
88
- recursive: true,
89
- filter: (src) => shouldArchiveEntry(src, runDir),
90
- });
91
- } catch {
92
- // Fallback for Node < 16.7: manual recursive copy
93
- copyDirRecursive(runDir, destDir, runDir);
94
- }
95
-
96
- // Step 2: Capture git info
97
- captureGitInfo(destDir, state);
98
-
99
- // Step 3: Generate summary
100
- generateSummary(destDir, state);
101
-
102
- // Step 4: Write archive metadata (last — marks archive as complete)
103
- writeJson(metaPath, {
104
- runId,
105
- archivedAt: nowIso(),
106
- status: 'completed',
107
- sourceStatus: state.status,
108
- });
109
-
110
- return destDir;
111
- }
112
-
113
- /**
114
- * Capture git information into the archive's git/ directory.
115
- * Each command is independent — one failure does not block the rest.
116
- */
117
- function captureGitInfo(destDir, state) {
118
- const gitDir = path.join(destDir, 'git');
119
- ensureDir(gitDir);
120
- const latestGitStatus = findLatestStageGitStatus(destDir);
121
-
122
- if (!latestGitStatus) {
123
- writeText(path.join(gitDir, 'branch.txt'), '# No stage git-status.json found in archive\n');
124
- writeText(path.join(gitDir, 'status.txt'), '# No stage git-status.json found in archive\n');
125
- writeText(path.join(gitDir, 'modified-files.txt'), '# No stage git-status.json found in archive\n');
126
- writeText(path.join(gitDir, 'diff.patch'), '# Diff omitted from archive; inspect archived stage artifacts instead.\n');
127
- writeText(path.join(gitDir, 'log.txt'), '# Git log omitted from archive; inspect archived stage artifacts instead.\n');
128
- return;
129
- }
130
-
131
- const dirtyLines = Array.isArray(latestGitStatus.dirtyFiles) ? latestGitStatus.dirtyFiles : [];
132
- const modifiedFiles = dirtyLines
133
- .map((line) => String(line).replace(/^[ MARCUD?!]+/, '').trim())
134
- .filter(Boolean);
135
-
136
- writeText(path.join(gitDir, 'branch.txt'), `${latestGitStatus.branch || 'unknown'}\n`);
137
- writeText(path.join(gitDir, 'status.txt'), `${dirtyLines.length ? dirtyLines.join('\n') : '# clean'}\n`);
138
- writeText(path.join(gitDir, 'modified-files.txt'), `${modifiedFiles.length ? modifiedFiles.join('\n') : '# none'}\n`);
139
- writeText(path.join(gitDir, 'diff.patch'), '# Diff omitted from archive; inspect archived stage artifacts and git-status.json.\n');
140
- writeText(path.join(gitDir, 'log.txt'), [
141
- `headSha: ${latestGitStatus.headSha || 'unknown'}`,
142
- `baseBranch: ${latestGitStatus.baseBranch || 'unknown'}`,
143
- `remoteBranch: ${latestGitStatus.remoteBranch || 'unknown'}`,
144
- `capturedAt: ${state.updatedAt || nowIso()}`,
145
- ].join('\n') + '\n');
146
- }
147
-
148
- function findLatestStageGitStatus(destDir) {
149
- const stagesDir = path.join(destDir, 'stages');
150
- if (!fileExists(stagesDir)) return null;
151
-
152
- const stageDirs = fs.readdirSync(stagesDir).sort().reverse();
153
- for (const dir of stageDirs) {
154
- const gitStatusPath = path.join(stagesDir, dir, 'git-status.json');
155
- if (fileExists(gitStatusPath)) {
156
- return readJson(gitStatusPath);
157
- }
158
- }
159
- return null;
160
- }
161
-
162
- /**
163
- * Generate a human-readable archive summary.
164
- */
165
- function generateSummary(destDir, state) {
166
- const lines = [];
167
-
168
- // Identity
169
- lines.push(`# Sprint Archive: ${state.title || state.taskId}`);
170
- lines.push('');
171
- lines.push('## Identity');
172
- lines.push(`- Run ID: ${state.runId}`);
173
- lines.push(`- Task: ${state.taskId}`);
174
- lines.push(`- Status: ${state.status}`);
175
- lines.push(`- Archived at: ${nowIso()}`);
176
- lines.push('');
177
-
178
- // Timeline
179
- const created = state.createdAt || '';
180
- const updated = state.updatedAt || '';
181
- const elapsedMs = created ? (Date.parse(updated) || Date.now()) - Date.parse(created) : 0;
182
- const elapsedMin = (elapsedMs / 60_000).toFixed(1);
183
- lines.push('## Timeline');
184
- lines.push(`- Created: ${created}`);
185
- lines.push(`- Updated: ${updated}`);
186
- lines.push(`- Total wall time: ${elapsedMin} minutes`);
187
- lines.push(`- Final stage: ${state.currentStage} (index ${state.currentStageIndex})`);
188
- lines.push(`- Final round: ${state.currentRound}`);
189
- lines.push('');
190
-
191
- // Stage progress table from scorecards
192
- lines.push('## Stage Progress');
193
- const stagesDir = path.join(destDir, 'stages');
194
- const stageEntries = [];
195
- if (fileExists(stagesDir)) {
196
- const dirs = fs.readdirSync(stagesDir).sort();
197
- for (const dir of dirs) {
198
- const scorecardPath = path.join(stagesDir, dir, 'scorecard.json');
199
- if (fileExists(scorecardPath)) {
200
- const sc = readJson(scorecardPath);
201
- stageEntries.push({
202
- dir,
203
- outcome: sc.outcome || '?',
204
- round: sc.round || '?',
205
- approvals: sc.approvalCount ?? '?',
206
- blockers: sc.blockerCount ?? 0,
207
- reviewerA: sc.reviewerAVerdict || '?',
208
- reviewerB: sc.reviewerBVerdict || '?',
209
- });
210
- }
211
- }
212
- }
213
-
214
- if (stageEntries.length > 0) {
215
- lines.push('| Stage | Outcome | Round | Approvals | Blockers | Reviewer A | Reviewer B |');
216
- lines.push('|-------|---------|-------|-----------|----------|-----------|-----------|');
217
- for (const s of stageEntries) {
218
- lines.push(`| ${s.dir} | ${s.outcome} | ${s.round} | ${s.approvals}/2 | ${s.blockers} | ${s.reviewerA} | ${s.reviewerB} |`);
219
- }
220
- } else {
221
- lines.push('No stage scorecards found.');
222
- }
223
- lines.push('');
224
-
225
- // Git context
226
- lines.push('## Git Context');
227
- const gitDir = path.join(destDir, 'git');
228
- if (fileExists(path.join(gitDir, 'branch.txt'))) {
229
- lines.push(`- Branch: ${fs.readFileSync(path.join(gitDir, 'branch.txt'), 'utf8').trim()}`);
230
- }
231
- if (fileExists(path.join(gitDir, 'log.txt'))) {
232
- const log = fs.readFileSync(path.join(gitDir, 'log.txt'), 'utf8').trim();
233
- if (log && !log.startsWith('#')) {
234
- lines.push('');
235
- lines.push('### Commits');
236
- for (const line of log.split('\n').filter(Boolean)) {
237
- lines.push(`- ${line}`);
238
- }
239
- }
240
- }
241
- if (fileExists(path.join(gitDir, 'modified-files.txt'))) {
242
- const files = fs.readFileSync(path.join(gitDir, 'modified-files.txt'), 'utf8').trim();
243
- if (files && !files.startsWith('#')) {
244
- lines.push('');
245
- lines.push('### Modified Files');
246
- for (const f of files.split('\n').filter(Boolean)) {
247
- lines.push(`- ${f}`);
248
- }
249
- }
250
- }
251
- lines.push('');
252
-
253
- // Halt reason
254
- if (state.haltReason) {
255
- lines.push('## Halt Reason');
256
- lines.push(`- Type: ${state.haltReason.type}`);
257
- lines.push(`- Details: ${state.haltReason.details}`);
258
- if (state.haltReason.blockers?.length) {
259
- lines.push('### Blockers');
260
- for (const b of state.haltReason.blockers) {
261
- lines.push(`- ${b}`);
262
- }
263
- }
264
- lines.push('');
265
- }
266
-
267
- // Open risks from verify producer
268
- const verifyDirs = stageEntries.filter((s) => s.dir.includes('verify'));
269
- if (verifyDirs.length > 0) {
270
- const verifyDir = path.join(stagesDir, verifyDirs[verifyDirs.length - 1].dir);
271
- const producerPath = path.join(verifyDir, 'producer.md');
272
- if (fileExists(producerPath)) {
273
- const producerText = fs.readFileSync(producerPath, 'utf8');
274
- const risksSection = extractSection(producerText, 'OPEN_RISKS');
275
- if (risksSection) {
276
- lines.push('## Open Risks (from verify producer)');
277
- lines.push(risksSection);
278
- lines.push('');
279
- }
280
- }
281
- }
282
-
283
- writeText(path.join(destDir, 'archive-summary.md'), lines.join('\n') + '\n');
284
- }
285
-
286
- /**
287
- * Extract a markdown section body by heading name.
288
- */
289
- function extractSection(text, heading) {
290
- const pattern = new RegExp(`^##\\s+${heading}\\s*\\n([\\s\\S]*?)(?=^##\\s|$(?!\\n))`, 'm');
291
- const match = text.match(pattern);
292
- return match ? match[1].trim() : null;
293
- }
294
-
295
- /**
296
- * Fallback recursive directory copy for Node < 16.7.
297
- */
298
- function copyDirRecursive(src, dest, rootDir = src) {
299
- ensureDir(dest);
300
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
301
- const srcPath = path.join(src, entry.name);
302
- const destPath = path.join(dest, entry.name);
303
- if (!shouldArchiveEntry(srcPath, rootDir)) continue;
304
- if (entry.isDirectory()) {
305
- copyDirRecursive(srcPath, destPath, rootDir);
306
- } else {
307
- fs.copyFileSync(srcPath, destPath);
308
- }
309
- }
310
- }