cc-devflow 4.5.8 → 4.5.10
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 +33 -0
- package/.claude/skills/cc-act/PLAYBOOK.md +9 -4
- package/.claude/skills/cc-act/SKILL.md +73 -12
- package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_INDEX_TEMPLATE.md +30 -0
- package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_PRINCIPLES_TEMPLATE.md +29 -0
- package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_TEMPLATE.md +103 -0
- package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +61 -5
- package/.claude/skills/cc-act/references/closure-contract.md +4 -1
- package/.claude/skills/cc-act/references/git-commit-guidelines.md +342 -37
- package/.claude/skills/cc-act/scripts/cc-act-common.sh +29 -1
- package/.claude/skills/cc-act/scripts/render-pr-brief.sh +164 -0
- package/.claude/skills/cc-act/scripts/sync-act-docs.sh +1 -1
- package/.claude/skills/cc-check/CHANGELOG.md +17 -0
- package/.claude/skills/cc-check/PLAYBOOK.md +1 -0
- package/.claude/skills/cc-check/SKILL.md +9 -5
- package/.claude/skills/cc-check/references/review-contract.md +7 -0
- package/.claude/skills/cc-check/scripts/render-report-card.js +6 -1
- package/.claude/skills/cc-dev/CHANGELOG.md +5 -0
- package/.claude/skills/cc-dev/SKILL.md +26 -1
- package/.claude/skills/cc-do/CHANGELOG.md +23 -0
- package/.claude/skills/cc-do/PLAYBOOK.md +7 -7
- package/.claude/skills/cc-do/SKILL.md +49 -45
- package/.claude/skills/cc-do/references/execution-recovery.md +18 -13
- package/.claude/skills/cc-do/scripts/build-task-context.sh +13 -22
- package/.claude/skills/cc-do/scripts/mark-task-complete.sh +0 -6
- package/.claude/skills/cc-do/scripts/record-review-decision.sh +4 -5
- package/.claude/skills/cc-do/scripts/recover-workflow.sh +9 -11
- package/.claude/skills/cc-do/scripts/verify-task-gates.sh +12 -10
- package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +7 -29
- package/.claude/skills/cc-investigate/CHANGELOG.md +34 -0
- package/.claude/skills/cc-investigate/PLAYBOOK.md +21 -5
- package/.claude/skills/cc-investigate/SKILL.md +97 -40
- package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +66 -4
- package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +30 -59
- package/.claude/skills/cc-investigate/assets/{ANALYSIS_TEMPLATE.md → legacy/ANALYSIS_TEMPLATE.md} +48 -0
- package/.claude/skills/cc-investigate/references/investigation-contract.md +16 -2
- package/.claude/skills/cc-investigate/scripts/bootstrap-analysis.sh +1 -1
- package/.claude/skills/cc-next/CHANGELOG.md +6 -0
- package/.claude/skills/cc-next/PLAYBOOK.md +26 -4
- package/.claude/skills/cc-next/SKILL.md +39 -4
- package/.claude/skills/cc-plan/CHANGELOG.md +38 -0
- package/.claude/skills/cc-plan/PLAYBOOK.md +60 -53
- package/.claude/skills/cc-plan/SKILL.md +164 -87
- package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +101 -9
- package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +58 -229
- package/.claude/skills/cc-plan/assets/{DESIGN_TEMPLATE.md → legacy/DESIGN_TEMPLATE.md} +68 -0
- package/.claude/skills/cc-plan/assets/{TINY_DESIGN_TEMPLATE.md → legacy/TINY_DESIGN_TEMPLATE.md} +47 -1
- package/.claude/skills/cc-plan/references/planning-contract.md +48 -33
- package/.claude/skills/cc-review/CHANGELOG.md +6 -0
- package/.claude/skills/cc-review/PLAYBOOK.md +9 -11
- package/.claude/skills/cc-review/SKILL.md +37 -61
- package/.claude/skills/cc-review/references/e2e-and-plugin-verification.md +1 -1
- package/.claude/skills/cc-review/references/implementation-review-branch.md +5 -5
- package/.claude/skills/cc-review/references/plan-review-branch.md +1 -1
- package/.claude/skills/cc-review/references/review-methods.md +4 -4
- package/.claude/skills/cc-review/scripts/collect-review-context.sh +14 -7
- package/.claude/skills/cc-roadmap/CHANGELOG.md +6 -0
- package/.claude/skills/cc-roadmap/PLAYBOOK.md +30 -0
- package/.claude/skills/cc-roadmap/SKILL.md +45 -8
- package/.claude/skills/cc-roadmap/assets/BACKLOG_TEMPLATE.md +8 -0
- package/.claude/skills/cc-roadmap/assets/ROADMAP_TEMPLATE.md +22 -0
- package/.claude/skills/cc-roadmap/assets/TRACKING_TEMPLATE.json +32 -1
- package/.claude/skills/cc-roadmap/references/roadmap-dialogue.md +14 -14
- package/CHANGELOG.md +28 -0
- package/CONTRIBUTING.md +40 -4
- package/CONTRIBUTING.zh-CN.md +40 -4
- package/README.md +57 -43
- package/README.zh-CN.md +57 -43
- package/bin/cc-devflow-cli.js +293 -36
- package/docs/examples/START-HERE.md +5 -4
- package/docs/examples/example-bindings.json +10 -10
- package/docs/examples/full-design-blocked/BACKLOG.md +1 -1
- package/docs/examples/full-design-blocked/README.md +2 -2
- package/docs/examples/full-design-blocked/ROADMAP.md +1 -1
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +2 -1
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +29 -312
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/tasks.md +11 -8
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +4 -4
- package/docs/examples/full-design-blocked/roadmap.json +1 -1
- package/docs/examples/local-handoff/BACKLOG.md +1 -1
- package/docs/examples/local-handoff/README.md +2 -2
- package/docs/examples/local-handoff/ROADMAP.md +1 -1
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +2 -1
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +27 -210
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/tasks.md +9 -6
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +1 -1
- package/docs/examples/local-handoff/roadmap.json +1 -1
- package/docs/examples/pdca-loop/BACKLOG.md +1 -1
- package/docs/examples/pdca-loop/README.md +2 -2
- package/docs/examples/pdca-loop/ROADMAP.md +1 -1
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +65 -1
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +2 -1
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +26 -228
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/tasks.md +9 -6
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +1 -1
- package/docs/examples/pdca-loop/roadmap.json +1 -1
- package/docs/examples/scripts/check-example-bindings.sh +11 -5
- package/docs/get-shit-done-strategy-audit.md +22 -22
- package/docs/guides/artifact-contract.md +44 -0
- package/docs/guides/getting-started.md +10 -8
- package/docs/guides/getting-started.zh-CN.md +10 -8
- package/docs/guides/minimize-artifacts.md +123 -0
- package/docs/guides/project-postmortem.md +78 -0
- package/lib/compiler/__tests__/skills-registry.test.js +2 -2
- package/lib/skill-runtime/CLAUDE.md +1 -1
- package/lib/skill-runtime/__tests__/autopilot.test.js +42 -6
- package/lib/skill-runtime/__tests__/benchmark-artifacts.test.js +165 -0
- package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +2 -2
- package/lib/skill-runtime/__tests__/dispatch.test.js +8 -38
- package/lib/skill-runtime/__tests__/intent.test.js +4 -20
- package/lib/skill-runtime/__tests__/lifecycle.test.js +1 -1
- package/lib/skill-runtime/__tests__/paths.test.js +7 -1
- package/lib/skill-runtime/__tests__/planner.tdd.test.js +63 -2
- package/lib/skill-runtime/__tests__/prepare-pr.test.js +3 -16
- package/lib/skill-runtime/__tests__/query.test.js +388 -7
- package/lib/skill-runtime/__tests__/review-check-integration.test.js +148 -0
- package/lib/skill-runtime/__tests__/review-records.test.js +619 -0
- package/lib/skill-runtime/__tests__/runtime.integration.test.js +64 -23
- package/lib/skill-runtime/__tests__/schemas.test.js +76 -2
- package/lib/skill-runtime/__tests__/task-contract-migrate.test.js +137 -0
- package/lib/skill-runtime/__tests__/task-contract.test.js +783 -0
- package/lib/skill-runtime/__tests__/verify-artifacts.test.js +203 -0
- package/lib/skill-runtime/__tests__/worker-run.test.js +4 -11
- package/lib/skill-runtime/__tests__/workflow-context-legacy-fallback.test.js +31 -0
- package/lib/skill-runtime/__tests__/workflow-context.test.js +98 -0
- package/lib/skill-runtime/artifacts.js +0 -5
- package/lib/skill-runtime/context-index.js +545 -0
- package/lib/skill-runtime/intent.js +9 -33
- package/lib/skill-runtime/lifecycle.js +1 -1
- package/lib/skill-runtime/operations/CLAUDE.md +2 -2
- package/lib/skill-runtime/operations/dispatch.js +4 -42
- package/lib/skill-runtime/operations/init.js +2 -6
- package/lib/skill-runtime/operations/janitor.js +2 -18
- package/lib/skill-runtime/operations/resume.js +21 -38
- package/lib/skill-runtime/operations/review-records.js +265 -0
- package/lib/skill-runtime/operations/snapshot.js +1 -1
- package/lib/skill-runtime/operations/task-contract.js +524 -0
- package/lib/skill-runtime/operations/worker-run.js +2 -30
- package/lib/skill-runtime/paths.js +4 -4
- package/lib/skill-runtime/planner.js +25 -13
- package/lib/skill-runtime/query-registry.js +2 -2
- package/lib/skill-runtime/query.js +16 -3
- package/lib/skill-runtime/review-records.js +123 -0
- package/lib/skill-runtime/review.js +246 -11
- package/lib/skill-runtime/schemas.js +179 -15
- package/lib/skill-runtime/store.js +0 -10
- package/lib/skill-runtime/task-contract.js +187 -0
- package/lib/skill-runtime/workflow-context.js +748 -0
- package/package.json +7 -4
|
@@ -15,8 +15,7 @@ const {
|
|
|
15
15
|
const {
|
|
16
16
|
getRuntimeStatePath,
|
|
17
17
|
getTaskManifestPath,
|
|
18
|
-
getReportCardPath
|
|
19
|
-
getCheckpointPath
|
|
18
|
+
getReportCardPath
|
|
20
19
|
} = require('../store');
|
|
21
20
|
|
|
22
21
|
function writeJson(filePath, value) {
|
|
@@ -86,21 +85,6 @@ describe('intent handoff bridge', () => {
|
|
|
86
85
|
}
|
|
87
86
|
);
|
|
88
87
|
|
|
89
|
-
writeJson(
|
|
90
|
-
getCheckpointPath(repoRoot, 'REQ-123', 'T001'),
|
|
91
|
-
{
|
|
92
|
-
changeId: 'REQ-123',
|
|
93
|
-
taskId: 'T001',
|
|
94
|
-
sessionId: 'T001-session',
|
|
95
|
-
planVersion: 1,
|
|
96
|
-
status: 'passed',
|
|
97
|
-
summary: 'Task passed after 1 attempt',
|
|
98
|
-
error: '',
|
|
99
|
-
outputExcerpt: 'worker-ok',
|
|
100
|
-
timestamp: '2026-03-25T01:11:00.000Z',
|
|
101
|
-
attempt: 1
|
|
102
|
-
}
|
|
103
|
-
);
|
|
104
88
|
});
|
|
105
89
|
|
|
106
90
|
test('syncIntentMemory removes legacy projection files instead of writing them', async () => {
|
|
@@ -152,7 +136,7 @@ describe('intent handoff bridge', () => {
|
|
|
152
136
|
}
|
|
153
137
|
});
|
|
154
138
|
|
|
155
|
-
test('writes pr brief from manifest
|
|
139
|
+
test('writes pr brief from manifest task state and report-card only', async () => {
|
|
156
140
|
const prBriefPath = getIntentPrBriefPath(repoRoot, 'REQ-123');
|
|
157
141
|
const manifestPath = getTaskManifestPath(repoRoot, 'REQ-123');
|
|
158
142
|
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
@@ -208,8 +192,8 @@ describe('intent handoff bridge', () => {
|
|
|
208
192
|
|
|
209
193
|
expect(prBrief).toContain('PR Brief: REQ-123');
|
|
210
194
|
expect(prBrief).toContain('Suggested Title: feat(req-123): Deliver autopilot memory bridge');
|
|
211
|
-
expect(prBrief).toContain('
|
|
212
|
-
expect(prBrief).toContain('
|
|
195
|
+
expect(prBrief).toContain('planning/tasks.md');
|
|
196
|
+
expect(prBrief).toContain('planning/task-manifest.json');
|
|
213
197
|
expect(prBrief).toContain('存在 1 个 skipped 任务,需要确认是否可接受:T002');
|
|
214
198
|
expect(prBrief).not.toContain('result.md');
|
|
215
199
|
for (const filePath of getIntentHandoffArtifactPaths(repoRoot, 'REQ-123')) {
|
|
@@ -104,7 +104,7 @@ describe('lifecycle helpers', () => {
|
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
expect(deriveLifecycleNextAction({ state: approvedState, manifest, report: null })).toBe(
|
|
107
|
-
'优先修复失败任务 T002
|
|
107
|
+
'优先修复失败任务 T002,然后从 task-manifest 的最近稳定状态恢复。'
|
|
108
108
|
);
|
|
109
109
|
expect(
|
|
110
110
|
deriveLifecycleNextAction({
|
|
@@ -4,6 +4,7 @@ const path = require('path');
|
|
|
4
4
|
|
|
5
5
|
const {
|
|
6
6
|
buildChangeKey,
|
|
7
|
+
getChangeKeyPrefix,
|
|
7
8
|
getChangePaths,
|
|
8
9
|
getChangeSlug,
|
|
9
10
|
nextChangeKey
|
|
@@ -17,11 +18,16 @@ describe('change directory naming', () => {
|
|
|
17
18
|
.toBe('FIX-123-修复-目录-命名');
|
|
18
19
|
});
|
|
19
20
|
|
|
21
|
+
test('derives the numeric prefix from full change keys', () => {
|
|
22
|
+
expect(getChangeKeyPrefix('REQ-123-plan-folder-contract')).toBe('REQ-123');
|
|
23
|
+
expect(getChangeKeyPrefix('FIX-456-crash-on-start')).toBe('FIX-456');
|
|
24
|
+
});
|
|
25
|
+
|
|
20
26
|
test('rejects change ids and explicit keys outside the canonical prefix contract', () => {
|
|
21
27
|
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-paths-'));
|
|
22
28
|
|
|
23
29
|
expect(() => buildChangeKey('BUG-123', { goal: 'legacy bug id' }))
|
|
24
|
-
.toThrow(/REQ-<number
|
|
30
|
+
.toThrow(/REQ-<number>\[-description\] or FIX-<number>\[-description\]/);
|
|
25
31
|
expect(() => getChangePaths(repoRoot, 'REQ-123', { changeKey: 'req-123-lowercase' }))
|
|
26
32
|
.toThrow(/Expected REQ-123-<description>/);
|
|
27
33
|
|
|
@@ -107,6 +107,67 @@ describe('TDD Order Validation', () => {
|
|
|
107
107
|
});
|
|
108
108
|
|
|
109
109
|
describe('Manifest execution state', () => {
|
|
110
|
+
test('createTaskManifest reads tasks.md when legacy design.md is absent', async () => {
|
|
111
|
+
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-planner-new-contract-'));
|
|
112
|
+
const changeId = 'REQ-322';
|
|
113
|
+
const changeKey = 'REQ-322-new-contract';
|
|
114
|
+
const tasksPath = path.join(repoRoot, 'devflow', 'changes', changeKey, 'planning', 'tasks.md');
|
|
115
|
+
fs.mkdirSync(path.dirname(tasksPath), { recursive: true });
|
|
116
|
+
fs.writeFileSync(
|
|
117
|
+
tasksPath,
|
|
118
|
+
[
|
|
119
|
+
'## Phase 1: Build',
|
|
120
|
+
'',
|
|
121
|
+
'- [ ] T001 [TEST] Counter behavior `src/counter.test.ts`',
|
|
122
|
+
'- [ ] T002 [IMPL] Counter behavior (dependsOn:T001) `src/counter.ts`'
|
|
123
|
+
].join('\n')
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const manifest = await createTaskManifest({
|
|
127
|
+
repoRoot,
|
|
128
|
+
changeId,
|
|
129
|
+
changeKey,
|
|
130
|
+
goal: 'Exercise new contract readFiles',
|
|
131
|
+
overwrite: true
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(manifest.tasks[0].context.readFiles).toEqual(['tasks.md', 'src/counter.test.ts']);
|
|
135
|
+
expect(manifest.tasks[1].context.readFiles).toEqual(['tasks.md']);
|
|
136
|
+
|
|
137
|
+
fs.rmSync(repoRoot, { recursive: true, force: true });
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test('createTaskManifest keeps design.md when legacy design.md exists', async () => {
|
|
141
|
+
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-planner-legacy-contract-'));
|
|
142
|
+
const changeId = 'REQ-323';
|
|
143
|
+
const changeKey = 'REQ-323-legacy-contract';
|
|
144
|
+
const planningDir = path.join(repoRoot, 'devflow', 'changes', changeKey, 'planning');
|
|
145
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
146
|
+
fs.writeFileSync(path.join(planningDir, 'design.md'), '# DESIGN\n');
|
|
147
|
+
fs.writeFileSync(
|
|
148
|
+
path.join(planningDir, 'tasks.md'),
|
|
149
|
+
[
|
|
150
|
+
'## Phase 1: Build',
|
|
151
|
+
'',
|
|
152
|
+
'- [ ] T001 [TEST] Counter behavior `src/counter.test.ts`',
|
|
153
|
+
'- [ ] T002 [IMPL] Counter behavior (dependsOn:T001) `src/counter.ts`'
|
|
154
|
+
].join('\n')
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const manifest = await createTaskManifest({
|
|
158
|
+
repoRoot,
|
|
159
|
+
changeId,
|
|
160
|
+
changeKey,
|
|
161
|
+
goal: 'Exercise legacy contract readFiles',
|
|
162
|
+
overwrite: true
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(manifest.tasks[0].context.readFiles).toEqual(['design.md', 'tasks.md', 'src/counter.test.ts']);
|
|
166
|
+
expect(manifest.tasks[1].context.readFiles).toEqual(['design.md']);
|
|
167
|
+
|
|
168
|
+
fs.rmSync(repoRoot, { recursive: true, force: true });
|
|
169
|
+
});
|
|
170
|
+
|
|
110
171
|
test('should derive active phase and current task from ready tasks', () => {
|
|
111
172
|
const state = deriveManifestExecutionState([
|
|
112
173
|
{ id: 'T001', phase: 1, status: 'passed', dependsOn: [] },
|
|
@@ -120,7 +181,7 @@ describe('TDD Order Validation', () => {
|
|
|
120
181
|
});
|
|
121
182
|
});
|
|
122
183
|
|
|
123
|
-
test('should write currentTaskId
|
|
184
|
+
test('should write currentTaskId while deriving activePhase from the task graph', async () => {
|
|
124
185
|
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-planner-'));
|
|
125
186
|
const changeId = 'REQ-321';
|
|
126
187
|
const tasksPath = path.join(repoRoot, 'devflow', 'changes', `${changeId}-change`, 'planning', 'tasks.md');
|
|
@@ -146,7 +207,7 @@ describe('TDD Order Validation', () => {
|
|
|
146
207
|
overwrite: true
|
|
147
208
|
});
|
|
148
209
|
|
|
149
|
-
expect(manifest.activePhase).
|
|
210
|
+
expect(manifest.activePhase).toBeUndefined();
|
|
150
211
|
expect(manifest.currentTaskId).toBe('T002');
|
|
151
212
|
expect(manifest.tasks[1].reviews).toEqual({ spec: 'pending', code: 'pending' });
|
|
152
213
|
});
|
|
@@ -6,8 +6,7 @@ const { runPreparePr } = require('../operations/prepare-pr');
|
|
|
6
6
|
const {
|
|
7
7
|
getRuntimeStatePath,
|
|
8
8
|
getTaskManifestPath,
|
|
9
|
-
getReportCardPath
|
|
10
|
-
getCheckpointPath
|
|
9
|
+
getReportCardPath
|
|
11
10
|
} = require('../store');
|
|
12
11
|
const {
|
|
13
12
|
getIntentPrBriefPath,
|
|
@@ -94,19 +93,6 @@ describe('runPreparePr', () => {
|
|
|
94
93
|
timestamp: '2026-03-25T01:11:00.000Z'
|
|
95
94
|
});
|
|
96
95
|
|
|
97
|
-
writeJson(getCheckpointPath(repoRoot, 'REQ-123', 'T001'), {
|
|
98
|
-
changeId: 'REQ-123',
|
|
99
|
-
taskId: 'T001',
|
|
100
|
-
sessionId: 'task-session',
|
|
101
|
-
planVersion: 1,
|
|
102
|
-
status: 'passed',
|
|
103
|
-
summary: 'Task passed after 1 attempt',
|
|
104
|
-
error: '',
|
|
105
|
-
outputExcerpt: 'ok',
|
|
106
|
-
timestamp: '2026-03-25T01:09:00.000Z',
|
|
107
|
-
attempt: 1
|
|
108
|
-
});
|
|
109
|
-
|
|
110
96
|
writeJson(getRuntimeStatePath(repoRoot, 'REQ-123'), {
|
|
111
97
|
...JSON.parse(fs.readFileSync(getRuntimeStatePath(repoRoot, 'REQ-123'), 'utf8')),
|
|
112
98
|
approval: {
|
|
@@ -130,7 +116,8 @@ describe('runPreparePr', () => {
|
|
|
130
116
|
expect(result.status).toBe('prepared');
|
|
131
117
|
expect(result.suggestedTitle).toBe('feat(req-123): Prepare a PR-ready brief');
|
|
132
118
|
expect(prBrief).toContain('PR Brief: REQ-123');
|
|
133
|
-
expect(prBrief).toContain('
|
|
119
|
+
expect(prBrief).toContain('planning/task-manifest.json');
|
|
120
|
+
expect(prBrief).not.toContain('execution/tasks/T001/checkpoint.json');
|
|
134
121
|
expect(prBrief).not.toContain('result.md');
|
|
135
122
|
for (const filePath of getIntentHandoffArtifactPaths(repoRoot, 'REQ-123')) {
|
|
136
123
|
expect(fs.existsSync(filePath)).toBe(filePath === prBriefPath);
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
getFullState,
|
|
7
7
|
getNextTask,
|
|
8
8
|
getProgress,
|
|
9
|
+
getWorkflowContext,
|
|
9
10
|
listQueryIds,
|
|
10
11
|
runQuery
|
|
11
12
|
} = require('../query');
|
|
@@ -288,6 +289,386 @@ describe('query helpers', () => {
|
|
|
288
289
|
expect(next.id).toBe('T002');
|
|
289
290
|
});
|
|
290
291
|
|
|
292
|
+
test('returns compact workflow context for the current ready task', async () => {
|
|
293
|
+
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-context-'));
|
|
294
|
+
const manifestPath = getTaskManifestPath(repoRoot, 'REQ-126');
|
|
295
|
+
const planningDir = path.dirname(manifestPath);
|
|
296
|
+
const changeDir = path.dirname(planningDir);
|
|
297
|
+
|
|
298
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
299
|
+
fs.writeFileSync(path.join(planningDir, 'design.md'), '# Design\n');
|
|
300
|
+
fs.writeFileSync(path.join(planningDir, 'tasks.md'), '# Tasks\n');
|
|
301
|
+
writeJson(path.join(changeDir, 'change-meta.json'), {
|
|
302
|
+
spec: {
|
|
303
|
+
primaryCapability: 'cap-compact-context',
|
|
304
|
+
syncStatus: 'planned'
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
writeJson(manifestPath, {
|
|
308
|
+
changeId: 'REQ-126',
|
|
309
|
+
goal: 'Expose compact workflow context',
|
|
310
|
+
createdAt: '2026-05-12T01:00:00.000Z',
|
|
311
|
+
updatedAt: '2026-05-12T01:05:00.000Z',
|
|
312
|
+
currentTaskId: 'T002',
|
|
313
|
+
planningMeta: {
|
|
314
|
+
reqPlanSkillVersion: '3.8.8'
|
|
315
|
+
},
|
|
316
|
+
tasks: [
|
|
317
|
+
{
|
|
318
|
+
id: 'T001',
|
|
319
|
+
title: 'Completed test task',
|
|
320
|
+
type: 'TEST',
|
|
321
|
+
phase: 1,
|
|
322
|
+
dependsOn: [],
|
|
323
|
+
touches: ['src/feature.test.ts'],
|
|
324
|
+
files: ['src/feature.test.ts'],
|
|
325
|
+
run: ['npm test -- src/feature.test.ts'],
|
|
326
|
+
checks: [],
|
|
327
|
+
acceptance: [],
|
|
328
|
+
verification: ['npm test -- src/feature.test.ts'],
|
|
329
|
+
evidence: ['red output'],
|
|
330
|
+
context: { readFiles: ['planning/design.md'], commands: ['npm test -- src/feature.test.ts'], notes: [] },
|
|
331
|
+
status: 'passed',
|
|
332
|
+
attempts: 1,
|
|
333
|
+
maxRetries: 1
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
id: 'T002',
|
|
337
|
+
title: 'Implement compact context',
|
|
338
|
+
type: 'IMPL',
|
|
339
|
+
phase: 1,
|
|
340
|
+
dependsOn: ['T001'],
|
|
341
|
+
touches: ['lib/skill-runtime/query.js'],
|
|
342
|
+
files: ['lib/skill-runtime/query.js'],
|
|
343
|
+
run: ['npm test -- lib/skill-runtime/__tests__/query.test.js'],
|
|
344
|
+
checks: [],
|
|
345
|
+
acceptance: [],
|
|
346
|
+
verification: ['npm test -- lib/skill-runtime/__tests__/query.test.js'],
|
|
347
|
+
evidence: ['green output'],
|
|
348
|
+
context: {
|
|
349
|
+
readFiles: ['design.md', 'tasks.md', 'change-meta.json', 'lib/skill-runtime/query.js'],
|
|
350
|
+
commands: ['npm test -- lib/skill-runtime/__tests__/query.test.js'],
|
|
351
|
+
notes: ['Read the context index before opening deep docs']
|
|
352
|
+
},
|
|
353
|
+
status: 'pending',
|
|
354
|
+
attempts: 0,
|
|
355
|
+
maxRetries: 1
|
|
356
|
+
}
|
|
357
|
+
],
|
|
358
|
+
metadata: {
|
|
359
|
+
source: 'test',
|
|
360
|
+
generatedBy: 'test',
|
|
361
|
+
planVersion: 2
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const context = await getWorkflowContext(repoRoot, 'REQ-126');
|
|
366
|
+
|
|
367
|
+
expect(context.nextAction).toMatchObject({
|
|
368
|
+
skill: 'cc-do',
|
|
369
|
+
action: 'execute-current-task',
|
|
370
|
+
taskId: 'T002'
|
|
371
|
+
});
|
|
372
|
+
expect(context.currentTask).toMatchObject({
|
|
373
|
+
id: 'T002',
|
|
374
|
+
context: {
|
|
375
|
+
readFiles: expect.arrayContaining(['design.md', 'tasks.md', 'change-meta.json', 'lib/skill-runtime/query.js'])
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
expect(context.progressiveDisclosure).toMatchObject({
|
|
379
|
+
mode: 'compact-first',
|
|
380
|
+
rule: expect.stringContaining('context index'),
|
|
381
|
+
packetOnly: {
|
|
382
|
+
contractDigest: expect.any(String),
|
|
383
|
+
manifestDigest: expect.any(String),
|
|
384
|
+
currentTaskDigest: expect.any(String),
|
|
385
|
+
evidenceDigest: expect.any(String),
|
|
386
|
+
mustNotForgetDigest: expect.any(String)
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
expect(context.source.manifest).toMatchObject({
|
|
390
|
+
path: expect.stringContaining('planning/task-manifest.json'),
|
|
391
|
+
hash: expect.stringMatching(/^sha256:/)
|
|
392
|
+
});
|
|
393
|
+
expect(context.progressiveDisclosure.sourceHashes).toEqual(expect.objectContaining({
|
|
394
|
+
[context.source.manifest.path]: expect.stringMatching(/^sha256:/)
|
|
395
|
+
}));
|
|
396
|
+
expect(context.progressiveDisclosure.mustNotForget).toMatchObject({
|
|
397
|
+
goal: {
|
|
398
|
+
value: 'Expose compact workflow context',
|
|
399
|
+
source: {
|
|
400
|
+
ref: expect.stringContaining('planning/task-manifest.json#/goal'),
|
|
401
|
+
hash: expect.stringMatching(/^sha256:/)
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
nonNegotiables: expect.arrayContaining([
|
|
405
|
+
expect.objectContaining({
|
|
406
|
+
value: expect.stringContaining('read-only'),
|
|
407
|
+
source: expect.objectContaining({ ref: expect.any(String) })
|
|
408
|
+
})
|
|
409
|
+
]),
|
|
410
|
+
acceptanceGates: expect.arrayContaining([
|
|
411
|
+
expect.objectContaining({
|
|
412
|
+
value: 'npm test -- lib/skill-runtime/__tests__/query.test.js',
|
|
413
|
+
source: expect.objectContaining({ ref: expect.stringContaining('planning/task-manifest.json#/tasks/T002') })
|
|
414
|
+
})
|
|
415
|
+
])
|
|
416
|
+
});
|
|
417
|
+
expect(context.progressiveDisclosure.defaultOpen).toEqual(expect.arrayContaining([
|
|
418
|
+
expect.objectContaining({
|
|
419
|
+
ref: expect.stringContaining('planning/design.md#design'),
|
|
420
|
+
reason: 'primary task contract',
|
|
421
|
+
exists: true,
|
|
422
|
+
sourceHash: expect.stringMatching(/^sha256:/)
|
|
423
|
+
}),
|
|
424
|
+
expect.objectContaining({
|
|
425
|
+
ref: expect.stringContaining('planning/task-manifest.json#/tasks/T002'),
|
|
426
|
+
reason: 'current task source of truth',
|
|
427
|
+
sourceHash: expect.stringMatching(/^sha256:/)
|
|
428
|
+
}),
|
|
429
|
+
expect.objectContaining({
|
|
430
|
+
ref: expect.stringContaining('change-meta.json#/spec')
|
|
431
|
+
})
|
|
432
|
+
]));
|
|
433
|
+
expect(context.progressiveDisclosure.defaultOpen.every((entry) => entry.exists === true)).toBe(true);
|
|
434
|
+
expect(context.progressiveDisclosure.defaultRead).toBeUndefined();
|
|
435
|
+
expect(context.progressiveDisclosure.deepOpen).toEqual(expect.arrayContaining([
|
|
436
|
+
expect.objectContaining({
|
|
437
|
+
when: 'scope_or_contract_uncertain',
|
|
438
|
+
conditions: expect.arrayContaining(['confidence.scope < 0.85']),
|
|
439
|
+
refs: expect.arrayContaining([
|
|
440
|
+
expect.objectContaining({ ref: expect.stringContaining('planning/design.md') })
|
|
441
|
+
])
|
|
442
|
+
}),
|
|
443
|
+
expect.objectContaining({
|
|
444
|
+
when: 'implementation_details_needed',
|
|
445
|
+
refs: expect.arrayContaining([
|
|
446
|
+
expect.objectContaining({ ref: 'lib/skill-runtime/query.js' })
|
|
447
|
+
])
|
|
448
|
+
})
|
|
449
|
+
]));
|
|
450
|
+
expect(context.progressiveDisclosure.defaultOpen).not.toEqual(expect.arrayContaining([
|
|
451
|
+
'design.md',
|
|
452
|
+
'tasks.md',
|
|
453
|
+
'change-meta.json'
|
|
454
|
+
]));
|
|
455
|
+
expect(context.progressiveDisclosure.commandsToTrust).toContain('npm test -- lib/skill-runtime/__tests__/query.test.js');
|
|
456
|
+
expect(context.progressiveDisclosure.openWhen).toEqual(expect.arrayContaining([
|
|
457
|
+
expect.objectContaining({
|
|
458
|
+
trigger: expect.stringContaining('all tasks are complete'),
|
|
459
|
+
conditions: expect.arrayContaining(['nextAction.skill == cc-act'])
|
|
460
|
+
})
|
|
461
|
+
]));
|
|
462
|
+
expect(context.planningMeta).toMatchObject({
|
|
463
|
+
reqPlanSkillVersion: '3.8.8',
|
|
464
|
+
sourceCapability: 'cap-compact-context',
|
|
465
|
+
specSyncStatus: 'planned'
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
test('routes compact workflow context through check and act after execution', async () => {
|
|
470
|
+
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-terminal-'));
|
|
471
|
+
|
|
472
|
+
writeJson(getTaskManifestPath(repoRoot, 'REQ-127'), {
|
|
473
|
+
changeId: 'REQ-127',
|
|
474
|
+
goal: 'Expose terminal workflow routing',
|
|
475
|
+
createdAt: '2026-05-12T01:00:00.000Z',
|
|
476
|
+
updatedAt: '2026-05-12T01:05:00.000Z',
|
|
477
|
+
tasks: [
|
|
478
|
+
{
|
|
479
|
+
id: 'T001',
|
|
480
|
+
status: 'passed',
|
|
481
|
+
verification: ['npm test -- final.test.js'],
|
|
482
|
+
context: {
|
|
483
|
+
commands: ['npm test -- final.test.js']
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
],
|
|
487
|
+
metadata: {
|
|
488
|
+
source: 'test',
|
|
489
|
+
generatedBy: 'test',
|
|
490
|
+
planVersion: 1
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
await expect(getWorkflowContext(repoRoot, 'REQ-127')).resolves.toMatchObject({
|
|
495
|
+
nextAction: {
|
|
496
|
+
skill: 'cc-check',
|
|
497
|
+
action: 'build-fresh-verdict'
|
|
498
|
+
},
|
|
499
|
+
progressiveDisclosure: {
|
|
500
|
+
commandsToTrust: ['npm test -- final.test.js']
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
writeJson(getReportCardPath(repoRoot, 'REQ-127'), {
|
|
505
|
+
changeId: 'REQ-127',
|
|
506
|
+
verdict: 'pass',
|
|
507
|
+
overall: 'pass',
|
|
508
|
+
reroute: 'none',
|
|
509
|
+
specSyncReady: false,
|
|
510
|
+
blockingFindings: [],
|
|
511
|
+
timestamp: '2026-05-12T01:10:00.000Z'
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
await expect(getWorkflowContext(repoRoot, 'REQ-127')).resolves.toMatchObject({
|
|
515
|
+
nextAction: {
|
|
516
|
+
skill: 'cc-check',
|
|
517
|
+
action: 'build-fresh-verdict',
|
|
518
|
+
blockers: expect.arrayContaining(['specSyncReady is not true'])
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
writeJson(getReportCardPath(repoRoot, 'REQ-127'), {
|
|
523
|
+
changeId: 'REQ-127',
|
|
524
|
+
verdict: 'pass',
|
|
525
|
+
overall: 'pass',
|
|
526
|
+
reroute: 'none',
|
|
527
|
+
specSyncReady: true,
|
|
528
|
+
blockingFindings: [],
|
|
529
|
+
timestamp: '2026-05-12T01:11:00.000Z'
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
await expect(getWorkflowContext(repoRoot, 'REQ-127')).resolves.toMatchObject({
|
|
533
|
+
nextAction: {
|
|
534
|
+
skill: 'cc-act',
|
|
535
|
+
action: 'ship-or-handoff'
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
test('resumes current running task before selecting another ready task', async () => {
|
|
541
|
+
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-resume-'));
|
|
542
|
+
|
|
543
|
+
writeJson(getTaskManifestPath(repoRoot, 'REQ-130'), {
|
|
544
|
+
changeId: 'REQ-130',
|
|
545
|
+
currentTaskId: 'T002',
|
|
546
|
+
tasks: [
|
|
547
|
+
{ id: 'T001', status: 'passed' },
|
|
548
|
+
{
|
|
549
|
+
id: 'T002',
|
|
550
|
+
status: 'running',
|
|
551
|
+
dependsOn: ['T001'],
|
|
552
|
+
verification: ['npm test -- src/current.test.ts'],
|
|
553
|
+
context: {
|
|
554
|
+
commands: ['npm test -- src/current.test.ts']
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
id: 'T003',
|
|
559
|
+
status: 'pending',
|
|
560
|
+
dependsOn: ['T001'],
|
|
561
|
+
verification: ['npm test -- src/ready.test.ts'],
|
|
562
|
+
context: {
|
|
563
|
+
commands: ['npm test -- src/ready.test.ts']
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
],
|
|
567
|
+
metadata: {
|
|
568
|
+
source: 'test',
|
|
569
|
+
generatedBy: 'test',
|
|
570
|
+
planVersion: 1
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
await expect(getWorkflowContext(repoRoot, 'REQ-130')).resolves.toMatchObject({
|
|
575
|
+
nextAction: {
|
|
576
|
+
skill: 'cc-do',
|
|
577
|
+
action: 'resume-current-task',
|
|
578
|
+
taskId: 'T002'
|
|
579
|
+
},
|
|
580
|
+
currentTask: {
|
|
581
|
+
id: 'T002',
|
|
582
|
+
status: 'running'
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
test('resumes inferred running task before selecting ready task when currentTaskId is missing', async () => {
|
|
588
|
+
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-inferred-resume-'));
|
|
589
|
+
|
|
590
|
+
writeJson(getTaskManifestPath(repoRoot, 'REQ-132'), {
|
|
591
|
+
changeId: 'REQ-132',
|
|
592
|
+
tasks: [
|
|
593
|
+
{ id: 'T001', status: 'passed' },
|
|
594
|
+
{
|
|
595
|
+
id: 'T002',
|
|
596
|
+
status: 'running',
|
|
597
|
+
dependsOn: ['T001'],
|
|
598
|
+
verification: ['npm test -- src/current.test.ts'],
|
|
599
|
+
context: {
|
|
600
|
+
commands: ['npm test -- src/current.test.ts']
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
id: 'T003',
|
|
605
|
+
status: 'pending',
|
|
606
|
+
dependsOn: ['T001'],
|
|
607
|
+
verification: ['npm test -- src/ready.test.ts'],
|
|
608
|
+
context: {
|
|
609
|
+
commands: ['npm test -- src/ready.test.ts']
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
],
|
|
613
|
+
metadata: {
|
|
614
|
+
source: 'test',
|
|
615
|
+
generatedBy: 'test',
|
|
616
|
+
planVersion: 1
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
await expect(getWorkflowContext(repoRoot, 'REQ-132')).resolves.toMatchObject({
|
|
621
|
+
nextAction: {
|
|
622
|
+
skill: 'cc-do',
|
|
623
|
+
action: 'resume-current-task',
|
|
624
|
+
taskId: 'T002'
|
|
625
|
+
},
|
|
626
|
+
currentTask: {
|
|
627
|
+
id: 'T002',
|
|
628
|
+
status: 'running'
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
test('reports missing verification commands instead of trusting the query command', async () => {
|
|
634
|
+
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-missing-commands-'));
|
|
635
|
+
|
|
636
|
+
writeJson(getTaskManifestPath(repoRoot, 'REQ-131'), {
|
|
637
|
+
changeId: 'REQ-131',
|
|
638
|
+
currentTaskId: 'T001',
|
|
639
|
+
tasks: [
|
|
640
|
+
{
|
|
641
|
+
id: 'T001',
|
|
642
|
+
status: 'pending',
|
|
643
|
+
context: {
|
|
644
|
+
readFiles: ['design.md']
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
],
|
|
648
|
+
metadata: {
|
|
649
|
+
source: 'test',
|
|
650
|
+
generatedBy: 'test',
|
|
651
|
+
planVersion: 1
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
await expect(getWorkflowContext(repoRoot, 'REQ-131')).resolves.toMatchObject({
|
|
656
|
+
nextAction: {
|
|
657
|
+
skill: 'cc-plan',
|
|
658
|
+
action: 'repair-task-verification',
|
|
659
|
+
taskId: 'T001'
|
|
660
|
+
},
|
|
661
|
+
progressiveDisclosure: {
|
|
662
|
+
commandsToTrust: [],
|
|
663
|
+
missingVerificationCommands: true,
|
|
664
|
+
manifestIssue: 'current task has no executable verification command',
|
|
665
|
+
failClosed: expect.arrayContaining([
|
|
666
|
+
expect.stringContaining('verification command is missing')
|
|
667
|
+
])
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
});
|
|
671
|
+
|
|
291
672
|
test('dispatches typed query ids with trace metadata', async () => {
|
|
292
673
|
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-registry-'));
|
|
293
674
|
|
|
@@ -321,7 +702,7 @@ describe('query helpers', () => {
|
|
|
321
702
|
}
|
|
322
703
|
});
|
|
323
704
|
|
|
324
|
-
expect(listQueryIds()).toEqual(expect.arrayContaining(['full-state', 'next-task', 'progress']));
|
|
705
|
+
expect(listQueryIds()).toEqual(expect.arrayContaining(['full-state', 'next-task', 'progress', 'workflow-context']));
|
|
325
706
|
});
|
|
326
707
|
|
|
327
708
|
test('requires a full change key when duplicate local numbers exist', async () => {
|
|
@@ -354,7 +735,7 @@ describe('query helpers', () => {
|
|
|
354
735
|
},
|
|
355
736
|
trace: {
|
|
356
737
|
event: 'query.progress.failed',
|
|
357
|
-
nextAction: 'inspect-
|
|
738
|
+
nextAction: 'inspect-workflow-artifacts'
|
|
358
739
|
}
|
|
359
740
|
});
|
|
360
741
|
|
|
@@ -381,7 +762,7 @@ describe('query helpers', () => {
|
|
|
381
762
|
queryId: 'unknown-query',
|
|
382
763
|
error: {
|
|
383
764
|
name: 'UnknownQueryError',
|
|
384
|
-
rescueAction: 'use one of: full-state, next-task, progress, ship-readiness'
|
|
765
|
+
rescueAction: 'use one of: full-state, next-task, progress, ship-readiness, workflow-context'
|
|
385
766
|
},
|
|
386
767
|
trace: {
|
|
387
768
|
nextAction: 'choose-supported-query'
|
|
@@ -400,11 +781,11 @@ describe('query helpers', () => {
|
|
|
400
781
|
artifactRefs: [
|
|
401
782
|
expect.stringContaining('task-manifest.json')
|
|
402
783
|
],
|
|
403
|
-
rescueAction: 'create required
|
|
784
|
+
rescueAction: 'create required workflow artifacts before running this query'
|
|
404
785
|
},
|
|
405
786
|
trace: {
|
|
406
787
|
event: 'query.progress.failed',
|
|
407
|
-
nextAction: 'create required
|
|
788
|
+
nextAction: 'create required workflow artifacts before running this query'
|
|
408
789
|
}
|
|
409
790
|
});
|
|
410
791
|
});
|
|
@@ -423,11 +804,11 @@ describe('query helpers', () => {
|
|
|
423
804
|
artifactRefs: [
|
|
424
805
|
expect.stringContaining('task-manifest.json')
|
|
425
806
|
],
|
|
426
|
-
rescueAction: 'repair or regenerate the invalid
|
|
807
|
+
rescueAction: 'repair or regenerate the invalid workflow artifact before running this query'
|
|
427
808
|
},
|
|
428
809
|
trace: {
|
|
429
810
|
event: 'query.progress.failed',
|
|
430
|
-
nextAction: 'repair or regenerate the invalid
|
|
811
|
+
nextAction: 'repair or regenerate the invalid workflow artifact before running this query'
|
|
431
812
|
}
|
|
432
813
|
});
|
|
433
814
|
});
|