cclaw-cli 7.7.0 → 8.1.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/README.md +210 -134
- package/dist/artifact-frontmatter.d.ts +51 -0
- package/dist/artifact-frontmatter.js +131 -0
- package/dist/artifact-paths.d.ts +7 -27
- package/dist/artifact-paths.js +20 -249
- package/dist/cancel.d.ts +16 -0
- package/dist/cancel.js +66 -0
- package/dist/cli.d.ts +2 -27
- package/dist/cli.js +90 -508
- package/dist/compound.d.ts +26 -0
- package/dist/compound.js +96 -0
- package/dist/config.d.ts +14 -51
- package/dist/config.js +23 -359
- package/dist/constants.d.ts +11 -18
- package/dist/constants.js +19 -106
- package/dist/content/antipatterns.d.ts +1 -0
- package/dist/content/antipatterns.js +109 -0
- package/dist/content/artifact-templates.d.ts +10 -0
- package/dist/content/artifact-templates.js +550 -0
- package/dist/content/cancel-command.d.ts +2 -2
- package/dist/content/cancel-command.js +25 -17
- package/dist/content/core-agents.d.ts +9 -233
- package/dist/content/core-agents.js +39 -766
- package/dist/content/decision-protocol.d.ts +1 -12
- package/dist/content/decision-protocol.js +27 -20
- package/dist/content/examples.d.ts +8 -42
- package/dist/content/examples.js +293 -425
- package/dist/content/idea-command.d.ts +2 -0
- package/dist/content/idea-command.js +38 -0
- package/dist/content/iron-laws.d.ts +4 -138
- package/dist/content/iron-laws.js +18 -197
- package/dist/content/meta-skill.d.ts +1 -3
- package/dist/content/meta-skill.js +57 -132
- package/dist/content/node-hooks.d.ts +12 -8
- package/dist/content/node-hooks.js +188 -838
- package/dist/content/recovery.d.ts +8 -0
- package/dist/content/recovery.js +179 -0
- package/dist/content/reference-patterns.d.ts +4 -13
- package/dist/content/reference-patterns.js +260 -389
- package/dist/content/research-playbooks.d.ts +8 -8
- package/dist/content/research-playbooks.js +108 -121
- package/dist/content/review-loop.d.ts +6 -192
- package/dist/content/review-loop.js +29 -731
- package/dist/content/skills.d.ts +8 -38
- package/dist/content/skills.js +681 -732
- package/dist/content/specialist-prompts/architect.d.ts +1 -0
- package/dist/content/specialist-prompts/architect.js +225 -0
- package/dist/content/specialist-prompts/brainstormer.d.ts +1 -0
- package/dist/content/specialist-prompts/brainstormer.js +168 -0
- package/dist/content/specialist-prompts/index.d.ts +2 -0
- package/dist/content/specialist-prompts/index.js +14 -0
- package/dist/content/specialist-prompts/planner.d.ts +1 -0
- package/dist/content/specialist-prompts/planner.js +182 -0
- package/dist/content/specialist-prompts/reviewer.d.ts +1 -0
- package/dist/content/specialist-prompts/reviewer.js +193 -0
- package/dist/content/specialist-prompts/security-reviewer.d.ts +1 -0
- package/dist/content/specialist-prompts/security-reviewer.js +133 -0
- package/dist/content/specialist-prompts/slice-builder.d.ts +1 -0
- package/dist/content/specialist-prompts/slice-builder.js +232 -0
- package/dist/content/stage-playbooks.d.ts +8 -0
- package/dist/content/stage-playbooks.js +404 -0
- package/dist/content/start-command.d.ts +2 -12
- package/dist/content/start-command.js +221 -207
- package/dist/flow-state.d.ts +21 -178
- package/dist/flow-state.js +67 -170
- package/dist/fs-utils.d.ts +6 -26
- package/dist/fs-utils.js +29 -162
- package/dist/gitignore.d.ts +2 -1
- package/dist/gitignore.js +51 -34
- package/dist/harness-detect.d.ts +10 -0
- package/dist/harness-detect.js +29 -0
- package/dist/install.d.ts +27 -15
- package/dist/install.js +230 -1342
- package/dist/knowledge-store.d.ts +19 -163
- package/dist/knowledge-store.js +56 -590
- package/dist/logger.d.ts +8 -3
- package/dist/logger.js +13 -4
- package/dist/orchestrator-routing.d.ts +29 -0
- package/dist/orchestrator-routing.js +156 -0
- package/dist/run-persistence.d.ts +7 -118
- package/dist/run-persistence.js +29 -845
- package/dist/runtime/run-hook.entry.d.ts +1 -3
- package/dist/runtime/run-hook.entry.js +19 -4
- package/dist/runtime/run-hook.mjs +13 -1024
- package/dist/types.d.ts +25 -261
- package/dist/types.js +8 -36
- package/package.json +6 -3
- package/dist/artifact-linter/brainstorm.d.ts +0 -2
- package/dist/artifact-linter/brainstorm.js +0 -353
- package/dist/artifact-linter/design.d.ts +0 -18
- package/dist/artifact-linter/design.js +0 -444
- package/dist/artifact-linter/findings-dedup.d.ts +0 -56
- package/dist/artifact-linter/findings-dedup.js +0 -232
- package/dist/artifact-linter/plan.d.ts +0 -2
- package/dist/artifact-linter/plan.js +0 -826
- package/dist/artifact-linter/review-army.d.ts +0 -49
- package/dist/artifact-linter/review-army.js +0 -520
- package/dist/artifact-linter/review.d.ts +0 -2
- package/dist/artifact-linter/review.js +0 -113
- package/dist/artifact-linter/scope.d.ts +0 -2
- package/dist/artifact-linter/scope.js +0 -158
- package/dist/artifact-linter/shared.d.ts +0 -637
- package/dist/artifact-linter/shared.js +0 -2163
- package/dist/artifact-linter/ship.d.ts +0 -2
- package/dist/artifact-linter/ship.js +0 -250
- package/dist/artifact-linter/spec.d.ts +0 -2
- package/dist/artifact-linter/spec.js +0 -176
- package/dist/artifact-linter/tdd.d.ts +0 -118
- package/dist/artifact-linter/tdd.js +0 -1404
- package/dist/artifact-linter.d.ts +0 -15
- package/dist/artifact-linter.js +0 -517
- package/dist/codex-feature-flag.d.ts +0 -58
- package/dist/codex-feature-flag.js +0 -193
- package/dist/content/closeout-guidance.d.ts +0 -14
- package/dist/content/closeout-guidance.js +0 -44
- package/dist/content/diff-command.d.ts +0 -1
- package/dist/content/diff-command.js +0 -43
- package/dist/content/harness-doc.d.ts +0 -1
- package/dist/content/harness-doc.js +0 -65
- package/dist/content/hook-events.d.ts +0 -9
- package/dist/content/hook-events.js +0 -23
- package/dist/content/hook-manifest.d.ts +0 -81
- package/dist/content/hook-manifest.js +0 -156
- package/dist/content/hooks.d.ts +0 -11
- package/dist/content/hooks.js +0 -1972
- package/dist/content/idea.d.ts +0 -60
- package/dist/content/idea.js +0 -416
- package/dist/content/language-policy.d.ts +0 -2
- package/dist/content/language-policy.js +0 -13
- package/dist/content/learnings.d.ts +0 -6
- package/dist/content/learnings.js +0 -141
- package/dist/content/observe.d.ts +0 -19
- package/dist/content/observe.js +0 -86
- package/dist/content/opencode-plugin.d.ts +0 -1
- package/dist/content/opencode-plugin.js +0 -635
- package/dist/content/review-prompts.d.ts +0 -1
- package/dist/content/review-prompts.js +0 -104
- package/dist/content/runtime-shared-snippets.d.ts +0 -8
- package/dist/content/runtime-shared-snippets.js +0 -80
- package/dist/content/session-hooks.d.ts +0 -7
- package/dist/content/session-hooks.js +0 -107
- package/dist/content/skills-elicitation.d.ts +0 -1
- package/dist/content/skills-elicitation.js +0 -167
- package/dist/content/stage-command.d.ts +0 -2
- package/dist/content/stage-command.js +0 -17
- package/dist/content/stage-schema.d.ts +0 -117
- package/dist/content/stage-schema.js +0 -955
- package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
- package/dist/content/stages/_lint-metadata/index.js +0 -97
- package/dist/content/stages/brainstorm.d.ts +0 -2
- package/dist/content/stages/brainstorm.js +0 -184
- package/dist/content/stages/design.d.ts +0 -2
- package/dist/content/stages/design.js +0 -288
- package/dist/content/stages/index.d.ts +0 -8
- package/dist/content/stages/index.js +0 -11
- package/dist/content/stages/plan.d.ts +0 -2
- package/dist/content/stages/plan.js +0 -191
- package/dist/content/stages/review.d.ts +0 -2
- package/dist/content/stages/review.js +0 -240
- package/dist/content/stages/schema-types.d.ts +0 -203
- package/dist/content/stages/schema-types.js +0 -1
- package/dist/content/stages/scope.d.ts +0 -2
- package/dist/content/stages/scope.js +0 -254
- package/dist/content/stages/ship.d.ts +0 -2
- package/dist/content/stages/ship.js +0 -159
- package/dist/content/stages/spec.d.ts +0 -2
- package/dist/content/stages/spec.js +0 -170
- package/dist/content/stages/tdd.d.ts +0 -4
- package/dist/content/stages/tdd.js +0 -273
- package/dist/content/state-contracts.d.ts +0 -1
- package/dist/content/state-contracts.js +0 -63
- package/dist/content/status-command.d.ts +0 -4
- package/dist/content/status-command.js +0 -109
- package/dist/content/subagent-context-skills.d.ts +0 -4
- package/dist/content/subagent-context-skills.js +0 -279
- package/dist/content/subagents.d.ts +0 -3
- package/dist/content/subagents.js +0 -997
- package/dist/content/templates.d.ts +0 -26
- package/dist/content/templates.js +0 -1692
- package/dist/content/track-render-context.d.ts +0 -18
- package/dist/content/track-render-context.js +0 -53
- package/dist/content/tree-command.d.ts +0 -1
- package/dist/content/tree-command.js +0 -64
- package/dist/content/utility-skills.d.ts +0 -30
- package/dist/content/utility-skills.js +0 -160
- package/dist/content/view-command.d.ts +0 -2
- package/dist/content/view-command.js +0 -92
- package/dist/delegation.d.ts +0 -649
- package/dist/delegation.js +0 -1539
- package/dist/early-loop.d.ts +0 -70
- package/dist/early-loop.js +0 -302
- package/dist/execution-topology.d.ts +0 -36
- package/dist/execution-topology.js +0 -73
- package/dist/gate-evidence.d.ts +0 -85
- package/dist/gate-evidence.js +0 -631
- package/dist/harness-adapters.d.ts +0 -151
- package/dist/harness-adapters.js +0 -756
- package/dist/harness-selection.d.ts +0 -31
- package/dist/harness-selection.js +0 -214
- package/dist/hook-schema.d.ts +0 -6
- package/dist/hook-schema.js +0 -114
- package/dist/hook-schemas/claude-hooks.v1.json +0 -10
- package/dist/hook-schemas/codex-hooks.v1.json +0 -10
- package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
- package/dist/init-detect.d.ts +0 -2
- package/dist/init-detect.js +0 -50
- package/dist/internal/advance-stage/advance.d.ts +0 -89
- package/dist/internal/advance-stage/advance.js +0 -655
- package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
- package/dist/internal/advance-stage/cancel-run.js +0 -19
- package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
- package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
- package/dist/internal/advance-stage/helpers.d.ts +0 -14
- package/dist/internal/advance-stage/helpers.js +0 -145
- package/dist/internal/advance-stage/hook.d.ts +0 -8
- package/dist/internal/advance-stage/hook.js +0 -40
- package/dist/internal/advance-stage/parsers.d.ts +0 -72
- package/dist/internal/advance-stage/parsers.js +0 -357
- package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
- package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
- package/dist/internal/advance-stage/review-loop.d.ts +0 -16
- package/dist/internal/advance-stage/review-loop.js +0 -199
- package/dist/internal/advance-stage/rewind.d.ts +0 -14
- package/dist/internal/advance-stage/rewind.js +0 -108
- package/dist/internal/advance-stage/start-flow.d.ts +0 -13
- package/dist/internal/advance-stage/start-flow.js +0 -241
- package/dist/internal/advance-stage/verify.d.ts +0 -21
- package/dist/internal/advance-stage/verify.js +0 -185
- package/dist/internal/advance-stage.d.ts +0 -7
- package/dist/internal/advance-stage.js +0 -138
- package/dist/internal/cohesion-contract-stub.d.ts +0 -24
- package/dist/internal/cohesion-contract-stub.js +0 -148
- package/dist/internal/compound-readiness.d.ts +0 -23
- package/dist/internal/compound-readiness.js +0 -102
- package/dist/internal/detect-public-api-changes.d.ts +0 -5
- package/dist/internal/detect-public-api-changes.js +0 -45
- package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
- package/dist/internal/detect-supply-chain-changes.js +0 -138
- package/dist/internal/early-loop-status.d.ts +0 -7
- package/dist/internal/early-loop-status.js +0 -93
- package/dist/internal/envelope-validate.d.ts +0 -7
- package/dist/internal/envelope-validate.js +0 -66
- package/dist/internal/flow-state-repair.d.ts +0 -20
- package/dist/internal/flow-state-repair.js +0 -104
- package/dist/internal/plan-split-waves.d.ts +0 -190
- package/dist/internal/plan-split-waves.js +0 -764
- package/dist/internal/runtime-integrity.d.ts +0 -7
- package/dist/internal/runtime-integrity.js +0 -268
- package/dist/internal/slice-commit.d.ts +0 -7
- package/dist/internal/slice-commit.js +0 -619
- package/dist/internal/tdd-loop-status.d.ts +0 -14
- package/dist/internal/tdd-loop-status.js +0 -68
- package/dist/internal/tdd-red-evidence.d.ts +0 -7
- package/dist/internal/tdd-red-evidence.js +0 -153
- package/dist/internal/waiver-grant.d.ts +0 -62
- package/dist/internal/waiver-grant.js +0 -294
- package/dist/internal/wave-status.d.ts +0 -63
- package/dist/internal/wave-status.js +0 -450
- package/dist/managed-resources.d.ts +0 -53
- package/dist/managed-resources.js +0 -313
- package/dist/policy.d.ts +0 -10
- package/dist/policy.js +0 -167
- package/dist/retro-gate.d.ts +0 -9
- package/dist/retro-gate.js +0 -47
- package/dist/run-archive.d.ts +0 -61
- package/dist/run-archive.js +0 -391
- package/dist/runs.d.ts +0 -2
- package/dist/runs.js +0 -2
- package/dist/stack-detection.d.ts +0 -116
- package/dist/stack-detection.js +0 -489
- package/dist/streaming/event-stream.d.ts +0 -31
- package/dist/streaming/event-stream.js +0 -114
- package/dist/tdd-cycle.d.ts +0 -107
- package/dist/tdd-cycle.js +0 -289
- package/dist/tdd-verification-evidence.d.ts +0 -17
- package/dist/tdd-verification-evidence.js +0 -122
- package/dist/track-heuristics.d.ts +0 -27
- package/dist/track-heuristics.js +0 -154
- package/dist/util/slice-id.d.ts +0 -58
- package/dist/util/slice-id.js +0 -89
- package/dist/worktree-manager.d.ts +0 -20
- package/dist/worktree-manager.js +0 -108
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { RUNTIME_ROOT } from "../../constants.js";
|
|
4
|
-
import { ensureDir } from "../../fs-utils.js";
|
|
5
|
-
import { readFlowState, writeFlowState } from "../../runs.js";
|
|
6
|
-
import { TRACK_STAGES } from "../../types.js";
|
|
7
|
-
export function rewindLogPath(projectRoot) {
|
|
8
|
-
return path.join(projectRoot, RUNTIME_ROOT, "state", "rewind-log.jsonl");
|
|
9
|
-
}
|
|
10
|
-
export function rewindId(date = new Date()) {
|
|
11
|
-
return `rewind-${date.getTime().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
12
|
-
}
|
|
13
|
-
export function stagesInvalidatedByRewind(current, targetStage) {
|
|
14
|
-
const ordered = TRACK_STAGES[current.track];
|
|
15
|
-
const targetIndex = ordered.indexOf(targetStage);
|
|
16
|
-
const currentIndex = ordered.indexOf(current.currentStage);
|
|
17
|
-
if (targetIndex < 0 || currentIndex < 0 || targetIndex > currentIndex) {
|
|
18
|
-
return [];
|
|
19
|
-
}
|
|
20
|
-
return ordered.slice(targetIndex, currentIndex + 1);
|
|
21
|
-
}
|
|
22
|
-
export async function appendRewindLog(projectRoot, payload) {
|
|
23
|
-
const logPath = rewindLogPath(projectRoot);
|
|
24
|
-
await ensureDir(path.dirname(logPath));
|
|
25
|
-
await fs.appendFile(logPath, `${JSON.stringify(payload)}\n`, "utf8");
|
|
26
|
-
}
|
|
27
|
-
export async function runRewind(projectRoot, args, io) {
|
|
28
|
-
const current = await readFlowState(projectRoot);
|
|
29
|
-
const now = new Date().toISOString();
|
|
30
|
-
if (args.mode === "ack") {
|
|
31
|
-
const marker = current.staleStages[args.targetStage];
|
|
32
|
-
if (!marker) {
|
|
33
|
-
io.stderr.write(`cclaw internal rewind: no stale marker exists for "${args.targetStage}".\n`);
|
|
34
|
-
return 1;
|
|
35
|
-
}
|
|
36
|
-
if (current.currentStage !== args.targetStage) {
|
|
37
|
-
io.stderr.write(`cclaw internal rewind: cannot ack "${args.targetStage}" while currentStage is "${current.currentStage}". Re-run the stale stage before acknowledging it.\n`);
|
|
38
|
-
return 1;
|
|
39
|
-
}
|
|
40
|
-
const staleStages = { ...current.staleStages };
|
|
41
|
-
delete staleStages[args.targetStage];
|
|
42
|
-
const nextState = { ...current, staleStages };
|
|
43
|
-
await writeFlowState(projectRoot, nextState, { writerSubsystem: "rewind-ack" });
|
|
44
|
-
const payload = {
|
|
45
|
-
ok: true,
|
|
46
|
-
command: "rewind",
|
|
47
|
-
action: "ack",
|
|
48
|
-
stage: args.targetStage,
|
|
49
|
-
acknowledgedAt: now,
|
|
50
|
-
rewindId: marker.rewindId
|
|
51
|
-
};
|
|
52
|
-
await appendRewindLog(projectRoot, payload);
|
|
53
|
-
if (!args.quiet) {
|
|
54
|
-
io.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
55
|
-
}
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
58
|
-
const invalidatedStages = stagesInvalidatedByRewind(current, args.targetStage);
|
|
59
|
-
if (invalidatedStages.length === 0) {
|
|
60
|
-
io.stderr.write(`cclaw internal rewind: target "${args.targetStage}" is not an earlier or current stage on track "${current.track}" from "${current.currentStage}".\n`);
|
|
61
|
-
return 1;
|
|
62
|
-
}
|
|
63
|
-
const id = rewindId();
|
|
64
|
-
const completedInvalidated = new Set(invalidatedStages);
|
|
65
|
-
const staleStages = { ...current.staleStages };
|
|
66
|
-
for (const stage of invalidatedStages) {
|
|
67
|
-
staleStages[stage] = {
|
|
68
|
-
rewindId: id,
|
|
69
|
-
reason: args.reason ?? "rewind",
|
|
70
|
-
markedAt: now
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
const record = {
|
|
74
|
-
id,
|
|
75
|
-
fromStage: current.currentStage,
|
|
76
|
-
toStage: args.targetStage,
|
|
77
|
-
reason: args.reason ?? "rewind",
|
|
78
|
-
timestamp: now,
|
|
79
|
-
invalidatedStages
|
|
80
|
-
};
|
|
81
|
-
const nextState = {
|
|
82
|
-
...current,
|
|
83
|
-
currentStage: args.targetStage,
|
|
84
|
-
completedStages: current.completedStages.filter((stage) => !completedInvalidated.has(stage)),
|
|
85
|
-
staleStages,
|
|
86
|
-
rewinds: [...current.rewinds, record]
|
|
87
|
-
};
|
|
88
|
-
await writeFlowState(projectRoot, nextState, { writerSubsystem: "rewind" });
|
|
89
|
-
const payload = {
|
|
90
|
-
ok: true,
|
|
91
|
-
command: "rewind",
|
|
92
|
-
action: "rewind",
|
|
93
|
-
rewind: record,
|
|
94
|
-
currentStage: nextState.currentStage,
|
|
95
|
-
completedStages: nextState.completedStages,
|
|
96
|
-
staleStages: Object.keys(nextState.staleStages),
|
|
97
|
-
nextActions: [
|
|
98
|
-
`Re-run ${args.targetStage} stage work and update its artifact evidence.`,
|
|
99
|
-
`Then run cclaw internal rewind --ack ${args.targetStage}.`,
|
|
100
|
-
"Continue with /cc after the stale marker is acknowledged."
|
|
101
|
-
]
|
|
102
|
-
};
|
|
103
|
-
await appendRewindLog(projectRoot, payload);
|
|
104
|
-
if (!args.quiet) {
|
|
105
|
-
io.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
106
|
-
}
|
|
107
|
-
return 0;
|
|
108
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { type FlowState, type RepoSignals } from "../../flow-state.js";
|
|
2
|
-
import type { StartFlowArgs } from "./parsers.js";
|
|
3
|
-
import type { Writable } from "node:stream";
|
|
4
|
-
interface InternalIo {
|
|
5
|
-
stdout: Writable;
|
|
6
|
-
stderr: Writable;
|
|
7
|
-
}
|
|
8
|
-
/** One-pass repo snapshot (max ~200 files, skips `node_modules`/`.git`). */
|
|
9
|
-
export declare function collectRepoSignals(projectRoot: string): Promise<RepoSignals>;
|
|
10
|
-
export declare function discoverStartFlowContext(projectRoot: string): Promise<string[]>;
|
|
11
|
-
export declare function appendIdeaArtifact(projectRoot: string, args: StartFlowArgs, previous?: FlowState): Promise<void>;
|
|
12
|
-
export declare function runStartFlow(projectRoot: string, args: StartFlowArgs, io: InternalIo): Promise<number>;
|
|
13
|
-
export {};
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { RUNTIME_ROOT } from "../../constants.js";
|
|
4
|
-
import { createInitialFlowState } from "../../flow-state.js";
|
|
5
|
-
import { readFlowState, writeFlowState } from "../../runs.js";
|
|
6
|
-
import { listExistingFiles, listFilesUnder, pathExists } from "./helpers.js";
|
|
7
|
-
import { STACK_DISCOVERY_DIR_MARKERS, STACK_DISCOVERY_MARKERS, loadStackAdapter } from "../../stack-detection.js";
|
|
8
|
-
import { TRACK_STAGES } from "../../types.js";
|
|
9
|
-
import { buildValidationReport } from "./advance.js";
|
|
10
|
-
import { carriedCompletedStageCatalog, completedStageClosureEvidenceIssues, firstIncompleteStageForTrack } from "./verify.js";
|
|
11
|
-
function resolveTaskClass(className, fallback) {
|
|
12
|
-
if (className === "software-standard" || className === "software-trivial" || className === "software-bugfix") {
|
|
13
|
-
return className;
|
|
14
|
-
}
|
|
15
|
-
return fallback;
|
|
16
|
-
}
|
|
17
|
-
const REPO_SIGNAL_SKIP_DIRS = new Set(["node_modules", ".git"]);
|
|
18
|
-
/** One-pass repo snapshot (max ~200 files, skips `node_modules`/`.git`). */
|
|
19
|
-
export async function collectRepoSignals(projectRoot) {
|
|
20
|
-
const capturedAt = new Date().toISOString();
|
|
21
|
-
const cap = 200;
|
|
22
|
-
let fileCount = 0;
|
|
23
|
-
async function visit(absDir, depth) {
|
|
24
|
-
if (fileCount >= cap)
|
|
25
|
-
return;
|
|
26
|
-
let entries;
|
|
27
|
-
try {
|
|
28
|
-
entries = await fs.readdir(absDir, { withFileTypes: true });
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
for (const ent of entries) {
|
|
34
|
-
if (fileCount >= cap)
|
|
35
|
-
return;
|
|
36
|
-
const name = ent.name;
|
|
37
|
-
if (REPO_SIGNAL_SKIP_DIRS.has(name))
|
|
38
|
-
continue;
|
|
39
|
-
const abs = path.join(absDir, name);
|
|
40
|
-
if (ent.isFile()) {
|
|
41
|
-
fileCount += 1;
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
if (ent.isDirectory() && depth < 1) {
|
|
45
|
-
await visit(abs, depth + 1);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
let hasReadme = false;
|
|
50
|
-
let hasPackageManifest = false;
|
|
51
|
-
for (const fname of ["README.md", "readme.md", "Readme.md"]) {
|
|
52
|
-
try {
|
|
53
|
-
const st = await fs.stat(path.join(projectRoot, fname));
|
|
54
|
-
if (st.isFile())
|
|
55
|
-
hasReadme = true;
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
// ignore
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// 7.6.0 — manifest detection now routes through the stack-adapter
|
|
62
|
-
// contract instead of hardcoding `package.json` / `pyproject.toml` /
|
|
63
|
-
// `Cargo.toml`. Adapters that declare manifestGlobs probe their
|
|
64
|
-
// declared paths; the unknown adapter is a no-op.
|
|
65
|
-
const stackAdapter = await loadStackAdapter(projectRoot);
|
|
66
|
-
for (const manifestGlob of stackAdapter.manifestGlobs) {
|
|
67
|
-
if (manifestGlob.includes("*"))
|
|
68
|
-
continue;
|
|
69
|
-
try {
|
|
70
|
-
const st = await fs.stat(path.join(projectRoot, manifestGlob));
|
|
71
|
-
if (st.isFile()) {
|
|
72
|
-
hasPackageManifest = true;
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
// ignore
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
try {
|
|
81
|
-
await visit(projectRoot, 0);
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
fileCount = Math.min(fileCount, cap);
|
|
85
|
-
}
|
|
86
|
-
return { fileCount, hasReadme, hasPackageManifest, capturedAt };
|
|
87
|
-
}
|
|
88
|
-
export async function discoverStartFlowContext(projectRoot) {
|
|
89
|
-
const lines = [];
|
|
90
|
-
const seedFiles = (await listFilesUnder(projectRoot, path.join(RUNTIME_ROOT, "seeds"), 10))
|
|
91
|
-
.filter((relPath) => /^\.cclaw\/seeds\/SEED-.*\.md$/u.test(relPath));
|
|
92
|
-
lines.push(seedFiles.length > 0
|
|
93
|
-
? `- Seed shelf scanned: ${seedFiles.join(", ")}.`
|
|
94
|
-
: "- Seed shelf scanned: no `.cclaw/seeds/SEED-*.md` files found.");
|
|
95
|
-
const originDirs = ["docs/prd", "docs/rfcs", "docs/adr", "docs/design", "specs", "prd", "rfc", "design"];
|
|
96
|
-
const originRootFiles = ["PRD.md", "SPEC.md", "DESIGN.md", "REQUIREMENTS.md", "ROADMAP.md"];
|
|
97
|
-
const originFiles = [
|
|
98
|
-
...(await listExistingFiles(projectRoot, originRootFiles)),
|
|
99
|
-
...(await Promise.all(originDirs.map((dir) => listFilesUnder(projectRoot, dir, 6)))).flat()
|
|
100
|
-
].slice(0, 20);
|
|
101
|
-
lines.push(originFiles.length > 0
|
|
102
|
-
? `- Origin docs scanned: found ${originFiles.join(", ")}.`
|
|
103
|
-
: "- Origin docs scanned: no PRD/RFC/ADR/design/spec files found in configured locations.");
|
|
104
|
-
const stackMarkers = await listExistingFiles(projectRoot, [...STACK_DISCOVERY_MARKERS]);
|
|
105
|
-
for (const markerDir of STACK_DISCOVERY_DIR_MARKERS) {
|
|
106
|
-
if (await pathExists(projectRoot, markerDir)) {
|
|
107
|
-
stackMarkers.push(`${markerDir}/`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
lines.push(stackMarkers.length > 0
|
|
111
|
-
? `- Stack markers scanned: found ${stackMarkers.join(", ")}.`
|
|
112
|
-
: "- Stack markers scanned: no root stack markers found.");
|
|
113
|
-
return lines;
|
|
114
|
-
}
|
|
115
|
-
export async function appendIdeaArtifact(projectRoot, args, previous) {
|
|
116
|
-
const artifactPath = path.join(projectRoot, RUNTIME_ROOT, "artifacts", "00-idea.md");
|
|
117
|
-
await fs.mkdir(path.dirname(artifactPath), { recursive: true });
|
|
118
|
-
const now = new Date().toISOString();
|
|
119
|
-
if (args.reclassify) {
|
|
120
|
-
const entry = [
|
|
121
|
-
"",
|
|
122
|
-
`Reclassification: ${now}`,
|
|
123
|
-
`- From: ${previous?.track ?? "unknown"}`,
|
|
124
|
-
`- To: ${args.track}`,
|
|
125
|
-
`- Class: ${args.className || "unspecified"}`,
|
|
126
|
-
`- Discovery mode: ${args.discoveryMode}`,
|
|
127
|
-
`- Reason: ${args.reason || "unspecified"}`
|
|
128
|
-
].join("\n") + "\n";
|
|
129
|
-
await fs.appendFile(artifactPath, entry, "utf8");
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
const discoveredContext = await discoverStartFlowContext(projectRoot);
|
|
133
|
-
const body = [
|
|
134
|
-
"# Idea",
|
|
135
|
-
`Class: ${args.className || "unspecified"}`,
|
|
136
|
-
`Track: ${args.track}${args.reason ? ` (${args.reason})` : ""}`,
|
|
137
|
-
`Discovery mode: ${args.discoveryMode}`,
|
|
138
|
-
`Stack: ${args.stack || "unknown"}`,
|
|
139
|
-
"",
|
|
140
|
-
"## User prompt",
|
|
141
|
-
args.prompt || "(not provided)",
|
|
142
|
-
"",
|
|
143
|
-
"## Discovered context",
|
|
144
|
-
...discoveredContext
|
|
145
|
-
].join("\n") + "\n";
|
|
146
|
-
await fs.writeFile(artifactPath, body, "utf8");
|
|
147
|
-
}
|
|
148
|
-
export async function runStartFlow(projectRoot, args, io) {
|
|
149
|
-
const current = await readFlowState(projectRoot);
|
|
150
|
-
const hasProgress = current.completedStages.length > 0;
|
|
151
|
-
if (!args.reclassify && hasProgress && !args.forceReset) {
|
|
152
|
-
io.stderr.write("cclaw internal start-flow: refusing to reset an active flow with completed stages without --force-reset. Ask the user before resetting.\n");
|
|
153
|
-
return 1;
|
|
154
|
-
}
|
|
155
|
-
const nextTaskClass = resolveTaskClass(args.className, current.taskClass);
|
|
156
|
-
let nextState;
|
|
157
|
-
if (args.reclassify) {
|
|
158
|
-
const completedInNewTrack = current.completedStages.filter((stage) => TRACK_STAGES[args.track].includes(stage));
|
|
159
|
-
const fresh = createInitialFlowState({ activeRunId: current.activeRunId, track: args.track, discoveryMode: args.discoveryMode });
|
|
160
|
-
const stageGateCatalog = { ...fresh.stageGateCatalog };
|
|
161
|
-
const guardEvidence = {};
|
|
162
|
-
for (const stage of completedInNewTrack) {
|
|
163
|
-
const carried = carriedCompletedStageCatalog(current, fresh, stage);
|
|
164
|
-
stageGateCatalog[stage] = carried.catalog;
|
|
165
|
-
Object.assign(guardEvidence, carried.evidence);
|
|
166
|
-
}
|
|
167
|
-
nextState = {
|
|
168
|
-
...fresh,
|
|
169
|
-
...(nextTaskClass !== undefined ? { taskClass: nextTaskClass } : {}),
|
|
170
|
-
completedStages: completedInNewTrack,
|
|
171
|
-
currentStage: firstIncompleteStageForTrack(args.track, completedInNewTrack),
|
|
172
|
-
guardEvidence,
|
|
173
|
-
stageGateCatalog,
|
|
174
|
-
rewinds: current.rewinds,
|
|
175
|
-
staleStages: current.staleStages
|
|
176
|
-
};
|
|
177
|
-
const validation = await buildValidationReport(projectRoot, nextState);
|
|
178
|
-
const evidenceIssues = completedStageClosureEvidenceIssues(nextState);
|
|
179
|
-
if (!validation.completedStages.ok || evidenceIssues.length > 0) {
|
|
180
|
-
io.stderr.write("cclaw internal start-flow: reclassification would leave completed stages without valid gate closure.\n");
|
|
181
|
-
const issues = [...validation.completedStages.issues, ...evidenceIssues];
|
|
182
|
-
if (issues.length > 0) {
|
|
183
|
-
io.stderr.write(`- completed-stage closure issues: ${issues.join(" | ")}\n`);
|
|
184
|
-
}
|
|
185
|
-
return 1;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
nextState = createInitialFlowState({ track: args.track, discoveryMode: args.discoveryMode });
|
|
190
|
-
if (nextTaskClass !== undefined) {
|
|
191
|
-
nextState = { ...nextState, taskClass: nextTaskClass };
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
if (args.fromIdeaArtifact) {
|
|
195
|
-
const existingHints = nextState.interactionHints ?? {};
|
|
196
|
-
const existingBrainstorm = existingHints.brainstorm ?? {};
|
|
197
|
-
nextState.interactionHints = {
|
|
198
|
-
...existingHints,
|
|
199
|
-
brainstorm: {
|
|
200
|
-
...existingBrainstorm,
|
|
201
|
-
fromIdeaArtifact: args.fromIdeaArtifact,
|
|
202
|
-
...(args.fromIdeaCandidateId ? { fromIdeaCandidateId: args.fromIdeaCandidateId } : {}),
|
|
203
|
-
recordedAt: new Date().toISOString()
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
const repoSignals = await collectRepoSignals(projectRoot);
|
|
208
|
-
nextState = { ...nextState, repoSignals };
|
|
209
|
-
await writeFlowState(projectRoot, nextState, {
|
|
210
|
-
allowReset: true,
|
|
211
|
-
writerSubsystem: "start-flow"
|
|
212
|
-
});
|
|
213
|
-
await appendIdeaArtifact(projectRoot, args, current);
|
|
214
|
-
const successPayload = {
|
|
215
|
-
ok: true,
|
|
216
|
-
command: "start-flow",
|
|
217
|
-
reclassify: args.reclassify,
|
|
218
|
-
track: nextState.track,
|
|
219
|
-
discoveryMode: nextState.discoveryMode,
|
|
220
|
-
taskClass: nextState.taskClass ?? null,
|
|
221
|
-
currentStage: nextState.currentStage,
|
|
222
|
-
skippedStages: nextState.skippedStages,
|
|
223
|
-
activeRunId: nextState.activeRunId,
|
|
224
|
-
repoSignals
|
|
225
|
-
};
|
|
226
|
-
if (args.quiet) {
|
|
227
|
-
io.stdout.write(`${JSON.stringify({
|
|
228
|
-
ok: true,
|
|
229
|
-
command: "start-flow",
|
|
230
|
-
track: successPayload.track,
|
|
231
|
-
discoveryMode: successPayload.discoveryMode,
|
|
232
|
-
currentStage: successPayload.currentStage,
|
|
233
|
-
activeRunId: successPayload.activeRunId,
|
|
234
|
-
repoSignals: successPayload.repoSignals
|
|
235
|
-
})}\n`);
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
io.stdout.write(`${JSON.stringify(successPayload, null, 2)}\n`);
|
|
239
|
-
}
|
|
240
|
-
return 0;
|
|
241
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type FlowState, type StageGateState } from "../../flow-state.js";
|
|
2
|
-
import { type FlowStage, type FlowTrack } from "../../types.js";
|
|
3
|
-
import type { VerifyCurrentStateArgs, VerifyFlowStateDiffArgs } from "./parsers.js";
|
|
4
|
-
import type { Writable } from "node:stream";
|
|
5
|
-
interface InternalIo {
|
|
6
|
-
stdout: Writable;
|
|
7
|
-
stderr: Writable;
|
|
8
|
-
}
|
|
9
|
-
export declare function runVerifyFlowStateDiff(projectRoot: string, args: VerifyFlowStateDiffArgs, io: InternalIo): Promise<number>;
|
|
10
|
-
export declare function runVerifyCurrentState(projectRoot: string, args: VerifyCurrentStateArgs, io: InternalIo): Promise<number>;
|
|
11
|
-
export declare function firstIncompleteStageForTrack(track: FlowTrack, completedStages: FlowStage[]): FlowStage;
|
|
12
|
-
export declare function carriedCompletedStageCatalog(current: FlowState, fresh: FlowState, stage: FlowStage): {
|
|
13
|
-
catalog: StageGateState;
|
|
14
|
-
evidence: Record<string, string>;
|
|
15
|
-
};
|
|
16
|
-
export declare function completedStageClosureEvidenceIssues(flowState: FlowState): string[];
|
|
17
|
-
export declare function pathExists(projectRoot: string, relPath: string): Promise<boolean>;
|
|
18
|
-
export declare function listExistingFiles(projectRoot: string, relPaths: string[]): Promise<string[]>;
|
|
19
|
-
export declare function listFilesUnder(projectRoot: string, relDir: string, limit?: number): Promise<string[]>;
|
|
20
|
-
export declare function discoverStartFlowContext(projectRoot: string): Promise<string[]>;
|
|
21
|
-
export {};
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { RUNTIME_ROOT } from "../../constants.js";
|
|
3
|
-
import { stageSchema } from "../../content/stage-schema.js";
|
|
4
|
-
import { readFlowState } from "../../runs.js";
|
|
5
|
-
import { TRACK_STAGES } from "../../types.js";
|
|
6
|
-
import { STACK_DISCOVERY_DIR_MARKERS, STACK_DISCOVERY_MARKERS } from "../../stack-detection.js";
|
|
7
|
-
import { coerceCandidateFlowState } from "./flow-state-coercion.js";
|
|
8
|
-
import { buildValidationReport } from "./advance.js";
|
|
9
|
-
import fs from "node:fs/promises";
|
|
10
|
-
export async function runVerifyFlowStateDiff(projectRoot, args, io) {
|
|
11
|
-
let raw = args.afterJson;
|
|
12
|
-
if (!raw && args.afterFile) {
|
|
13
|
-
raw = await fs.readFile(args.afterFile, "utf8");
|
|
14
|
-
}
|
|
15
|
-
if (!raw) {
|
|
16
|
-
io.stderr.write("cclaw internal verify-flow-state-diff: no candidate state payload.\n");
|
|
17
|
-
return 1;
|
|
18
|
-
}
|
|
19
|
-
let parsed;
|
|
20
|
-
try {
|
|
21
|
-
parsed = JSON.parse(raw);
|
|
22
|
-
}
|
|
23
|
-
catch (err) {
|
|
24
|
-
io.stderr.write(`cclaw internal verify-flow-state-diff: invalid JSON payload (${err instanceof Error ? err.message : String(err)}).\n`);
|
|
25
|
-
return 1;
|
|
26
|
-
}
|
|
27
|
-
const current = await readFlowState(projectRoot);
|
|
28
|
-
const candidate = coerceCandidateFlowState(parsed, current);
|
|
29
|
-
const validation = await buildValidationReport(projectRoot, candidate);
|
|
30
|
-
if (!args.quiet) {
|
|
31
|
-
io.stdout.write(`${JSON.stringify(validation, null, 2)}\n`);
|
|
32
|
-
}
|
|
33
|
-
if (!validation.ok) {
|
|
34
|
-
io.stderr.write(`cclaw internal verify-flow-state-diff: candidate state is invalid for stage "${validation.stage}".\n`);
|
|
35
|
-
}
|
|
36
|
-
return validation.ok ? 0 : 1;
|
|
37
|
-
}
|
|
38
|
-
export async function runVerifyCurrentState(projectRoot, args, io) {
|
|
39
|
-
const current = await readFlowState(projectRoot);
|
|
40
|
-
const validation = await buildValidationReport(projectRoot, current);
|
|
41
|
-
if (!args.quiet) {
|
|
42
|
-
io.stdout.write(`${JSON.stringify(validation, null, 2)}\n`);
|
|
43
|
-
}
|
|
44
|
-
if (!validation.ok) {
|
|
45
|
-
const unmetDelegations = validation.delegation.missing.length + validation.delegation.missingEvidence.length;
|
|
46
|
-
const gatesWithoutEvidence = validation.gates.issues.filter((issue) => issue.includes("missing guardEvidence entry")).length;
|
|
47
|
-
io.stderr.write(`cclaw: current stage has ${unmetDelegations} unmet mandatory delegations and ${gatesWithoutEvidence} gates without evidence.\n`);
|
|
48
|
-
io.stderr.write(`cclaw internal verify-current-state: unresolved stage constraints for "${validation.stage}".\n`);
|
|
49
|
-
}
|
|
50
|
-
return validation.ok ? 0 : 1;
|
|
51
|
-
}
|
|
52
|
-
export function firstIncompleteStageForTrack(track, completedStages) {
|
|
53
|
-
const completed = new Set(completedStages);
|
|
54
|
-
const stages = TRACK_STAGES[track];
|
|
55
|
-
return stages.find((stage) => !completed.has(stage)) ?? stages[stages.length - 1] ?? "brainstorm";
|
|
56
|
-
}
|
|
57
|
-
export function carriedCompletedStageCatalog(current, fresh, stage) {
|
|
58
|
-
const previousCatalog = current.stageGateCatalog[stage];
|
|
59
|
-
const freshCatalog = fresh.stageGateCatalog[stage];
|
|
60
|
-
const allowed = new Set([...freshCatalog.required, ...freshCatalog.recommended]);
|
|
61
|
-
const previousPassed = new Set(previousCatalog.passed.filter((gateId) => allowed.has(gateId)));
|
|
62
|
-
const previousBlocked = new Set(previousCatalog.blocked.filter((gateId) => allowed.has(gateId)));
|
|
63
|
-
const orderedAllowed = [...freshCatalog.required, ...freshCatalog.recommended];
|
|
64
|
-
const evidence = {};
|
|
65
|
-
const passed = orderedAllowed.filter((gateId) => {
|
|
66
|
-
if (!previousPassed.has(gateId))
|
|
67
|
-
return false;
|
|
68
|
-
const note = current.guardEvidence[gateId];
|
|
69
|
-
if (typeof note !== "string" || note.trim().length === 0)
|
|
70
|
-
return false;
|
|
71
|
-
evidence[gateId] = note.trim();
|
|
72
|
-
return true;
|
|
73
|
-
});
|
|
74
|
-
const passedSet = new Set(passed);
|
|
75
|
-
return {
|
|
76
|
-
catalog: {
|
|
77
|
-
required: [...freshCatalog.required],
|
|
78
|
-
recommended: [...freshCatalog.recommended],
|
|
79
|
-
conditional: [],
|
|
80
|
-
triggered: [],
|
|
81
|
-
passed,
|
|
82
|
-
blocked: orderedAllowed.filter((gateId) => previousBlocked.has(gateId) && !passedSet.has(gateId))
|
|
83
|
-
},
|
|
84
|
-
evidence
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
export function completedStageClosureEvidenceIssues(flowState) {
|
|
88
|
-
const issues = [];
|
|
89
|
-
for (const stage of flowState.completedStages) {
|
|
90
|
-
const schema = stageSchema(stage, flowState.track, flowState.discoveryMode, flowState.taskClass ?? null);
|
|
91
|
-
const catalog = flowState.stageGateCatalog[stage];
|
|
92
|
-
const required = schema.requiredGates
|
|
93
|
-
.filter((gate) => gate.tier === "required")
|
|
94
|
-
.map((gate) => gate.id);
|
|
95
|
-
for (const gateId of required) {
|
|
96
|
-
if (!catalog.passed.includes(gateId))
|
|
97
|
-
continue;
|
|
98
|
-
const note = flowState.guardEvidence[gateId];
|
|
99
|
-
if (typeof note !== "string" || note.trim().length === 0) {
|
|
100
|
-
issues.push(`completed stage "${stage}" passed gate "${gateId}" is missing guardEvidence.`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return issues;
|
|
105
|
-
}
|
|
106
|
-
export async function pathExists(projectRoot, relPath) {
|
|
107
|
-
try {
|
|
108
|
-
await fs.stat(path.join(projectRoot, relPath));
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
export async function listExistingFiles(projectRoot, relPaths) {
|
|
116
|
-
const matches = [];
|
|
117
|
-
for (const relPath of relPaths) {
|
|
118
|
-
try {
|
|
119
|
-
const stat = await fs.stat(path.join(projectRoot, relPath));
|
|
120
|
-
if (stat.isFile())
|
|
121
|
-
matches.push(relPath);
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
// continue
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return matches;
|
|
128
|
-
}
|
|
129
|
-
export async function listFilesUnder(projectRoot, relDir, limit = 20) {
|
|
130
|
-
const root = path.join(projectRoot, relDir);
|
|
131
|
-
const out = [];
|
|
132
|
-
async function walk(absDir) {
|
|
133
|
-
if (out.length >= limit)
|
|
134
|
-
return;
|
|
135
|
-
let entries;
|
|
136
|
-
try {
|
|
137
|
-
entries = await fs.readdir(absDir, { withFileTypes: true });
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
for (const entry of entries) {
|
|
143
|
-
if (out.length >= limit)
|
|
144
|
-
return;
|
|
145
|
-
if (entry.name.startsWith("."))
|
|
146
|
-
continue;
|
|
147
|
-
const abs = path.join(absDir, entry.name);
|
|
148
|
-
if (entry.isDirectory()) {
|
|
149
|
-
await walk(abs);
|
|
150
|
-
}
|
|
151
|
-
else if (entry.isFile()) {
|
|
152
|
-
out.push(path.relative(projectRoot, abs).split(path.sep).join("/"));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
await walk(root);
|
|
157
|
-
return out;
|
|
158
|
-
}
|
|
159
|
-
export async function discoverStartFlowContext(projectRoot) {
|
|
160
|
-
const lines = [];
|
|
161
|
-
const seedFiles = (await listFilesUnder(projectRoot, path.join(RUNTIME_ROOT, "seeds"), 10))
|
|
162
|
-
.filter((relPath) => /^\.cclaw\/seeds\/SEED-.*\.md$/u.test(relPath));
|
|
163
|
-
lines.push(seedFiles.length > 0
|
|
164
|
-
? `- Seed shelf scanned: ${seedFiles.join(", ")}.`
|
|
165
|
-
: "- Seed shelf scanned: no `.cclaw/seeds/SEED-*.md` files found.");
|
|
166
|
-
const originDirs = ["docs/prd", "docs/rfcs", "docs/adr", "docs/design", "specs", "prd", "rfc", "design"];
|
|
167
|
-
const originRootFiles = ["PRD.md", "SPEC.md", "DESIGN.md", "REQUIREMENTS.md", "ROADMAP.md"];
|
|
168
|
-
const originFiles = [
|
|
169
|
-
...(await listExistingFiles(projectRoot, originRootFiles)),
|
|
170
|
-
...(await Promise.all(originDirs.map((dir) => listFilesUnder(projectRoot, dir, 6)))).flat()
|
|
171
|
-
].slice(0, 20);
|
|
172
|
-
lines.push(originFiles.length > 0
|
|
173
|
-
? `- Origin docs scanned: found ${originFiles.join(", ")}.`
|
|
174
|
-
: "- Origin docs scanned: no PRD/RFC/ADR/design/spec files found in configured locations.");
|
|
175
|
-
const stackMarkers = await listExistingFiles(projectRoot, [...STACK_DISCOVERY_MARKERS]);
|
|
176
|
-
for (const markerDir of STACK_DISCOVERY_DIR_MARKERS) {
|
|
177
|
-
if (await pathExists(projectRoot, markerDir)) {
|
|
178
|
-
stackMarkers.push(`${markerDir}/`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
lines.push(stackMarkers.length > 0
|
|
182
|
-
? `- Stack markers scanned: found ${stackMarkers.join(", ")}.`
|
|
183
|
-
: "- Stack markers scanned: no root stack markers found.");
|
|
184
|
-
return lines;
|
|
185
|
-
}
|