cclaw-cli 7.7.1 → 8.1.1
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 +211 -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 +107 -511
- 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 -768
- 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 -134
- 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/harness-prompt.d.ts +26 -0
- package/dist/harness-prompt.js +142 -0
- package/dist/install.d.ts +35 -15
- package/dist/install.js +238 -1347
- 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 -44
- package/dist/execution-topology.js +0 -95
- 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 -74
- package/dist/internal/wave-status.js +0 -506
- 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,444 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { resolveArtifactPath as resolveStageArtifactPath } from "../artifact-paths.js";
|
|
4
|
-
import { exists } from "../fs-utils.js";
|
|
5
|
-
import { CONFIDENCE_FINDING_REGEX_SOURCE } from "../content/skills.js";
|
|
6
|
-
import { checkCriticPredictionsContract, evaluateInvestigationTrace, evaluateLayeredDocumentReviewStatus, evaluateQaLogFloor, extractMarkdownSectionBody, getMarkdownTableRows, meaningfulLineCount, sectionBodyByName, markdownFieldRegex } from "./shared.js";
|
|
7
|
-
const DESIGN_DIAGRAM_REQUIREMENTS = {
|
|
8
|
-
lightweight: [
|
|
9
|
-
{
|
|
10
|
-
section: "Architecture Diagram",
|
|
11
|
-
markers: ["architecture"],
|
|
12
|
-
note: "Architecture diagram is required for all tiers."
|
|
13
|
-
}
|
|
14
|
-
],
|
|
15
|
-
standard: [
|
|
16
|
-
{
|
|
17
|
-
section: "Architecture Diagram",
|
|
18
|
-
markers: ["architecture"],
|
|
19
|
-
note: "Architecture diagram is required for all tiers."
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
section: "Data-Flow Shadow Paths",
|
|
23
|
-
markers: ["data-flow-shadow-paths"],
|
|
24
|
-
note: "Standard+ requires data-flow shadow path coverage."
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
section: "Error Flow Diagram",
|
|
28
|
-
markers: ["error-flow"],
|
|
29
|
-
note: "Standard+ requires explicit error-flow rescue mapping."
|
|
30
|
-
}
|
|
31
|
-
],
|
|
32
|
-
deep: [
|
|
33
|
-
{
|
|
34
|
-
section: "Architecture Diagram",
|
|
35
|
-
markers: ["architecture"],
|
|
36
|
-
note: "Architecture diagram is required for all tiers."
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
section: "Data-Flow Shadow Paths",
|
|
40
|
-
markers: ["data-flow-shadow-paths"],
|
|
41
|
-
note: "Standard+ requires data-flow shadow path coverage."
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
section: "Error Flow Diagram",
|
|
45
|
-
markers: ["error-flow"],
|
|
46
|
-
note: "Standard+ requires explicit error-flow rescue mapping."
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
section: "Deep Diagram Add-on",
|
|
50
|
-
markers: ["state-machine", "rollback-flowchart", "deployment-sequence"],
|
|
51
|
-
note: "Deep tier requires one add-on deep diagram (state machine, rollback flowchart, or deployment sequence)."
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
};
|
|
55
|
-
function normalizeDesignDiagramTier(value) {
|
|
56
|
-
if (!value)
|
|
57
|
-
return null;
|
|
58
|
-
const normalized = value.trim().toLowerCase();
|
|
59
|
-
if (/^(?:lite|light|lightweight)$/u.test(normalized))
|
|
60
|
-
return "lightweight";
|
|
61
|
-
if (/^standard$/u.test(normalized))
|
|
62
|
-
return "standard";
|
|
63
|
-
if (/^deep$/u.test(normalized))
|
|
64
|
-
return "deep";
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
function parseApproachTierSection(sectionBody) {
|
|
68
|
-
if (!sectionBody)
|
|
69
|
-
return null;
|
|
70
|
-
for (const line of sectionBody.split(/\r?\n/u)) {
|
|
71
|
-
const cleaned = line.replace(/[*_`]/gu, "").trim();
|
|
72
|
-
const directMatch = /(?:^|\b)tier\s*:\s*(lite|lightweight|light|standard|deep)\b/iu.exec(cleaned);
|
|
73
|
-
if (directMatch) {
|
|
74
|
-
const captured = directMatch[1] ?? "";
|
|
75
|
-
const remainder = cleaned.slice(cleaned.toLowerCase().indexOf("tier") + 4);
|
|
76
|
-
const tierTokens = remainder.match(/\b(?:lite|lightweight|light|standard|deep)\b/giu) ?? [];
|
|
77
|
-
const distinct = new Set(tierTokens.map((token) => token.toLowerCase()));
|
|
78
|
-
if (distinct.size >= 2) {
|
|
79
|
-
// Multi-token line is the unfilled template placeholder
|
|
80
|
-
// (`Tier: lite | standard | deep`); treat as no decision.
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
return normalizeDesignDiagramTier(captured);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
const token = /\b(lite|lightweight|light|standard|deep)\b/iu.exec(sectionBody)?.[1] ?? null;
|
|
87
|
-
return normalizeDesignDiagramTier(token);
|
|
88
|
-
}
|
|
89
|
-
async function resolveDesignDiagramTier(projectRoot, track, designRaw) {
|
|
90
|
-
const fromDesign = parseApproachTierSection(extractMarkdownSectionBody(designRaw, "Approach Tier"));
|
|
91
|
-
if (fromDesign) {
|
|
92
|
-
return { tier: fromDesign, source: "design-artifact:Approach Tier" };
|
|
93
|
-
}
|
|
94
|
-
try {
|
|
95
|
-
const brainstormArtifact = await resolveStageArtifactPath("brainstorm", {
|
|
96
|
-
projectRoot,
|
|
97
|
-
track,
|
|
98
|
-
intent: "read"
|
|
99
|
-
});
|
|
100
|
-
if (await exists(brainstormArtifact.absPath)) {
|
|
101
|
-
const brainstormRaw = await fs.readFile(brainstormArtifact.absPath, "utf8");
|
|
102
|
-
const fromBrainstorm = parseApproachTierSection(extractMarkdownSectionBody(brainstormRaw, "Approach Tier"));
|
|
103
|
-
if (fromBrainstorm) {
|
|
104
|
-
return { tier: fromBrainstorm, source: "brainstorm-artifact:Approach Tier" };
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
// Ignore read/resolve errors and fall back to default tier.
|
|
110
|
-
}
|
|
111
|
-
return { tier: "standard", source: "default:standard" };
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* parenthetical suffixes that the audit strips
|
|
115
|
-
* from a Codebase Investigation filename cell BEFORE attempting
|
|
116
|
-
* `fs.stat`. The user's quick-tier test wrote `index.html (new)` in
|
|
117
|
-
* the table, and the linter then tried to stat the literal string
|
|
118
|
-
* `index.html (new)` (with the suffix) and failed with "could not
|
|
119
|
-
* read blast-radius file(s): index.html (new)". Authors used these
|
|
120
|
-
* markers as informational labels, not as part of the filename.
|
|
121
|
-
*
|
|
122
|
-
* Stripping happens for ANY parenthetical suffix on the same line as
|
|
123
|
-
* the filename cell so we don't have to enumerate every author
|
|
124
|
-
* convention. For new files (suffix "new"), the audit records
|
|
125
|
-
* "new file, no stale diagrams to detect" instead of trying to stat.
|
|
126
|
-
*/
|
|
127
|
-
const STALE_DIAGRAM_NEW_FILE_SUFFIX_PATTERN = /\(\s*new(?:[\s-]?file)?\s*\)/iu;
|
|
128
|
-
const STALE_DIAGRAM_SKIP_FILE_SUFFIX_PATTERN = /\(\s*(?:n\/a|skip|skipped|deleted|removed|stub|placeholder|tbd)\s*\)/iu;
|
|
129
|
-
export function normalizeCodebaseInvestigationFileRef(value, notesCell) {
|
|
130
|
-
const cleanedFull = value
|
|
131
|
-
.replace(/`/gu, "")
|
|
132
|
-
.replace(/^\s*[-*]\s*/u, "")
|
|
133
|
-
.trim();
|
|
134
|
-
if (!cleanedFull)
|
|
135
|
-
return null;
|
|
136
|
-
if (/^#/u.test(cleanedFull)) {
|
|
137
|
-
return { filename: cleanedFull.replace(/^#\s*/u, ""), raw: cleanedFull, newFile: false, skip: true };
|
|
138
|
-
}
|
|
139
|
-
// Strip ANY trailing parenthetical suffix(es) so the audit operates
|
|
140
|
-
// on the raw filename. We loop because authors sometimes stack
|
|
141
|
-
// multiple suffixes (`index.html (new) (stub)`).
|
|
142
|
-
let stripped = cleanedFull;
|
|
143
|
-
let newFile = false;
|
|
144
|
-
let skip = false;
|
|
145
|
-
for (let safety = 0; safety < 4; safety += 1) {
|
|
146
|
-
const trailingParen = /\s*\([^)]*\)\s*$/u.exec(stripped);
|
|
147
|
-
if (!trailingParen)
|
|
148
|
-
break;
|
|
149
|
-
const parenText = trailingParen[0];
|
|
150
|
-
if (STALE_DIAGRAM_NEW_FILE_SUFFIX_PATTERN.test(parenText))
|
|
151
|
-
newFile = true;
|
|
152
|
-
if (STALE_DIAGRAM_SKIP_FILE_SUFFIX_PATTERN.test(parenText))
|
|
153
|
-
skip = true;
|
|
154
|
-
stripped = stripped.slice(0, trailingParen.index).trim();
|
|
155
|
-
}
|
|
156
|
-
if (!stripped)
|
|
157
|
-
return null;
|
|
158
|
-
if (/^(?:file|n\/a|none|\(none\)|tbd|\?)$/iu.test(stripped))
|
|
159
|
-
return null;
|
|
160
|
-
// Notes column may carry an explicit `skip:` marker.
|
|
161
|
-
if (/(?:^|\s|\|)skip\s*:/iu.test(notesCell))
|
|
162
|
-
skip = true;
|
|
163
|
-
return { filename: stripped, raw: cleanedFull, newFile, skip };
|
|
164
|
-
}
|
|
165
|
-
export function collectCodebaseInvestigationFiles(sectionBody) {
|
|
166
|
-
const refs = [];
|
|
167
|
-
const seen = new Set();
|
|
168
|
-
for (const row of getMarkdownTableRows(sectionBody)) {
|
|
169
|
-
const notesCell = row[row.length - 1] ?? "";
|
|
170
|
-
const fileCell = normalizeCodebaseInvestigationFileRef(row[0] ?? "", notesCell);
|
|
171
|
-
if (!fileCell)
|
|
172
|
-
continue;
|
|
173
|
-
const key = `${fileCell.filename}|${fileCell.skip}|${fileCell.newFile}`;
|
|
174
|
-
if (seen.has(key))
|
|
175
|
-
continue;
|
|
176
|
-
seen.add(key);
|
|
177
|
-
refs.push(fileCell);
|
|
178
|
-
}
|
|
179
|
-
return refs;
|
|
180
|
-
}
|
|
181
|
-
async function runStaleDiagramAudit(projectRoot, artifactPath, artifactRaw, codebaseInvestigationBody) {
|
|
182
|
-
const markerCount = (artifactRaw.match(/<!--\s*diagram:\s*[a-z0-9-]+\s*-->/giu) ?? []).length;
|
|
183
|
-
if (markerCount === 0) {
|
|
184
|
-
return {
|
|
185
|
-
ok: false,
|
|
186
|
-
details: "No diagram markers found in design artifact; stale-diagram baseline cannot be computed."
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
let artifactStat;
|
|
190
|
-
try {
|
|
191
|
-
artifactStat = await fs.stat(artifactPath);
|
|
192
|
-
}
|
|
193
|
-
catch {
|
|
194
|
-
return {
|
|
195
|
-
ok: false,
|
|
196
|
-
details: "Cannot stat design artifact to compute diagram marker baseline."
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
const refs = collectCodebaseInvestigationFiles(codebaseInvestigationBody);
|
|
200
|
-
if (refs.length === 0) {
|
|
201
|
-
return {
|
|
202
|
-
ok: false,
|
|
203
|
-
details: "Codebase Investigation must list at least one blast-radius file for stale-diagram audit."
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
const stale = [];
|
|
207
|
-
const missing = [];
|
|
208
|
-
const newFiles = [];
|
|
209
|
-
const skipped = [];
|
|
210
|
-
let scanned = 0;
|
|
211
|
-
for (const ref of refs) {
|
|
212
|
-
if (ref.skip) {
|
|
213
|
-
skipped.push(ref.filename);
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
if (ref.newFile) {
|
|
217
|
-
newFiles.push(ref.filename);
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
const absPath = path.isAbsolute(ref.filename) ? ref.filename : path.join(projectRoot, ref.filename);
|
|
221
|
-
if (!(await exists(absPath))) {
|
|
222
|
-
missing.push(ref.filename);
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
let fileStat;
|
|
226
|
-
try {
|
|
227
|
-
fileStat = await fs.stat(absPath);
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
missing.push(ref.filename);
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
if (!fileStat.isFile())
|
|
234
|
-
continue;
|
|
235
|
-
scanned += 1;
|
|
236
|
-
if (fileStat.mtimeMs > artifactStat.mtimeMs) {
|
|
237
|
-
stale.push(ref.filename);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
if (missing.length > 0) {
|
|
241
|
-
return {
|
|
242
|
-
ok: false,
|
|
243
|
-
details: `Stale Diagram Audit could not read blast-radius file(s): ${missing.join(", ")}. Strip parenthetical suffixes like \` (new)\`, \` (deleted)\`, \` (stub)\` from the filename column, mark new files as \`<path> (new)\`, or add a leading \`#\` to the filename to skip the row.`
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
const noteParts = [];
|
|
247
|
-
if (skipped.length > 0)
|
|
248
|
-
noteParts.push(`${skipped.length} skipped (${skipped.join(", ")})`);
|
|
249
|
-
if (newFiles.length > 0)
|
|
250
|
-
noteParts.push(`${newFiles.length} new file(s) with no stale diagrams to detect (${newFiles.join(", ")})`);
|
|
251
|
-
const notes = noteParts.length > 0 ? `; ${noteParts.join("; ")}` : "";
|
|
252
|
-
if (scanned === 0 && newFiles.length === 0 && skipped.length === 0) {
|
|
253
|
-
return {
|
|
254
|
-
ok: false,
|
|
255
|
-
details: "Stale Diagram Audit found no readable blast-radius files in Codebase Investigation."
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
if (stale.length > 0) {
|
|
259
|
-
return {
|
|
260
|
-
ok: false,
|
|
261
|
-
details: `Stale Diagram Audit flagged stale file(s) newer than diagram baseline: ${stale.join(", ")}${notes}.`
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
return {
|
|
265
|
-
ok: true,
|
|
266
|
-
details: `Stale Diagram Audit clear: ${scanned} blast-radius file(s) are not newer than diagram baseline${notes}.`
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
export async function lintDesignStage(ctx) {
|
|
270
|
-
const { projectRoot, track, raw, absFile, sections, findings, parsedFrontmatter, brainstormShortCircuitBody, brainstormShortCircuitActivated, staleDiagramAuditEnabled, isTrivialOverride, activeStageFlags } = ctx;
|
|
271
|
-
evaluateInvestigationTrace(ctx, "Codebase Investigation");
|
|
272
|
-
const qaLogBody = sectionBodyByName(sections, "Q&A Log");
|
|
273
|
-
const qaLogRows = qaLogBody ? getMarkdownTableRows(qaLogBody) : [];
|
|
274
|
-
const qaLogOk = qaLogBody !== null && qaLogRows.length > 0;
|
|
275
|
-
findings.push({
|
|
276
|
-
section: "qa_log_missing",
|
|
277
|
-
required: false,
|
|
278
|
-
rule: "[P2] qa_log_missing — Q&A Log empty — confirm you actually had a dialogue with the user, not a draft from memory.",
|
|
279
|
-
found: qaLogOk,
|
|
280
|
-
details: qaLogOk
|
|
281
|
-
? `Q&A Log contains ${qaLogRows.length} data row(s).`
|
|
282
|
-
: qaLogBody === null
|
|
283
|
-
? "Missing `## Q&A Log` section."
|
|
284
|
-
: "Q&A Log is present but has zero data rows."
|
|
285
|
-
});
|
|
286
|
-
{
|
|
287
|
-
const skipQuestions = activeStageFlags.includes("--skip-questions");
|
|
288
|
-
const floor = evaluateQaLogFloor(qaLogBody, track, "design", { discoveryMode: ctx.discoveryMode, skipQuestions });
|
|
289
|
-
findings.push({
|
|
290
|
-
section: "qa_log_unconverged",
|
|
291
|
-
required: !floor.skipQuestionsAdvisory,
|
|
292
|
-
rule: "[P1] qa_log_unconverged — Q&A Log has not converged for this stage. Continue elicitation until every forcing-question topic id is tagged with `[topic:<id>]` on at least one row, the last 2 rows produce no decision-changing impact (Ralph-Loop), or an explicit user stop-signal row is appended.",
|
|
293
|
-
found: floor.ok,
|
|
294
|
-
details: floor.details
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
const criticPredictions = checkCriticPredictionsContract(sections);
|
|
298
|
-
if (criticPredictions !== null) {
|
|
299
|
-
findings.push({
|
|
300
|
-
section: "critic.predictions_missing",
|
|
301
|
-
required: false,
|
|
302
|
-
rule: "[P2] critic.predictions_missing — pre-commitment predictions block missing or empty",
|
|
303
|
-
found: criticPredictions.found,
|
|
304
|
-
details: criticPredictions.details
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
const tierResolution = await resolveDesignDiagramTier(projectRoot, track, raw);
|
|
308
|
-
const diagramTier = isTrivialOverride
|
|
309
|
-
? "lightweight"
|
|
310
|
-
: tierResolution.tier;
|
|
311
|
-
const tierSource = isTrivialOverride
|
|
312
|
-
? `${tierResolution.source}; trivial override forced lightweight`
|
|
313
|
-
: tierResolution.source;
|
|
314
|
-
const hasDiagramMarkers = /<!--\s*diagram:\s*[a-z0-9-]+\s*-->/iu.test(raw);
|
|
315
|
-
const skipDiagramRequirements = isTrivialOverride && !hasDiagramMarkers;
|
|
316
|
-
if (skipDiagramRequirements) {
|
|
317
|
-
findings.push({
|
|
318
|
-
section: "Diagram Requirement: Architecture Diagram",
|
|
319
|
-
required: true,
|
|
320
|
-
rule: "Compact trivial-override slices may omit architecture diagram markers when they intentionally skip diagram work.",
|
|
321
|
-
found: true,
|
|
322
|
-
details: "Diagram requirement skipped: compact trivial-override slice without diagram markers."
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
for (const requirement of DESIGN_DIAGRAM_REQUIREMENTS[diagramTier]) {
|
|
327
|
-
const sectionBody = sectionBodyByName(sections, requirement.section);
|
|
328
|
-
const hasSection = sectionBody !== null;
|
|
329
|
-
const matchedMarker = requirement.markers.find((marker) => {
|
|
330
|
-
const escapedMarker = marker.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
331
|
-
const markerRegex = new RegExp(`<!--\\s*diagram:\\s*${escapedMarker}\\s*-->`, "iu");
|
|
332
|
-
return sectionBody !== null && markerRegex.test(sectionBody);
|
|
333
|
-
});
|
|
334
|
-
const hasMarker = matchedMarker !== undefined;
|
|
335
|
-
const hasContent = sectionBody !== null && meaningfulLineCount(sectionBody) > 0;
|
|
336
|
-
const found = hasSection && hasMarker && hasContent;
|
|
337
|
-
const markerList = requirement.markers.map((marker) => `<!-- diagram: ${marker} -->`).join(" or ");
|
|
338
|
-
findings.push({
|
|
339
|
-
section: `Diagram Requirement: ${requirement.section}`,
|
|
340
|
-
required: true,
|
|
341
|
-
rule: `Design tier "${diagramTier}" requires "${requirement.section}" with marker ${markerList}. ${requirement.note}`,
|
|
342
|
-
found,
|
|
343
|
-
details: found
|
|
344
|
-
? `Satisfied (${tierSource}).`
|
|
345
|
-
: !hasSection
|
|
346
|
-
? `Missing section "${requirement.section}" (${tierSource}).`
|
|
347
|
-
: !hasMarker
|
|
348
|
-
? `Missing marker (${markerList}) in section "${requirement.section}" (${tierSource}).`
|
|
349
|
-
: `Section "${requirement.section}" has marker but no meaningful content (${tierSource}).`
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
if (staleDiagramAuditEnabled) {
|
|
354
|
-
if (isTrivialOverride && !hasDiagramMarkers) {
|
|
355
|
-
findings.push({
|
|
356
|
-
section: "Stale Diagram Drift Check",
|
|
357
|
-
required: true,
|
|
358
|
-
rule: "When stale-diagram audit is enabled, compact trivial-override slices may skip the drift check only if no design diagram markers are present.",
|
|
359
|
-
found: true,
|
|
360
|
-
details: "Stale Diagram Audit skipped: artifact has no diagram markers (compact trivial-override slice)."
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
const codebaseInvestigation = sectionBodyByName(sections, "Codebase Investigation");
|
|
365
|
-
if (codebaseInvestigation === null) {
|
|
366
|
-
findings.push({
|
|
367
|
-
section: "Stale Diagram Drift Check",
|
|
368
|
-
required: true,
|
|
369
|
-
rule: "When stale-diagram audit is enabled, stale diagram audit requires Codebase Investigation blast-radius files.",
|
|
370
|
-
found: false,
|
|
371
|
-
details: "No ## heading matching required section \"Codebase Investigation\"."
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
const staleAudit = await runStaleDiagramAudit(projectRoot, absFile, raw, codebaseInvestigation);
|
|
376
|
-
findings.push({
|
|
377
|
-
section: "Stale Diagram Drift Check",
|
|
378
|
-
required: true,
|
|
379
|
-
rule: "When stale-diagram audit is enabled, blast-radius files must not be newer than current design diagram baseline.",
|
|
380
|
-
found: staleAudit.ok,
|
|
381
|
-
details: staleAudit.details
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
// Universal Layer 2.3 structural checks (gstack plan-eng-review). All
|
|
387
|
-
// present-only. Validates regression iron-rule acknowledgment and
|
|
388
|
-
// confidence-calibrated finding format.
|
|
389
|
-
const regressionBody = sectionBodyByName(sections, "Regression Iron Rule");
|
|
390
|
-
if (regressionBody !== null) {
|
|
391
|
-
const ack = markdownFieldRegex("Iron rule acknowledged", "yes|true|y").test(regressionBody);
|
|
392
|
-
findings.push({
|
|
393
|
-
section: "Regression Iron Rule Acknowledgement",
|
|
394
|
-
required: false,
|
|
395
|
-
rule: "Regression Iron Rule section must affirm `Iron rule acknowledged: yes`.",
|
|
396
|
-
found: ack,
|
|
397
|
-
details: ack
|
|
398
|
-
? "Regression iron rule acknowledged."
|
|
399
|
-
: "Regression Iron Rule is missing explicit `Iron rule acknowledged: yes`."
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
const findingsBody = sectionBodyByName(sections, "Calibrated Findings");
|
|
403
|
-
if (findingsBody !== null) {
|
|
404
|
-
const isEmpty = /(^|\n)\s*-\s*None this stage\b/iu.test(findingsBody);
|
|
405
|
-
const findingRegex = new RegExp(CONFIDENCE_FINDING_REGEX_SOURCE, "u");
|
|
406
|
-
const validRows = findingsBody
|
|
407
|
-
.split("\n")
|
|
408
|
-
.filter((line) => /^[-*]\s+\[/u.test(line.trim()))
|
|
409
|
-
.filter((line) => findingRegex.test(line));
|
|
410
|
-
const ok = isEmpty || validRows.length >= 1;
|
|
411
|
-
findings.push({
|
|
412
|
-
section: "Calibrated Finding Format",
|
|
413
|
-
required: false,
|
|
414
|
-
rule: "Calibrated Findings must either declare `None this stage` or contain at least one finding in the form `[P1|P2|P3] (confidence: <n>/10) <path>[:<line>] — <description>`.",
|
|
415
|
-
found: ok,
|
|
416
|
-
details: isEmpty
|
|
417
|
-
? "No findings recorded for this stage."
|
|
418
|
-
: ok
|
|
419
|
-
? `Detected ${validRows.length} calibrated finding(s).`
|
|
420
|
-
: "No calibrated findings detected. Use `[P1|P2|P3] (confidence: <n>/10) <repo-path>[:<line>] — <description>`."
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
const layeredDocumentReview = evaluateLayeredDocumentReviewStatus(sections, CONFIDENCE_FINDING_REGEX_SOURCE);
|
|
424
|
-
if (layeredDocumentReview !== null) {
|
|
425
|
-
findings.push({
|
|
426
|
-
section: "Document Reviewer Structured Findings",
|
|
427
|
-
required: true,
|
|
428
|
-
rule: "When Layered review references coherence-reviewer/scope-guardian-reviewer/feasibility-reviewer, include explicit reviewer status plus calibrated finding lines.",
|
|
429
|
-
found: layeredDocumentReview.missingStructured.length === 0,
|
|
430
|
-
details: layeredDocumentReview.missingStructured.length === 0
|
|
431
|
-
? `Structured findings present for reviewers: ${layeredDocumentReview.triggeredReviewers.join(", ")}.`
|
|
432
|
-
: `Missing status or calibrated findings for: ${layeredDocumentReview.missingStructured.join(", ")}.`
|
|
433
|
-
});
|
|
434
|
-
findings.push({
|
|
435
|
-
section: "document-review.fail_without_waiver",
|
|
436
|
-
required: true,
|
|
437
|
-
rule: "[P1] document-review.fail_without_waiver — reviewer FAIL/PARTIAL requires fix evidence or explicit waiver.",
|
|
438
|
-
found: layeredDocumentReview.failOrPartialWithoutWaiver.length === 0,
|
|
439
|
-
details: layeredDocumentReview.failOrPartialWithoutWaiver.length === 0
|
|
440
|
-
? "No unwaived FAIL/PARTIAL reviewer statuses detected."
|
|
441
|
-
: `Unwaived FAIL/PARTIAL statuses: ${layeredDocumentReview.failOrPartialWithoutWaiver.join(", ")}.`
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { FlowStage } from "../types.js";
|
|
2
|
-
import type { LintFinding } from "./shared.js";
|
|
3
|
-
export declare const FINDINGS_CACHE_SCHEMA_VERSION = 1;
|
|
4
|
-
export type FindingStatus = {
|
|
5
|
-
kind: "new";
|
|
6
|
-
} | {
|
|
7
|
-
kind: "repeat";
|
|
8
|
-
count: number;
|
|
9
|
-
} | {
|
|
10
|
-
kind: "resolved";
|
|
11
|
-
};
|
|
12
|
-
export interface ClassifiedFinding {
|
|
13
|
-
finding: LintFinding;
|
|
14
|
-
fingerprint: string;
|
|
15
|
-
status: FindingStatus;
|
|
16
|
-
}
|
|
17
|
-
export interface ResolvedFinding {
|
|
18
|
-
fingerprint: string;
|
|
19
|
-
rule: string;
|
|
20
|
-
lastSeenAt: string;
|
|
21
|
-
}
|
|
22
|
-
export interface FindingsDedupSummary {
|
|
23
|
-
newCount: number;
|
|
24
|
-
repeatCount: number;
|
|
25
|
-
resolvedCount: number;
|
|
26
|
-
resolved: ResolvedFinding[];
|
|
27
|
-
}
|
|
28
|
-
export interface LintRunDedupResult {
|
|
29
|
-
classified: ClassifiedFinding[];
|
|
30
|
-
summary: FindingsDedupSummary;
|
|
31
|
-
header: string;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Normalize a finding detail string so volatile tokens (run IDs,
|
|
35
|
-
* timestamps, counts, hex hashes, temp paths) don't cause a finding
|
|
36
|
-
* to appear "new" on every invocation.
|
|
37
|
-
*/
|
|
38
|
-
export declare function normalizeFindingDetail(detail: string): string;
|
|
39
|
-
export declare function fingerprintFinding(stage: FlowStage, finding: LintFinding): string;
|
|
40
|
-
/**
|
|
41
|
-
* Classify each emitted finding as `new`, `repeat:N`, or `resolved`
|
|
42
|
-
* relative to the cached sidecar for this stage. Persists the updated
|
|
43
|
-
* fingerprint set under a directory lock so concurrent lint runs for
|
|
44
|
-
* the same project don't clobber each other.
|
|
45
|
-
*
|
|
46
|
-
* The returned `header` is a short human string intended for inclusion
|
|
47
|
-
* above the linter output; it's stable across runs when findings
|
|
48
|
-
* repeat. Empty string when there is nothing meaningful to report
|
|
49
|
-
* (no findings and no carry-over state).
|
|
50
|
-
*/
|
|
51
|
-
export declare function classifyAndPersistFindings(projectRoot: string, stage: FlowStage, findings: LintFinding[], options?: {
|
|
52
|
-
now?: Date;
|
|
53
|
-
}): Promise<LintRunDedupResult>;
|
|
54
|
-
export declare function buildDedupHeader(stage: FlowStage, summary: FindingsDedupSummary): string;
|
|
55
|
-
export declare function formatFindingStatusTag(status: FindingStatus): string;
|
|
56
|
-
export declare function findingsDedupCachePathFor(projectRoot: string): string;
|