cc-devflow 4.5.10 → 4.5.12
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/.claude/skills/cc-act/CHANGELOG.md +23 -0
- package/.claude/skills/cc-act/PLAYBOOK.md +17 -269
- package/.claude/skills/cc-act/SKILL.md +38 -418
- package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_INDEX_TEMPLATE.md +2 -13
- package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_TEMPLATE.md +1 -9
- package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +21 -177
- package/.claude/skills/cc-act/references/closure-contract.md +12 -63
- package/.claude/skills/cc-act/references/git-commit-guidelines.md +5 -5
- package/.claude/skills/cc-act/scripts/cc-act-common.sh +5 -322
- package/.claude/skills/cc-act/scripts/detect-ship-target.sh +11 -2
- package/.claude/skills/cc-act/scripts/inspect-git-index.sh +58 -0
- package/.claude/skills/cc-act/scripts/render-pr-brief.sh +40 -440
- package/.claude/skills/cc-act/scripts/verify-act-gate.sh +10 -50
- package/.claude/skills/cc-check/CHANGELOG.md +24 -0
- package/.claude/skills/cc-check/PLAYBOOK.md +19 -273
- package/.claude/skills/cc-check/SKILL.md +33 -454
- package/.claude/skills/cc-check/references/review-contract.md +12 -147
- package/.claude/skills/cc-dev/CHANGELOG.md +20 -0
- package/.claude/skills/cc-dev/PLAYBOOK.md +1 -1
- package/.claude/skills/cc-dev/SKILL.md +52 -130
- package/.claude/skills/cc-dev/scripts/resolve-cc-devflow.sh +181 -0
- package/.claude/skills/cc-do/CHANGELOG.md +17 -0
- package/.claude/skills/cc-do/PLAYBOOK.md +19 -113
- package/.claude/skills/cc-do/SKILL.md +39 -236
- package/.claude/skills/cc-do/references/execution-recovery.md +15 -109
- package/.claude/skills/cc-do/scripts/cc-do-common.sh +5 -57
- package/.claude/skills/cc-do/scripts/check-task-status.sh +35 -65
- package/.claude/skills/cc-do/scripts/mark-task-complete.sh +9 -46
- package/.claude/skills/cc-do/scripts/select-ready-tasks.sh +29 -97
- package/.claude/skills/cc-investigate/CHANGELOG.md +23 -0
- package/.claude/skills/cc-investigate/PLAYBOOK.md +20 -180
- package/.claude/skills/cc-investigate/SKILL.md +65 -513
- package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +48 -95
- package/.claude/skills/cc-investigate/references/investigation-contract.md +14 -217
- package/.claude/skills/cc-next/CHANGELOG.md +6 -0
- package/.claude/skills/cc-next/PLAYBOOK.md +12 -8
- package/.claude/skills/cc-next/SKILL.md +34 -140
- package/.claude/skills/cc-plan/CHANGELOG.md +29 -0
- package/.claude/skills/cc-plan/PLAYBOOK.md +22 -161
- package/.claude/skills/cc-plan/SKILL.md +47 -640
- package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +30 -225
- package/.claude/skills/cc-plan/references/planning-contract.md +24 -160
- package/.claude/skills/cc-plan/scripts/next-change-key.sh +8 -44
- package/.claude/skills/cc-plan/scripts/parse-task-dependencies.js +2 -2
- package/.claude/skills/cc-plan/scripts/validate-scope.sh +1 -1
- package/.claude/skills/cc-pr-land/SKILL.md +14 -114
- package/.claude/skills/cc-pr-review/CHANGELOG.md +4 -0
- package/.claude/skills/cc-pr-review/SKILL.md +20 -103
- package/.claude/skills/cc-review/CHANGELOG.md +17 -0
- package/.claude/skills/cc-review/PLAYBOOK.md +13 -86
- package/.claude/skills/cc-review/SKILL.md +53 -241
- package/.claude/skills/cc-review/references/e2e-and-plugin-verification.md +2 -2
- package/.claude/skills/cc-review/references/implementation-review-branch.md +7 -147
- package/.claude/skills/cc-review/references/plan-review-branch.md +5 -147
- package/.claude/skills/cc-review/references/review-methods.md +10 -218
- package/.claude/skills/cc-review/scripts/collect-review-context.sh +4 -63
- package/.claude/skills/cc-roadmap/PLAYBOOK.md +1 -1
- package/.claude/skills/cc-roadmap/SKILL.md +3 -3
- package/.claude/skills/cc-simplify/CHANGELOG.md +7 -0
- package/.claude/skills/cc-simplify/SKILL.md +26 -21
- package/.claude/skills/cc-spec-init/PLAYBOOK.md +12 -48
- package/.claude/skills/cc-spec-init/SKILL.md +29 -132
- package/.claude/skills/cc-spec-init/references/spec-contract.md +8 -17
- package/CHANGELOG.md +27 -0
- package/README.md +5 -3
- package/README.zh-CN.md +5 -3
- package/bin/cc-devflow-cli.js +20 -260
- package/bin/cc-devflow.js +44 -7
- package/docs/commands/README.md +1 -1
- package/docs/commands/README.zh-CN.md +1 -1
- package/docs/examples/README.md +1 -1
- package/docs/examples/START-HERE.md +14 -14
- package/docs/examples/example-bindings.json +11 -11
- package/docs/examples/full-design-blocked/README.md +4 -6
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/{planning/tasks.md → task.md} +20 -15
- package/docs/examples/local-handoff/README.md +8 -11
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/pr-brief.md +31 -0
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/{planning/tasks.md → task.md} +18 -13
- package/docs/examples/pdca-loop/README.md +6 -9
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +9 -11
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/{planning/tasks.md → task.md} +18 -13
- package/docs/examples/scripts/check-example-bindings.sh +11 -62
- package/docs/guides/artifact-contract.md +10 -36
- package/docs/guides/getting-started.md +8 -7
- package/docs/guides/getting-started.zh-CN.md +8 -7
- package/docs/guides/minimize-artifacts.md +16 -116
- package/docs/guides/project-postmortem.md +14 -71
- package/lib/compiler/__tests__/skills-registry.test.js +9 -8
- package/lib/compiler/resource-copier.js +29 -0
- package/lib/skill-runtime/__tests__/archive-change.test.js +2 -2
- package/lib/skill-runtime/__tests__/benchmark-skills.test.js +109 -0
- package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +14 -4
- package/lib/skill-runtime/errors.js +3 -3
- package/lib/skill-runtime/index.js +5 -23
- package/lib/skill-runtime/paths.js +5 -52
- package/lib/skill-runtime/query-registry.js +4 -4
- package/lib/skill-runtime/query.js +89 -201
- package/lib/skill-runtime/store.js +4 -40
- package/lib/skill-runtime/trace.js +2 -2
- package/package.json +5 -7
- package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_PRINCIPLES_TEMPLATE.md +0 -29
- package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +0 -54
- package/.claude/skills/cc-act/scripts/generate-status-report.sh +0 -92
- package/.claude/skills/cc-act/scripts/sync-act-docs.sh +0 -355
- package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +0 -234
- package/.claude/skills/cc-check/scripts/render-report-card.js +0 -438
- package/.claude/skills/cc-check/scripts/verify-gate.sh +0 -85
- package/.claude/skills/cc-do/scripts/build-task-context.sh +0 -175
- package/.claude/skills/cc-do/scripts/record-review-decision.sh +0 -88
- package/.claude/skills/cc-do/scripts/recover-workflow.sh +0 -82
- package/.claude/skills/cc-do/scripts/run-problem-analysis.sh +0 -70
- package/.claude/skills/cc-do/scripts/verify-task-gates.sh +0 -109
- package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +0 -92
- package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +0 -225
- package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +0 -179
- package/.claude/skills/cc-spec-init/assets/CHANGE_META_TEMPLATE.json +0 -28
- package/.claude/skills/cc-spec-init/scripts/validate-spec-links.sh +0 -45
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +0 -234
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +0 -488
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +0 -189
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/resume-index.md +0 -39
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/status.md +0 -29
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +0 -123
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +0 -292
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +0 -136
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/status.md +0 -29
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +0 -124
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +0 -292
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +0 -136
- package/docs/get-shit-done-strategy-audit.md +0 -518
- package/docs/skill-runtime-migration.md +0 -46
- package/lib/skill-runtime/__tests__/approve.test.js +0 -92
- package/lib/skill-runtime/__tests__/autopilot.test.js +0 -253
- package/lib/skill-runtime/__tests__/benchmark-artifacts.test.js +0 -165
- package/lib/skill-runtime/__tests__/delegation.test.js +0 -97
- package/lib/skill-runtime/__tests__/dispatch.test.js +0 -237
- package/lib/skill-runtime/__tests__/intent.test.js +0 -203
- package/lib/skill-runtime/__tests__/lifecycle.test.js +0 -169
- package/lib/skill-runtime/__tests__/planner.tdd.test.js +0 -331
- package/lib/skill-runtime/__tests__/prepare-pr.test.js +0 -126
- package/lib/skill-runtime/__tests__/query.test.js +0 -860
- package/lib/skill-runtime/__tests__/readiness.test.js +0 -53
- package/lib/skill-runtime/__tests__/release.test.js +0 -85
- package/lib/skill-runtime/__tests__/review-check-integration.test.js +0 -148
- package/lib/skill-runtime/__tests__/review-records.test.js +0 -619
- package/lib/skill-runtime/__tests__/runtime.integration.test.js +0 -351
- package/lib/skill-runtime/__tests__/schemas.test.js +0 -337
- package/lib/skill-runtime/__tests__/task-contract-migrate.test.js +0 -137
- package/lib/skill-runtime/__tests__/task-contract.test.js +0 -783
- package/lib/skill-runtime/__tests__/team-state.test.js +0 -51
- package/lib/skill-runtime/__tests__/verify-artifacts.test.js +0 -203
- package/lib/skill-runtime/__tests__/worker-run.test.js +0 -275
- package/lib/skill-runtime/__tests__/worker.test.js +0 -56
- package/lib/skill-runtime/__tests__/workflow-context-legacy-fallback.test.js +0 -31
- package/lib/skill-runtime/__tests__/workflow-context.test.js +0 -98
- package/lib/skill-runtime/artifacts.js +0 -88
- package/lib/skill-runtime/context-index.js +0 -545
- package/lib/skill-runtime/delegation.js +0 -533
- package/lib/skill-runtime/intent.js +0 -309
- package/lib/skill-runtime/lifecycle.js +0 -294
- package/lib/skill-runtime/operations/CLAUDE.md +0 -19
- package/lib/skill-runtime/operations/approve.js +0 -81
- package/lib/skill-runtime/operations/autopilot-core.js +0 -337
- package/lib/skill-runtime/operations/autopilot-execution.js +0 -307
- package/lib/skill-runtime/operations/autopilot-shared.js +0 -48
- package/lib/skill-runtime/operations/autopilot.js +0 -163
- package/lib/skill-runtime/operations/dispatch.js +0 -416
- package/lib/skill-runtime/operations/init.js +0 -60
- package/lib/skill-runtime/operations/janitor.js +0 -61
- package/lib/skill-runtime/operations/plan.js +0 -59
- package/lib/skill-runtime/operations/prepare-pr.js +0 -25
- package/lib/skill-runtime/operations/release.js +0 -99
- package/lib/skill-runtime/operations/resume.js +0 -126
- package/lib/skill-runtime/operations/review-records.js +0 -265
- package/lib/skill-runtime/operations/snapshot.js +0 -45
- package/lib/skill-runtime/operations/task-contract.js +0 -524
- package/lib/skill-runtime/operations/verify.js +0 -170
- package/lib/skill-runtime/operations/worker-run.js +0 -531
- package/lib/skill-runtime/operations/worker.js +0 -33
- package/lib/skill-runtime/planner.js +0 -539
- package/lib/skill-runtime/readiness.js +0 -84
- package/lib/skill-runtime/review-records.js +0 -123
- package/lib/skill-runtime/review.js +0 -855
- package/lib/skill-runtime/schemas.js +0 -746
- package/lib/skill-runtime/task-contract.js +0 -187
- package/lib/skill-runtime/team-state.js +0 -122
- package/lib/skill-runtime/workflow-context.js +0 -748
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const {
|
|
6
|
-
getTeamStatePath,
|
|
7
|
-
readTeamState,
|
|
8
|
-
writeTeamState
|
|
9
|
-
} = require('../team-state');
|
|
10
|
-
|
|
11
|
-
describe('team-state', () => {
|
|
12
|
-
test('writes and reads the canonical truth state', async () => {
|
|
13
|
-
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-team-state-'));
|
|
14
|
-
fs.writeFileSync(path.join(repoRoot, 'package.json'), JSON.stringify({ name: 'team-state-smoke', version: '1.0.0' }, null, 2));
|
|
15
|
-
|
|
16
|
-
await writeTeamState(repoRoot, 'REQ-123', {
|
|
17
|
-
status: 'delegated',
|
|
18
|
-
phase: 'delegate',
|
|
19
|
-
branch: 'main',
|
|
20
|
-
planVersion: 4,
|
|
21
|
-
team: {
|
|
22
|
-
mode: 'parallel',
|
|
23
|
-
lead: 'main-agent',
|
|
24
|
-
teammates: [
|
|
25
|
-
{
|
|
26
|
-
id: 'delegate-01',
|
|
27
|
-
role: 'dev-implementer',
|
|
28
|
-
status: 'idle',
|
|
29
|
-
currentTask: null,
|
|
30
|
-
completedTasks: [],
|
|
31
|
-
lastActiveAt: '2026-03-26T00:00:00.000Z'
|
|
32
|
-
}
|
|
33
|
-
],
|
|
34
|
-
taskAssignments: {
|
|
35
|
-
T001: 'delegate-01'
|
|
36
|
-
},
|
|
37
|
-
createdAt: '2026-03-26T00:00:00.000Z',
|
|
38
|
-
updatedAt: '2026-03-26T00:00:00.000Z'
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const truth = JSON.parse(fs.readFileSync(getTeamStatePath(repoRoot, 'REQ-123'), 'utf8'));
|
|
43
|
-
const state = await readTeamState(repoRoot, 'REQ-123');
|
|
44
|
-
|
|
45
|
-
expect(truth.changeId).toBe('REQ-123');
|
|
46
|
-
expect(truth.team.taskAssignments.T001).toBe('delegate-01');
|
|
47
|
-
expect(state.changeId).toBe('REQ-123');
|
|
48
|
-
expect(state.planVersion).toBe(4);
|
|
49
|
-
expect(state.phase).toBe('delegate');
|
|
50
|
-
});
|
|
51
|
-
});
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* [INPUT]: 依赖 scripts/verify-artifacts.js 导出的 runVerifyArtifacts 和临时 change fixture。
|
|
3
|
-
* [OUTPUT]: 验证 verify:artifacts 只实现 C1-C10,返回稳定 exit code 和 JSON 报告。
|
|
4
|
-
* [POS]: REQ-003-minimize-workflow-artifacts T016 的 Red/Green 证据。
|
|
5
|
-
* [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const os = require('os');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const { spawnSync } = require('child_process');
|
|
12
|
-
|
|
13
|
-
const { runVerifyArtifacts } = require('../../../scripts/verify-artifacts');
|
|
14
|
-
|
|
15
|
-
const REPO_ROOT = path.resolve(__dirname, '../../..');
|
|
16
|
-
const VERIFY_SCRIPT = path.join(REPO_ROOT, 'scripts', 'verify-artifacts.js');
|
|
17
|
-
|
|
18
|
-
function writeJson(filePath, value) {
|
|
19
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
20
|
-
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function tasksMarkdown({ profile = 'standard', taskCount = 1, extraBody = '' } = {}) {
|
|
24
|
-
const contract = [
|
|
25
|
-
'# Tasks',
|
|
26
|
-
'',
|
|
27
|
-
'## Contract Summary',
|
|
28
|
-
'',
|
|
29
|
-
'Change: REQ-900-valid-artifacts',
|
|
30
|
-
'Mode: plan',
|
|
31
|
-
`Profile: ${profile}`,
|
|
32
|
-
'Approval: approved',
|
|
33
|
-
'',
|
|
34
|
-
'Goal:',
|
|
35
|
-
'- Keep artifact verification deterministic.',
|
|
36
|
-
'',
|
|
37
|
-
'Do Not Do:',
|
|
38
|
-
'- Do not add checks outside C1-C10.',
|
|
39
|
-
'',
|
|
40
|
-
'Approved Direction:',
|
|
41
|
-
'- Verify the minimized artifact shape.',
|
|
42
|
-
'',
|
|
43
|
-
'Acceptance:',
|
|
44
|
-
'- The verifier returns stable rule ids and exit codes.',
|
|
45
|
-
'',
|
|
46
|
-
'Verification:',
|
|
47
|
-
'',
|
|
48
|
-
'```bash',
|
|
49
|
-
'npm run verify:artifacts',
|
|
50
|
-
'```',
|
|
51
|
-
'',
|
|
52
|
-
'Risk / Escalate If:',
|
|
53
|
-
'- The rule table drifts from C1-C10.',
|
|
54
|
-
''
|
|
55
|
-
];
|
|
56
|
-
const tasks = Array.from({ length: taskCount }, (_, index) => [
|
|
57
|
-
`- [ ] T${String(index + 1).padStart(3, '0')} validate artifacts`,
|
|
58
|
-
' Goal: Exercise one verifier rule.',
|
|
59
|
-
' Files: `scripts/verify-artifacts.js`',
|
|
60
|
-
' Verification: npm run verify:artifacts',
|
|
61
|
-
` Vertical slice: Slice ${index + 1}`,
|
|
62
|
-
''
|
|
63
|
-
].join('\n'));
|
|
64
|
-
return [...contract, extraBody, '## Phase 1', '', ...tasks].join('\n');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function seedValidChange(repoRoot, options = {}) {
|
|
68
|
-
const changeKey = options.changeKey || 'REQ-900-valid-artifacts';
|
|
69
|
-
const changeDir = path.join(repoRoot, 'devflow', 'changes', changeKey);
|
|
70
|
-
const planningDir = path.join(changeDir, 'planning');
|
|
71
|
-
fs.mkdirSync(planningDir, { recursive: true });
|
|
72
|
-
fs.writeFileSync(path.join(planningDir, 'tasks.md'), tasksMarkdown(options));
|
|
73
|
-
writeJson(path.join(planningDir, 'task-manifest.json'), {
|
|
74
|
-
changeId: changeKey,
|
|
75
|
-
createdAt: '2026-05-12T00:00:00.000Z',
|
|
76
|
-
updatedAt: '2026-05-12T00:00:00.000Z',
|
|
77
|
-
currentTaskId: null,
|
|
78
|
-
tasks: [],
|
|
79
|
-
metadata: {
|
|
80
|
-
source: 'tasks.md',
|
|
81
|
-
generatedBy: 'cc-devflow task-contract',
|
|
82
|
-
planVersion: 1
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
writeJson(path.join(changeDir, 'change-meta.json'), {
|
|
86
|
-
changeId: changeKey,
|
|
87
|
-
requirementId: changeKey,
|
|
88
|
-
goal: ['Verify artifacts'],
|
|
89
|
-
acceptance: ['Verifier passes'],
|
|
90
|
-
specReference: {
|
|
91
|
-
source: 'planning/tasks.md#contract-summary',
|
|
92
|
-
change: changeKey,
|
|
93
|
-
mode: 'plan',
|
|
94
|
-
profile: options.profile || 'standard',
|
|
95
|
-
approval: 'approved'
|
|
96
|
-
},
|
|
97
|
-
_meta: {
|
|
98
|
-
generatedBy: 'cc-devflow task-contract',
|
|
99
|
-
generatedAt: '2026-05-12T00:00:00.000Z'
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
return { changeDir, planningDir, changeKey };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
describe('verify:artifacts', () => {
|
|
106
|
-
let repoRoot;
|
|
107
|
-
|
|
108
|
-
beforeEach(() => {
|
|
109
|
-
repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-verify-artifacts-'));
|
|
110
|
-
writeJson(path.join(repoRoot, 'package.json'), {
|
|
111
|
-
name: 'verify-artifacts-fixture',
|
|
112
|
-
version: '0.0.0',
|
|
113
|
-
scripts: {
|
|
114
|
-
'verify:artifacts': 'node scripts/verify-artifacts.js'
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
afterEach(() => {
|
|
120
|
-
fs.rmSync(repoRoot, { recursive: true, force: true });
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const ruleCases = [
|
|
124
|
-
['C1', 2, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'design.md'), '# legacy design\n')],
|
|
125
|
-
['C2', 2, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'analysis.md'), '# legacy analysis\n')],
|
|
126
|
-
['C3', 2, (ctx) => {
|
|
127
|
-
const reviewDir = path.join(ctx.changeDir, 'review');
|
|
128
|
-
fs.mkdirSync(reviewDir, { recursive: true });
|
|
129
|
-
fs.writeFileSync(path.join(reviewDir, 'cc-review-report.md'), '# legacy review\n');
|
|
130
|
-
}],
|
|
131
|
-
['C4', 3, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'tasks.md'), '# Tasks\n\n- [ ] T001 no contract\n')],
|
|
132
|
-
['C5', 3, (ctx) => writeJson(path.join(ctx.planningDir, 'task-manifest.json'), {
|
|
133
|
-
changeId: ctx.changeKey,
|
|
134
|
-
createdAt: '2026-05-12T00:00:00.000Z',
|
|
135
|
-
updatedAt: '2026-05-12T00:00:00.000Z',
|
|
136
|
-
currentTaskId: null,
|
|
137
|
-
tasks: [],
|
|
138
|
-
metadata: { source: 'tasks.md', generatedBy: 'manual', planVersion: 1 }
|
|
139
|
-
})],
|
|
140
|
-
['C6', 3, (ctx) => writeJson(path.join(ctx.changeDir, 'change-meta.json'), {
|
|
141
|
-
_meta: { generatedBy: 'manual' }
|
|
142
|
-
})],
|
|
143
|
-
['C7', 4, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'tasks.md'), tasksMarkdown({
|
|
144
|
-
profile: 'tiny',
|
|
145
|
-
taskCount: 2
|
|
146
|
-
}))],
|
|
147
|
-
['C8', 5, (ctx) => {
|
|
148
|
-
const reviewDir = path.join(ctx.changeDir, 'review');
|
|
149
|
-
fs.mkdirSync(reviewDir, { recursive: true });
|
|
150
|
-
fs.writeFileSync(path.join(reviewDir, 'review-ledger.jsonl'), '{"event":"review-started"}\n');
|
|
151
|
-
}],
|
|
152
|
-
['C9', 5, (ctx) => {
|
|
153
|
-
const reviewDir = path.join(ctx.changeDir, 'review');
|
|
154
|
-
fs.mkdirSync(reviewDir, { recursive: true });
|
|
155
|
-
fs.writeFileSync(path.join(reviewDir, 'report-card.json'), '{"overall":"pass"}\n');
|
|
156
|
-
}],
|
|
157
|
-
['C10', 6, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'tasks.md'), tasksMarkdown({
|
|
158
|
-
profile: 'standard',
|
|
159
|
-
extraBody: 'x'.repeat(12000)
|
|
160
|
-
}))]
|
|
161
|
-
];
|
|
162
|
-
|
|
163
|
-
test.each(ruleCases)('%s returns exit code %i with JSON report', async (ruleId, exitCode, mutate) => {
|
|
164
|
-
const ctx = seedValidChange(repoRoot, { changeKey: `REQ-9${ruleId.slice(1).padStart(2, '0')}-${ruleId.toLowerCase()}` });
|
|
165
|
-
mutate(ctx);
|
|
166
|
-
|
|
167
|
-
const result = await runVerifyArtifacts(repoRoot);
|
|
168
|
-
|
|
169
|
-
expect(result.code).toBe(exitCode);
|
|
170
|
-
expect(result.violations[0]).toMatchObject({ ruleId, exitCode });
|
|
171
|
-
expect(result.checks).toHaveLength(10);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
test('passes a valid generated change and skips grandfathered legacy directories', async () => {
|
|
175
|
-
seedValidChange(repoRoot);
|
|
176
|
-
const legacy = seedValidChange(repoRoot, { changeKey: 'REQ-001-legacy-fallback' });
|
|
177
|
-
fs.writeFileSync(path.join(legacy.planningDir, 'design.md'), '# grandfathered design\n');
|
|
178
|
-
const manifest = JSON.parse(fs.readFileSync(path.join(legacy.planningDir, 'task-manifest.json'), 'utf8'));
|
|
179
|
-
manifest.metadata.generatedBy = 'skill:cc-plan';
|
|
180
|
-
fs.writeFileSync(path.join(legacy.planningDir, 'task-manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
181
|
-
|
|
182
|
-
const result = await runVerifyArtifacts(repoRoot);
|
|
183
|
-
|
|
184
|
-
expect(result).toMatchObject({ code: 0, ok: true });
|
|
185
|
-
expect(result.skippedLegacy.map((item) => item.changeKey)).toContain('REQ-001-legacy-fallback');
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
test('CLI prints stdout JSON and exits with the first violation code', () => {
|
|
189
|
-
const ctx = seedValidChange(repoRoot);
|
|
190
|
-
fs.writeFileSync(path.join(ctx.planningDir, 'design.md'), '# rogue design\n');
|
|
191
|
-
|
|
192
|
-
const result = spawnSync(process.execPath, [VERIFY_SCRIPT, repoRoot], { encoding: 'utf8' });
|
|
193
|
-
const report = JSON.parse(result.stdout);
|
|
194
|
-
|
|
195
|
-
expect(result.status).toBe(2);
|
|
196
|
-
expect(report.violations[0].ruleId).toBe('C1');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test('package.json exposes npm run verify:artifacts', () => {
|
|
200
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8'));
|
|
201
|
-
expect(pkg.scripts['verify:artifacts']).toBe('node scripts/verify-artifacts.js');
|
|
202
|
-
});
|
|
203
|
-
});
|
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const { syncDelegationRuntime, buildWorkerHandoff, getMessageBusPath, getWorkerAssignmentPath } = require('../delegation');
|
|
6
|
-
const {
|
|
7
|
-
buildProviderPrompt,
|
|
8
|
-
buildProviderCommand,
|
|
9
|
-
runWorkerCommand
|
|
10
|
-
} = require('../operations/worker-run');
|
|
11
|
-
const {
|
|
12
|
-
getRuntimeStatePath,
|
|
13
|
-
getTaskManifestPath,
|
|
14
|
-
getEventsPath
|
|
15
|
-
} = require('../store');
|
|
16
|
-
|
|
17
|
-
function writeJson(filePath, value) {
|
|
18
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
19
|
-
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function createManifest() {
|
|
23
|
-
return {
|
|
24
|
-
changeId: 'REQ-123',
|
|
25
|
-
goal: 'Run delegated worker command',
|
|
26
|
-
createdAt: '2026-03-25T01:00:00.000Z',
|
|
27
|
-
updatedAt: '2026-03-25T01:01:00.000Z',
|
|
28
|
-
tasks: [
|
|
29
|
-
{
|
|
30
|
-
id: 'T002',
|
|
31
|
-
title: 'Delegated task',
|
|
32
|
-
type: 'IMPL',
|
|
33
|
-
dependsOn: [],
|
|
34
|
-
touches: ['src/a.ts', 'src/b.ts'],
|
|
35
|
-
run: ['echo delegated'],
|
|
36
|
-
checks: [],
|
|
37
|
-
status: 'pending',
|
|
38
|
-
attempts: 0,
|
|
39
|
-
maxRetries: 1
|
|
40
|
-
}
|
|
41
|
-
],
|
|
42
|
-
metadata: {
|
|
43
|
-
source: 'default',
|
|
44
|
-
generatedBy: 'test',
|
|
45
|
-
planVersion: 2
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function createSharedWorkerManifest() {
|
|
51
|
-
return {
|
|
52
|
-
changeId: 'REQ-123',
|
|
53
|
-
goal: 'Run delegated worker command',
|
|
54
|
-
createdAt: '2026-03-25T01:00:00.000Z',
|
|
55
|
-
updatedAt: '2026-03-25T01:01:00.000Z',
|
|
56
|
-
tasks: [
|
|
57
|
-
{
|
|
58
|
-
id: 'T002',
|
|
59
|
-
title: 'Delegated task one',
|
|
60
|
-
type: 'IMPL',
|
|
61
|
-
dependsOn: [],
|
|
62
|
-
touches: ['src/a.ts', 'src/b.ts'],
|
|
63
|
-
run: ['echo delegated-one'],
|
|
64
|
-
checks: [],
|
|
65
|
-
status: 'pending',
|
|
66
|
-
attempts: 0,
|
|
67
|
-
maxRetries: 1
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
id: 'T003',
|
|
71
|
-
title: 'Delegated task two',
|
|
72
|
-
type: 'IMPL',
|
|
73
|
-
dependsOn: [],
|
|
74
|
-
touches: ['src/a.ts', 'src/b.ts'],
|
|
75
|
-
run: ['echo delegated-two'],
|
|
76
|
-
checks: [],
|
|
77
|
-
status: 'pending',
|
|
78
|
-
attempts: 0,
|
|
79
|
-
maxRetries: 1
|
|
80
|
-
}
|
|
81
|
-
],
|
|
82
|
-
metadata: {
|
|
83
|
-
source: 'default',
|
|
84
|
-
generatedBy: 'test',
|
|
85
|
-
planVersion: 2
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function setupRepoRoot(prefix) {
|
|
91
|
-
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
92
|
-
fs.writeFileSync(
|
|
93
|
-
path.join(repoRoot, 'package.json'),
|
|
94
|
-
JSON.stringify({ name: 'worker-run-test', version: '1.0.0' }, null, 2)
|
|
95
|
-
);
|
|
96
|
-
writeJson(getRuntimeStatePath(repoRoot, 'REQ-123'), {
|
|
97
|
-
changeId: 'REQ-123',
|
|
98
|
-
changeKey: 'REQ-123-run-delegated-worker-command',
|
|
99
|
-
slug: 'run-delegated-worker-command',
|
|
100
|
-
createdAt: '2026-03-25T01:00:00.000Z',
|
|
101
|
-
goal: 'Run delegated worker command',
|
|
102
|
-
status: 'planned',
|
|
103
|
-
initializedAt: '2026-03-25T01:00:00.000Z',
|
|
104
|
-
plannedAt: '2026-03-25T01:01:00.000Z',
|
|
105
|
-
updatedAt: '2026-03-25T01:01:00.000Z'
|
|
106
|
-
});
|
|
107
|
-
return repoRoot;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function writeManifest(repoRoot, manifest) {
|
|
111
|
-
writeJson(getTaskManifestPath(repoRoot, manifest.changeId), manifest);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
describe('runWorkerCommand', () => {
|
|
115
|
-
test('builds thin provider launch commands for codex and claude', () => {
|
|
116
|
-
const codexCommand = buildProviderCommand({
|
|
117
|
-
provider: 'codex',
|
|
118
|
-
providerPromptPath: '/tmp/provider.md',
|
|
119
|
-
providerLastMessagePath: '/tmp/last-message.md',
|
|
120
|
-
providerTranscriptPath: '/tmp/transcript.jsonl',
|
|
121
|
-
workspace: '/tmp/worktree',
|
|
122
|
-
providerArgs: '--model gpt-5'
|
|
123
|
-
});
|
|
124
|
-
const claudeCommand = buildProviderCommand({
|
|
125
|
-
provider: 'claude',
|
|
126
|
-
providerPromptPath: '/tmp/provider.md',
|
|
127
|
-
providerLastMessagePath: '/tmp/last-message.md',
|
|
128
|
-
providerTranscriptPath: '/tmp/transcript.jsonl',
|
|
129
|
-
workspace: '/tmp/worktree',
|
|
130
|
-
providerArgs: '--model sonnet --permission-mode bypassPermissions'
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
expect(codexCommand).toContain('codex exec');
|
|
134
|
-
expect(codexCommand).toContain('--dangerously-bypass-approvals-and-sandbox');
|
|
135
|
-
expect(codexCommand).toContain('/tmp/transcript.jsonl');
|
|
136
|
-
expect(claudeCommand).toContain('claude -p');
|
|
137
|
-
expect(claudeCommand).toContain('--dangerously-skip-permissions');
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test('runs local worker command and records only task status truth by default', async () => {
|
|
141
|
-
const repoRoot = setupRepoRoot('cc-devflow-worker-run-pass-');
|
|
142
|
-
const manifest = createManifest();
|
|
143
|
-
writeManifest(repoRoot, manifest);
|
|
144
|
-
const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
|
|
145
|
-
const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
|
|
146
|
-
|
|
147
|
-
const result = await runWorkerCommand({
|
|
148
|
-
repoRoot,
|
|
149
|
-
changeId: 'REQ-123',
|
|
150
|
-
workerId,
|
|
151
|
-
command: 'printf "worker-ok"'
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
const state = fs.readFileSync(result.sessionLogPath.replace('session.log', 'state.md'), 'utf8');
|
|
155
|
-
const journal = fs.readFileSync(result.sessionLogPath.replace('session.log', 'journal.md'), 'utf8');
|
|
156
|
-
const log = fs.readFileSync(result.sessionLogPath, 'utf8');
|
|
157
|
-
const bus = fs.readFileSync(getMessageBusPath(repoRoot, 'REQ-123'), 'utf8');
|
|
158
|
-
const assignment = fs.readFileSync(getWorkerAssignmentPath(repoRoot, 'REQ-123', workerId), 'utf8');
|
|
159
|
-
const nextManifest = JSON.parse(fs.readFileSync(getTaskManifestPath(repoRoot, 'REQ-123'), 'utf8'));
|
|
160
|
-
const runtimeState = JSON.parse(fs.readFileSync(getRuntimeStatePath(repoRoot, 'REQ-123'), 'utf8'));
|
|
161
|
-
|
|
162
|
-
expect(result.status).toBe('completed');
|
|
163
|
-
expect(state).toContain('Status: `completed`');
|
|
164
|
-
expect(journal).toContain('completed (exit 0)');
|
|
165
|
-
expect(log).toContain('worker-ok');
|
|
166
|
-
expect(bus).toContain(`${workerId} completed T002`);
|
|
167
|
-
expect(assignment).toContain('`T002` status=`completed`');
|
|
168
|
-
expect(fs.existsSync(getEventsPath(repoRoot, 'REQ-123', 'T002'))).toBe(false);
|
|
169
|
-
expect(fs.existsSync(path.join(repoRoot, 'devflow/changes/REQ-123-run-delegated-worker-command/execution/workers'))).toBe(false);
|
|
170
|
-
expect(nextManifest.tasks[0].status).toBe('passed');
|
|
171
|
-
expect(runtimeState.status).toBe('in_progress');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
test('builds provider prompt from assignment plus live manifest task brief', async () => {
|
|
175
|
-
const repoRoot = setupRepoRoot('cc-devflow-worker-run-provider-');
|
|
176
|
-
const manifest = createManifest();
|
|
177
|
-
writeManifest(repoRoot, manifest);
|
|
178
|
-
const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
|
|
179
|
-
const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
|
|
180
|
-
const handoff = await buildWorkerHandoff(repoRoot, 'REQ-123', workerId);
|
|
181
|
-
|
|
182
|
-
const providerPrompt = await buildProviderPrompt(repoRoot, handoff, 'T002');
|
|
183
|
-
|
|
184
|
-
expect(providerPrompt).toContain('## Worker Assignment');
|
|
185
|
-
expect(providerPrompt).toContain('## Selected Task Brief');
|
|
186
|
-
expect(providerPrompt).toContain('Task: `T002`');
|
|
187
|
-
expect(providerPrompt).toContain('Delegated task');
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
test('writes failure events and manifest error when local command exits non-zero', async () => {
|
|
191
|
-
const repoRoot = setupRepoRoot('cc-devflow-worker-run-fail-');
|
|
192
|
-
const manifest = createManifest();
|
|
193
|
-
writeManifest(repoRoot, manifest);
|
|
194
|
-
const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
|
|
195
|
-
const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
|
|
196
|
-
|
|
197
|
-
const result = await runWorkerCommand({
|
|
198
|
-
repoRoot,
|
|
199
|
-
changeId: 'REQ-123',
|
|
200
|
-
workerId,
|
|
201
|
-
command: 'echo boom >&2 && exit 7'
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
const state = fs.readFileSync(result.sessionLogPath.replace('session.log', 'state.md'), 'utf8');
|
|
205
|
-
const log = fs.readFileSync(result.sessionLogPath, 'utf8');
|
|
206
|
-
const assignment = fs.readFileSync(getWorkerAssignmentPath(repoRoot, 'REQ-123', workerId), 'utf8');
|
|
207
|
-
const failedManifest = JSON.parse(fs.readFileSync(getTaskManifestPath(repoRoot, 'REQ-123'), 'utf8'));
|
|
208
|
-
const events = fs.readFileSync(getEventsPath(repoRoot, 'REQ-123', 'T002'), 'utf8');
|
|
209
|
-
|
|
210
|
-
expect(result.status).toBe('failed');
|
|
211
|
-
expect(result.result.code).toBe(7);
|
|
212
|
-
expect(state).toContain('Status: `failed`');
|
|
213
|
-
expect(log).toContain('boom');
|
|
214
|
-
expect(assignment).toContain('`T002` status=`failed`');
|
|
215
|
-
expect(events).toContain('worker_run_failed');
|
|
216
|
-
expect(failedManifest.tasks[0].status).toBe('failed');
|
|
217
|
-
expect(failedManifest.tasks[0].lastError).toContain('boom');
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
test('updates only the selected task when a worker owns multiple assignments', async () => {
|
|
221
|
-
const repoRoot = setupRepoRoot('cc-devflow-worker-run-multi-');
|
|
222
|
-
const manifest = createSharedWorkerManifest();
|
|
223
|
-
writeManifest(repoRoot, manifest);
|
|
224
|
-
const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
|
|
225
|
-
const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
|
|
226
|
-
|
|
227
|
-
expect(delegation.assignments.find((item) => item.taskId === 'T003').workerId).toBe(workerId);
|
|
228
|
-
|
|
229
|
-
const result = await runWorkerCommand({
|
|
230
|
-
repoRoot,
|
|
231
|
-
changeId: 'REQ-123',
|
|
232
|
-
workerId,
|
|
233
|
-
taskId: 'T003',
|
|
234
|
-
command: 'printf "worker-t003"'
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
const assignment = fs.readFileSync(getWorkerAssignmentPath(repoRoot, 'REQ-123', workerId), 'utf8');
|
|
238
|
-
|
|
239
|
-
expect(result.taskId).toBe('T003');
|
|
240
|
-
expect(assignment).toContain('`T003` status=`completed`');
|
|
241
|
-
expect(assignment).not.toContain('`T002` status=`completed`');
|
|
242
|
-
const nextManifest = JSON.parse(fs.readFileSync(getTaskManifestPath(repoRoot, 'REQ-123'), 'utf8'));
|
|
243
|
-
expect(nextManifest.tasks.find((task) => task.id === 'T002').status).toBe('pending');
|
|
244
|
-
expect(nextManifest.tasks.find((task) => task.id === 'T003').status).toBe('passed');
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
test('blocks stale worker assignments when manifest planVersion has moved on', async () => {
|
|
248
|
-
const repoRoot = setupRepoRoot('cc-devflow-worker-run-stale-plan-');
|
|
249
|
-
const manifest = createManifest();
|
|
250
|
-
writeManifest(repoRoot, manifest);
|
|
251
|
-
const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
|
|
252
|
-
const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
|
|
253
|
-
|
|
254
|
-
writeManifest(repoRoot, {
|
|
255
|
-
...manifest,
|
|
256
|
-
metadata: {
|
|
257
|
-
...manifest.metadata,
|
|
258
|
-
planVersion: 3
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
await expect(runWorkerCommand({
|
|
263
|
-
repoRoot,
|
|
264
|
-
changeId: 'REQ-123',
|
|
265
|
-
workerId,
|
|
266
|
-
command: 'printf "should-not-run" > blocked.txt'
|
|
267
|
-
})).rejects.toMatchObject({
|
|
268
|
-
name: 'StalePlanVersionError',
|
|
269
|
-
rescueAction: 'rerun delegation sync for current planVersion before worker-run'
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
expect(fs.existsSync(path.join(repoRoot, 'blocked.txt'))).toBe(false);
|
|
273
|
-
expect(fs.existsSync(getEventsPath(repoRoot, 'REQ-123', 'T002'))).toBe(false);
|
|
274
|
-
});
|
|
275
|
-
});
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const { syncDelegationRuntime } = require('../delegation');
|
|
6
|
-
const { runWorkerSession } = require('../operations/worker');
|
|
7
|
-
|
|
8
|
-
describe('runWorkerSession', () => {
|
|
9
|
-
test('returns stable handoff bundle for a delegated worker', async () => {
|
|
10
|
-
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-worker-session-'));
|
|
11
|
-
fs.writeFileSync(path.join(repoRoot, 'package.json'), JSON.stringify({ name: 'worker-session', version: '1.0.0' }, null, 2));
|
|
12
|
-
|
|
13
|
-
const manifest = {
|
|
14
|
-
changeId: 'REQ-123',
|
|
15
|
-
goal: 'Prepare worker session',
|
|
16
|
-
createdAt: '2026-03-25T01:00:00.000Z',
|
|
17
|
-
updatedAt: '2026-03-25T01:01:00.000Z',
|
|
18
|
-
tasks: [
|
|
19
|
-
{
|
|
20
|
-
id: 'T002',
|
|
21
|
-
title: 'Multi file delegated task',
|
|
22
|
-
type: 'IMPL',
|
|
23
|
-
dependsOn: [],
|
|
24
|
-
touches: ['src/a.ts', 'src/b.ts'],
|
|
25
|
-
run: ['echo delegated'],
|
|
26
|
-
checks: [],
|
|
27
|
-
status: 'pending',
|
|
28
|
-
attempts: 0,
|
|
29
|
-
maxRetries: 1
|
|
30
|
-
}
|
|
31
|
-
],
|
|
32
|
-
metadata: {
|
|
33
|
-
source: 'default',
|
|
34
|
-
generatedBy: 'test',
|
|
35
|
-
planVersion: 2
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
|
|
40
|
-
const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
|
|
41
|
-
const handoff = await runWorkerSession({
|
|
42
|
-
repoRoot,
|
|
43
|
-
changeId: 'REQ-123',
|
|
44
|
-
workerId
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const journal = fs.readFileSync(handoff.journalPath, 'utf8');
|
|
48
|
-
const state = fs.readFileSync(handoff.statePath, 'utf8');
|
|
49
|
-
|
|
50
|
-
expect(handoff.workerId).toBe(workerId);
|
|
51
|
-
expect(handoff.assignmentPath).toContain('assignment.md');
|
|
52
|
-
expect(handoff.taskIds).toEqual(['T002']);
|
|
53
|
-
expect(journal).toContain('handoff prepared');
|
|
54
|
-
expect(state).toContain('Status: `handoff_ready`');
|
|
55
|
-
});
|
|
56
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* [INPUT]: 依赖 getWorkflowContext 查询 seam、仓库内真实 legacy workflow artifacts。
|
|
3
|
-
* [OUTPUT]: 验证 legacy design.md fallback 在 compact context 中仍是一等合同入口。
|
|
4
|
-
* [POS]: REQ-003-minimize-workflow-artifacts T010 的 Red/Green 证据。
|
|
5
|
-
* [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const path = require('path');
|
|
9
|
-
|
|
10
|
-
const { getWorkflowContext } = require('../query');
|
|
11
|
-
|
|
12
|
-
const repoRoot = path.resolve(__dirname, '../../..');
|
|
13
|
-
|
|
14
|
-
describe('workflow-context legacy fallback refs', () => {
|
|
15
|
-
test.each([
|
|
16
|
-
['REQ-002', 'REQ-002-unified-roadmap-truth']
|
|
17
|
-
])('%s keeps design.md as the first fallback contract ref', async (changeId, changeKey) => {
|
|
18
|
-
const context = await getWorkflowContext(repoRoot, changeId, { changeKey });
|
|
19
|
-
const designRef = `devflow/changes/${changeKey}/planning/design.md#approved-direction`;
|
|
20
|
-
|
|
21
|
-
expect(context.legacyFallback).toBe(true);
|
|
22
|
-
expect(context.source.contract.path).toBe(`devflow/changes/${changeKey}/planning/design.md`);
|
|
23
|
-
expect(context.progressiveDisclosure.defaultOpen[0]).toEqual(expect.objectContaining({
|
|
24
|
-
ref: designRef,
|
|
25
|
-
reason: 'primary task contract',
|
|
26
|
-
exists: true
|
|
27
|
-
}));
|
|
28
|
-
expect(context.progressiveDisclosure.defaultOpen.every((entry) => entry.exists === true))
|
|
29
|
-
.toBe(true);
|
|
30
|
-
});
|
|
31
|
-
});
|