principles-disciple 1.81.0 → 1.82.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.
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/commands/strategy.ts +0 -18
- package/src/i18n/commands.ts +0 -12
- package/src/index.ts +4 -22
- package/templates/langs/en/core/BOOTSTRAP.md +4 -18
- package/templates/langs/en/skills/bootstrap-tools/SKILL.md +1 -1
- package/templates/langs/en/skills/init-strategy/SKILL.md +1 -1
- package/templates/langs/en/skills/pd-mentor/SKILL.md +8 -23
- package/templates/langs/zh/core/BOOTSTRAP.md +2 -15
- package/templates/langs/zh/skills/bootstrap-tools/SKILL.md +1 -1
- package/templates/langs/zh/skills/init-strategy/SKILL.md +1 -1
- package/templates/langs/zh/skills/pd-mentor/SKILL.md +7 -22
- package/tests/commands/strategy.test.ts +3 -18
- package/templates/langs/en/skills/ai-sprint-orchestration/EXAMPLES.md +0 -63
- package/templates/langs/en/skills/ai-sprint-orchestration/REFERENCE.md +0 -136
- package/templates/langs/en/skills/ai-sprint-orchestration/SKILL.md +0 -67
- package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +0 -143
- package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +0 -107
- package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +0 -107
- package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +0 -95
- package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +0 -98
- package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +0 -58
- package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +0 -190
- package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +0 -310
- package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +0 -683
- package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +0 -604
- package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +0 -32
- package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +0 -707
- package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +0 -3455
- package/templates/langs/en/skills/evolve-system/SKILL.md +0 -46
- package/templates/langs/en/skills/manage-okr/SKILL.md +0 -96
- package/templates/langs/en/skills/pd-daily/SKILL.md +0 -199
- package/templates/langs/en/skills/pd-grooming/SKILL.md +0 -46
- package/templates/langs/zh/skills/ai-sprint-orchestration/EXAMPLES.md +0 -63
- package/templates/langs/zh/skills/ai-sprint-orchestration/REFERENCE.md +0 -136
- package/templates/langs/zh/skills/ai-sprint-orchestration/SKILL.md +0 -67
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +0 -143
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +0 -107
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +0 -107
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +0 -111
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +0 -95
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +0 -98
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +0 -58
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +0 -190
- package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +0 -2
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +0 -310
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +0 -683
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +0 -604
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +0 -32
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +0 -707
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +0 -3455
- package/templates/langs/zh/skills/ai-sprint-orchestration/test/archive.test.mjs +0 -230
- package/templates/langs/zh/skills/ai-sprint-orchestration/test/contract-enforcement.test.mjs +0 -672
- package/templates/langs/zh/skills/ai-sprint-orchestration/test/decision.test.mjs +0 -1321
- package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +0 -1435
- package/templates/langs/zh/skills/evolve-system/SKILL.md +0 -46
- package/templates/langs/zh/skills/manage-okr/SKILL.md +0 -109
- package/templates/langs/zh/skills/pd-daily/SKILL.md +0 -283
- 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
|
-
}
|