cclaw-cli 0.49.0 → 0.51.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 +57 -84
- package/dist/artifact-linter.d.ts +4 -0
- package/dist/artifact-linter.js +24 -3
- package/dist/cli.d.ts +1 -19
- package/dist/cli.js +49 -491
- package/dist/constants.d.ts +2 -13
- package/dist/constants.js +1 -43
- package/dist/content/closeout-guidance.d.ts +14 -0
- package/dist/content/closeout-guidance.js +42 -0
- package/dist/content/core-agents.js +55 -17
- package/dist/content/decision-protocol.d.ts +12 -0
- package/dist/content/decision-protocol.js +20 -0
- package/dist/content/diff-command.d.ts +1 -2
- package/dist/content/diff-command.js +8 -94
- package/dist/content/examples.d.ts +4 -10
- package/dist/content/examples.js +10 -20
- package/dist/content/hook-events.js +2 -2
- package/dist/content/hook-inline-snippets.d.ts +5 -2
- package/dist/content/hook-inline-snippets.js +33 -1
- package/dist/content/hook-manifest.d.ts +3 -4
- package/dist/content/hook-manifest.js +11 -12
- package/dist/content/hooks.js +44 -21
- package/dist/content/ideate-command.d.ts +2 -0
- package/dist/content/ideate-command.js +34 -25
- package/dist/content/iron-laws.d.ts +5 -5
- package/dist/content/iron-laws.js +5 -5
- package/dist/content/language-policy.d.ts +2 -0
- package/dist/content/language-policy.js +13 -0
- package/dist/content/learnings.d.ts +3 -4
- package/dist/content/learnings.js +26 -50
- package/dist/content/meta-skill.js +33 -22
- package/dist/content/next-command.js +41 -38
- package/dist/content/node-hooks.js +17 -345
- package/dist/content/opencode-plugin.js +5 -103
- package/dist/content/research-playbooks.js +14 -14
- package/dist/content/review-loop.d.ts +2 -0
- package/dist/content/review-loop.js +8 -0
- package/dist/content/session-hooks.js +15 -47
- package/dist/content/skills.d.ts +0 -5
- package/dist/content/skills.js +55 -128
- package/dist/content/stage-common-guidance.d.ts +0 -1
- package/dist/content/stage-common-guidance.js +17 -14
- package/dist/content/stage-schema.d.ts +26 -1
- package/dist/content/stage-schema.js +121 -40
- package/dist/content/stages/_lint-metadata/index.js +9 -15
- package/dist/content/stages/brainstorm.js +22 -43
- package/dist/content/stages/design.js +37 -57
- package/dist/content/stages/plan.js +22 -13
- package/dist/content/stages/review.js +24 -27
- package/dist/content/stages/scope.js +34 -46
- package/dist/content/stages/ship.js +7 -4
- package/dist/content/stages/spec.js +20 -9
- package/dist/content/stages/tdd.js +64 -44
- package/dist/content/start-command.js +13 -12
- package/dist/content/status-command.d.ts +2 -7
- package/dist/content/status-command.js +19 -146
- package/dist/content/subagents.d.ts +0 -5
- package/dist/content/subagents.js +51 -28
- package/dist/content/templates.d.ts +1 -1
- package/dist/content/templates.js +126 -135
- package/dist/content/track-render-context.d.ts +17 -0
- package/dist/content/track-render-context.js +44 -0
- package/dist/content/tree-command.d.ts +1 -2
- package/dist/content/tree-command.js +4 -87
- package/dist/content/utility-skills.d.ts +2 -29
- package/dist/content/utility-skills.js +2 -1534
- package/dist/content/view-command.js +31 -11
- package/dist/delegation.d.ts +1 -1
- package/dist/delegation.js +5 -15
- package/dist/doctor-registry.js +20 -21
- package/dist/doctor.js +88 -344
- package/dist/flow-state.d.ts +3 -0
- package/dist/flow-state.js +2 -0
- package/dist/harness-adapters.d.ts +1 -1
- package/dist/harness-adapters.js +51 -58
- package/dist/install.js +128 -358
- package/dist/internal/advance-stage.js +3 -9
- package/dist/internal/compound-readiness.d.ts +1 -1
- package/dist/internal/compound-readiness.js +1 -1
- package/dist/internal/tdd-loop-status.d.ts +1 -1
- package/dist/internal/tdd-loop-status.js +1 -1
- package/dist/knowledge-store.d.ts +16 -10
- package/dist/knowledge-store.js +51 -15
- package/dist/policy.js +16 -105
- package/dist/run-archive.d.ts +4 -6
- package/dist/run-archive.js +15 -20
- package/dist/run-persistence.d.ts +2 -2
- package/dist/run-persistence.js +3 -9
- package/package.json +1 -2
- package/dist/content/archive-command.d.ts +0 -2
- package/dist/content/archive-command.js +0 -124
- package/dist/content/compound-command.d.ts +0 -5
- package/dist/content/compound-command.js +0 -193
- package/dist/content/contexts.d.ts +0 -18
- package/dist/content/contexts.js +0 -24
- package/dist/content/contracts.d.ts +0 -2
- package/dist/content/contracts.js +0 -51
- package/dist/content/doctor-references.d.ts +0 -2
- package/dist/content/doctor-references.js +0 -150
- package/dist/content/eval-scaffold.d.ts +0 -15
- package/dist/content/eval-scaffold.js +0 -370
- package/dist/content/feature-command.d.ts +0 -2
- package/dist/content/feature-command.js +0 -123
- package/dist/content/flow-map.d.ts +0 -23
- package/dist/content/flow-map.js +0 -134
- package/dist/content/harness-doc.d.ts +0 -2
- package/dist/content/harness-doc.js +0 -202
- package/dist/content/harness-playbooks.d.ts +0 -24
- package/dist/content/harness-playbooks.js +0 -393
- package/dist/content/harness-tool-refs.d.ts +0 -20
- package/dist/content/harness-tool-refs.js +0 -268
- package/dist/content/ops-command.d.ts +0 -2
- package/dist/content/ops-command.js +0 -71
- package/dist/content/protocols.d.ts +0 -7
- package/dist/content/protocols.js +0 -215
- package/dist/content/retro-command.d.ts +0 -2
- package/dist/content/retro-command.js +0 -165
- package/dist/content/rewind-command.d.ts +0 -2
- package/dist/content/rewind-command.js +0 -106
- package/dist/content/tdd-log-command.d.ts +0 -2
- package/dist/content/tdd-log-command.js +0 -85
- package/dist/eval/agents/single-shot.d.ts +0 -27
- package/dist/eval/agents/single-shot.js +0 -79
- package/dist/eval/agents/with-tools.d.ts +0 -44
- package/dist/eval/agents/with-tools.js +0 -261
- package/dist/eval/agents/workflow.d.ts +0 -31
- package/dist/eval/agents/workflow.js +0 -155
- package/dist/eval/baseline.d.ts +0 -38
- package/dist/eval/baseline.js +0 -282
- package/dist/eval/config-loader.d.ts +0 -14
- package/dist/eval/config-loader.js +0 -395
- package/dist/eval/corpus.d.ts +0 -30
- package/dist/eval/corpus.js +0 -330
- package/dist/eval/cost-guard.d.ts +0 -102
- package/dist/eval/cost-guard.js +0 -190
- package/dist/eval/diff.d.ts +0 -64
- package/dist/eval/diff.js +0 -323
- package/dist/eval/llm-client.d.ts +0 -176
- package/dist/eval/llm-client.js +0 -267
- package/dist/eval/mode.d.ts +0 -28
- package/dist/eval/mode.js +0 -61
- package/dist/eval/progress.d.ts +0 -83
- package/dist/eval/progress.js +0 -59
- package/dist/eval/report.d.ts +0 -11
- package/dist/eval/report.js +0 -181
- package/dist/eval/rubric-loader.d.ts +0 -20
- package/dist/eval/rubric-loader.js +0 -143
- package/dist/eval/runner.d.ts +0 -81
- package/dist/eval/runner.js +0 -746
- package/dist/eval/runs.d.ts +0 -41
- package/dist/eval/runs.js +0 -114
- package/dist/eval/sandbox.d.ts +0 -38
- package/dist/eval/sandbox.js +0 -137
- package/dist/eval/tools/glob.d.ts +0 -2
- package/dist/eval/tools/glob.js +0 -163
- package/dist/eval/tools/grep.d.ts +0 -2
- package/dist/eval/tools/grep.js +0 -152
- package/dist/eval/tools/index.d.ts +0 -7
- package/dist/eval/tools/index.js +0 -35
- package/dist/eval/tools/read.d.ts +0 -2
- package/dist/eval/tools/read.js +0 -122
- package/dist/eval/tools/types.d.ts +0 -49
- package/dist/eval/tools/types.js +0 -41
- package/dist/eval/tools/write.d.ts +0 -2
- package/dist/eval/tools/write.js +0 -92
- package/dist/eval/types.d.ts +0 -561
- package/dist/eval/types.js +0 -47
- package/dist/eval/verifiers/judge.d.ts +0 -40
- package/dist/eval/verifiers/judge.js +0 -256
- package/dist/eval/verifiers/rules.d.ts +0 -24
- package/dist/eval/verifiers/rules.js +0 -218
- package/dist/eval/verifiers/structural.d.ts +0 -14
- package/dist/eval/verifiers/structural.js +0 -171
- package/dist/eval/verifiers/traceability.d.ts +0 -23
- package/dist/eval/verifiers/traceability.js +0 -84
- package/dist/eval/verifiers/workflow-consistency.d.ts +0 -21
- package/dist/eval/verifiers/workflow-consistency.js +0 -225
- package/dist/eval/workflow-corpus.d.ts +0 -7
- package/dist/eval/workflow-corpus.js +0 -207
- package/dist/feature-system.d.ts +0 -42
- package/dist/feature-system.js +0 -432
- package/dist/internal/knowledge-digest.d.ts +0 -7
- package/dist/internal/knowledge-digest.js +0 -93
|
@@ -45,6 +45,9 @@
|
|
|
45
45
|
* - `countArchivedRunsInline` counts immediate subdirectories of
|
|
46
46
|
* `<root>/.cclaw/runs/` so both the hook and the CLI see the same
|
|
47
47
|
* `archivedRunsCount` for the small-project relaxation.
|
|
48
|
+
* - `formatCompoundReadinessLineInline` mirrors the one-line summary shape
|
|
49
|
+
* used by `src/internal/compound-readiness.ts::formatCompoundReadinessLine`
|
|
50
|
+
* so session-start and internal CLI command stay wording-compatible.
|
|
48
51
|
*/
|
|
49
52
|
export const HOOK_INLINE_SHARED_HELPERS = `
|
|
50
53
|
function normalizeCompoundLastUpdatedAt(date) {
|
|
@@ -65,6 +68,35 @@ async function countArchivedRunsInline(root) {
|
|
|
65
68
|
return undefined;
|
|
66
69
|
}
|
|
67
70
|
}
|
|
71
|
+
|
|
72
|
+
function formatCompoundReadinessLineInline(readiness) {
|
|
73
|
+
if (!readiness || typeof readiness !== "object") {
|
|
74
|
+
return "";
|
|
75
|
+
}
|
|
76
|
+
const ready = Array.isArray(readiness.ready) ? readiness.ready : [];
|
|
77
|
+
const readyCount =
|
|
78
|
+
typeof readiness.readyCount === "number" && Number.isFinite(readiness.readyCount)
|
|
79
|
+
? Math.trunc(readiness.readyCount)
|
|
80
|
+
: ready.length;
|
|
81
|
+
const clusterCount =
|
|
82
|
+
typeof readiness.clusterCount === "number" && Number.isFinite(readiness.clusterCount)
|
|
83
|
+
? Math.trunc(readiness.clusterCount)
|
|
84
|
+
: 0;
|
|
85
|
+
const threshold =
|
|
86
|
+
typeof readiness.threshold === "number" && Number.isFinite(readiness.threshold)
|
|
87
|
+
? Math.trunc(readiness.threshold)
|
|
88
|
+
: COMPOUND_RECURRENCE_THRESHOLD;
|
|
89
|
+
if (readyCount === 0) {
|
|
90
|
+
return "Compound readiness: no candidates (clusters=" +
|
|
91
|
+
String(clusterCount) + ", threshold=" + String(threshold) + ")";
|
|
92
|
+
}
|
|
93
|
+
const critical = ready.filter(
|
|
94
|
+
(entry) => entry && typeof entry === "object" && entry.severity === "critical"
|
|
95
|
+
).length;
|
|
96
|
+
const criticalSuffix = critical > 0 ? " (critical=" + String(critical) + ")" : "";
|
|
97
|
+
return "Compound readiness: clusters=" + String(clusterCount) +
|
|
98
|
+
", ready=" + String(readyCount) + criticalSuffix;
|
|
99
|
+
}
|
|
68
100
|
`;
|
|
69
101
|
/**
|
|
70
102
|
* Inline mirror of `src/knowledge-store.ts::computeCompoundReadiness`.
|
|
@@ -127,7 +159,7 @@ async function computeCompoundReadinessInline(root, options) {
|
|
|
127
159
|
let row;
|
|
128
160
|
try { row = JSON.parse(line); } catch { continue; }
|
|
129
161
|
if (!row || typeof row !== "object" || Array.isArray(row)) continue;
|
|
130
|
-
if (row.maturity === "lifted-to-enforcement") continue;
|
|
162
|
+
if (row.maturity === "lifted-to-enforcement" || typeof row.superseded_by === "string") continue;
|
|
131
163
|
const type = typeof row.type === "string" ? row.type : "";
|
|
132
164
|
const trigger = typeof row.trigger === "string" ? row.trigger : "";
|
|
133
165
|
const action = typeof row.action === "string" ? row.action : "";
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
export declare const HOOK_MANIFEST_HARNESSES: readonly ["claude", "cursor", "codex"];
|
|
23
23
|
export type HookManifestHarness = (typeof HOOK_MANIFEST_HARNESSES)[number];
|
|
24
|
-
export declare const HOOK_HANDLERS: readonly ["session-start", "prompt-guard", "workflow-guard", "context-monitor", "stop-
|
|
24
|
+
export declare const HOOK_HANDLERS: readonly ["session-start", "prompt-guard", "workflow-guard", "context-monitor", "stop-handoff", "pre-compact", "verify-current-state"];
|
|
25
25
|
export type HookHandlerId = (typeof HOOK_HANDLERS)[number];
|
|
26
26
|
export interface HookBinding {
|
|
27
27
|
/**
|
|
@@ -52,7 +52,7 @@ export interface HookHandlerSpec {
|
|
|
52
52
|
semantic: HookSemanticEvent | null;
|
|
53
53
|
bindings: Partial<Record<HookManifestHarness, HookBinding[]>>;
|
|
54
54
|
}
|
|
55
|
-
export declare const HOOK_SEMANTIC_EVENTS: readonly ["session_rehydrate", "pre_tool_prompt_guard", "pre_tool_workflow_guard", "post_tool_context_monitor", "
|
|
55
|
+
export declare const HOOK_SEMANTIC_EVENTS: readonly ["session_rehydrate", "pre_tool_prompt_guard", "pre_tool_workflow_guard", "post_tool_context_monitor", "stop_handoff", "precompact_compat"];
|
|
56
56
|
export type HookSemanticEvent = (typeof HOOK_SEMANTIC_EVENTS)[number];
|
|
57
57
|
export declare const HOOK_MANIFEST: readonly HookHandlerSpec[];
|
|
58
58
|
export interface EventGroup {
|
|
@@ -76,7 +76,6 @@ export declare function groupBindingsByEvent(harness: HookManifestHarness): Even
|
|
|
76
76
|
/** Distinct harness-native event names covered by the manifest. */
|
|
77
77
|
export declare function requiredEventsFor(harness: HookManifestHarness): string[];
|
|
78
78
|
/**
|
|
79
|
-
* Human-readable per-harness semantic coverage used by docs and
|
|
80
|
-
* the doctor's `harness-gaps.json` synthesis.
|
|
79
|
+
* Human-readable per-harness semantic coverage used by docs and doctor output.
|
|
81
80
|
*/
|
|
82
81
|
export declare function semanticEventCoverage(harness: HookManifestHarness): Partial<Record<HookSemanticEvent, string>>;
|
|
@@ -25,7 +25,7 @@ export const HOOK_HANDLERS = [
|
|
|
25
25
|
"prompt-guard",
|
|
26
26
|
"workflow-guard",
|
|
27
27
|
"context-monitor",
|
|
28
|
-
"stop-
|
|
28
|
+
"stop-handoff",
|
|
29
29
|
"pre-compact",
|
|
30
30
|
"verify-current-state"
|
|
31
31
|
];
|
|
@@ -34,8 +34,8 @@ export const HOOK_SEMANTIC_EVENTS = [
|
|
|
34
34
|
"pre_tool_prompt_guard",
|
|
35
35
|
"pre_tool_workflow_guard",
|
|
36
36
|
"post_tool_context_monitor",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
37
|
+
"stop_handoff",
|
|
38
|
+
"precompact_compat"
|
|
39
39
|
];
|
|
40
40
|
export const HOOK_MANIFEST = [
|
|
41
41
|
{
|
|
@@ -90,9 +90,9 @@ export const HOOK_MANIFEST = [
|
|
|
90
90
|
}
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
|
-
handler: "stop-
|
|
94
|
-
description: "
|
|
95
|
-
semantic: "
|
|
93
|
+
handler: "stop-handoff",
|
|
94
|
+
description: "Remind about clean handoff with stage + run context on session stop.",
|
|
95
|
+
semantic: "stop_handoff",
|
|
96
96
|
bindings: {
|
|
97
97
|
claude: [{ event: "Stop", timeout: 10 }],
|
|
98
98
|
cursor: [{ event: "stop", timeout: 10 }],
|
|
@@ -101,12 +101,12 @@ export const HOOK_MANIFEST = [
|
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
handler: "pre-compact",
|
|
104
|
-
description: "
|
|
105
|
-
semantic: "
|
|
104
|
+
description: "No-op compatibility hook for harness pre-compact events; session-start rehydrates from flow-state, artifacts, and knowledge.",
|
|
105
|
+
semantic: "precompact_compat",
|
|
106
106
|
bindings: {
|
|
107
107
|
claude: [{ event: "PreCompact", matcher: "manual|auto", timeout: 10 }],
|
|
108
|
-
//
|
|
109
|
-
//
|
|
108
|
+
// Keep this before session-start on cursor `sessionCompact` so the
|
|
109
|
+
// compatibility handler runs before rehydration.
|
|
110
110
|
cursor: [{ event: "sessionCompact", priority: -10 }]
|
|
111
111
|
}
|
|
112
112
|
},
|
|
@@ -179,8 +179,7 @@ export function requiredEventsFor(harness) {
|
|
|
179
179
|
return ordered;
|
|
180
180
|
}
|
|
181
181
|
/**
|
|
182
|
-
* Human-readable per-harness semantic coverage used by docs and
|
|
183
|
-
* the doctor's `harness-gaps.json` synthesis.
|
|
182
|
+
* Human-readable per-harness semantic coverage used by docs and doctor output.
|
|
184
183
|
*/
|
|
185
184
|
export function semanticEventCoverage(harness) {
|
|
186
185
|
const out = {};
|
package/dist/content/hooks.js
CHANGED
|
@@ -1,12 +1,31 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
1
4
|
import { RUNTIME_ROOT } from "../constants.js";
|
|
5
|
+
function resolveCliEntrypointForGeneratedHook() {
|
|
6
|
+
const here = fileURLToPath(import.meta.url);
|
|
7
|
+
const candidates = [
|
|
8
|
+
path.resolve(path.dirname(here), "..", "cli.js"),
|
|
9
|
+
path.resolve(path.dirname(here), "..", "..", "dist", "cli.js")
|
|
10
|
+
];
|
|
11
|
+
for (const candidate of candidates) {
|
|
12
|
+
// Synchronous probe runs only during cclaw-cli init/sync generation.
|
|
13
|
+
// The generated hook receives a concrete path and does not need a global bin.
|
|
14
|
+
if (existsSync(candidate))
|
|
15
|
+
return candidate;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
2
19
|
export function stageCompleteScript() {
|
|
20
|
+
const cliEntrypoint = resolveCliEntrypointForGeneratedHook();
|
|
3
21
|
return `#!/usr/bin/env node
|
|
4
22
|
import fs from "node:fs/promises";
|
|
5
23
|
import path from "node:path";
|
|
6
24
|
import process from "node:process";
|
|
7
|
-
import { spawn
|
|
25
|
+
import { spawn } from "node:child_process";
|
|
8
26
|
|
|
9
27
|
const RUNTIME_ROOT = ${JSON.stringify(RUNTIME_ROOT)};
|
|
28
|
+
const CCLAW_CLI_ENTRYPOINT = ${JSON.stringify(cliEntrypoint)};
|
|
10
29
|
|
|
11
30
|
async function detectRoot() {
|
|
12
31
|
const candidates = [
|
|
@@ -58,27 +77,29 @@ async function main() {
|
|
|
58
77
|
return;
|
|
59
78
|
}
|
|
60
79
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
const cliEntrypoint = process.env.CCLAW_CLI_JS || CCLAW_CLI_ENTRYPOINT;
|
|
81
|
+
if (!cliEntrypoint || cliEntrypoint.trim().length === 0) {
|
|
82
|
+
process.stderr.write(
|
|
83
|
+
"[cclaw] stage-complete: local Node runtime entrypoint is missing. Re-run npx cclaw-cli sync or npx cclaw-cli upgrade to regenerate hooks.\\n"
|
|
84
|
+
);
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const stat = await fs.stat(cliEntrypoint);
|
|
91
|
+
if (!stat.isFile()) throw new Error("not-file");
|
|
92
|
+
} catch {
|
|
93
|
+
process.stderr.write(
|
|
94
|
+
"[cclaw] stage-complete: local Node runtime entrypoint not found at " + cliEntrypoint + ". Re-run npx cclaw-cli sync or npx cclaw-cli upgrade to regenerate hooks.\\n"
|
|
95
|
+
);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
74
98
|
}
|
|
75
99
|
|
|
76
|
-
const isWindows = process.platform === "win32";
|
|
77
100
|
const child = spawn(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
? ["/d", "/s", "/c", "cclaw", "internal", "advance-stage", stage, ...flags]
|
|
81
|
-
: ["internal", "advance-stage", stage, ...flags],
|
|
101
|
+
process.execPath,
|
|
102
|
+
[cliEntrypoint, "internal", "advance-stage", stage, ...flags],
|
|
82
103
|
{
|
|
83
104
|
cwd: root,
|
|
84
105
|
env: process.env,
|
|
@@ -92,11 +113,11 @@ async function main() {
|
|
|
92
113
|
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
93
114
|
if (code === "ENOENT") {
|
|
94
115
|
process.stderr.write(
|
|
95
|
-
"[cclaw] stage-complete:
|
|
116
|
+
"[cclaw] stage-complete: node executable not found while invoking local runtime. Re-run npx cclaw-cli doctor.\\n"
|
|
96
117
|
);
|
|
97
118
|
} else {
|
|
98
119
|
process.stderr.write(
|
|
99
|
-
"[cclaw] stage-complete: failed to invoke
|
|
120
|
+
"[cclaw] stage-complete: failed to invoke local Node advance-stage runtime (" +
|
|
100
121
|
(error instanceof Error ? error.message : String(error)) +
|
|
101
122
|
").\\n"
|
|
102
123
|
);
|
|
@@ -134,6 +155,7 @@ set "RUNTIME=%HOOK_DIR%run-hook.mjs"
|
|
|
134
155
|
where node >nul 2>nul
|
|
135
156
|
if %ERRORLEVEL% neq 0 (
|
|
136
157
|
REM Best-effort: missing node should not block harness execution loops.
|
|
158
|
+
echo [cclaw] run-hook.cmd: node not found; cclaw hook skipped. Run npx cclaw-cli doctor. >&2
|
|
137
159
|
exit /b 0
|
|
138
160
|
)
|
|
139
161
|
node "%RUNTIME%" %*
|
|
@@ -145,6 +167,7 @@ if [ "$#" -lt 1 ]; then
|
|
|
145
167
|
exit 1
|
|
146
168
|
fi
|
|
147
169
|
if ! command -v node >/dev/null 2>&1; then
|
|
170
|
+
echo "[cclaw] run-hook.cmd: node not found; cclaw hook skipped. Run npx cclaw-cli doctor." >&2
|
|
148
171
|
exit 0
|
|
149
172
|
fi
|
|
150
173
|
exec node "\${SCRIPT_DIR}/run-hook.mjs" "$@"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type IdeateFrameId } from "./ideate-frames.js";
|
|
2
2
|
export interface IdeateCommandOptions {
|
|
3
3
|
frameIds?: readonly IdeateFrameId[];
|
|
4
|
+
mode?: "repo-grounded" | "elsewhere-software" | "elsewhere-non-software" | "narrow";
|
|
4
5
|
}
|
|
6
|
+
export declare function minimumDistinctIdeateFrames(frameCount: number, mode?: IdeateCommandOptions["mode"]): number;
|
|
5
7
|
export declare function ideateCommandContract(options?: IdeateCommandOptions): string;
|
|
6
8
|
export declare function ideateCommandSkillMarkdown(options?: IdeateCommandOptions): string;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { RUNTIME_ROOT } from "../constants.js";
|
|
2
2
|
import { resolveIdeateFrames } from "./ideate-frames.js";
|
|
3
|
+
import { ideateStructuredAskToolsWithFallback } from "./decision-protocol.js";
|
|
4
|
+
import { conversationLanguagePolicyMarkdown } from "./language-policy.js";
|
|
3
5
|
const IDEATE_SKILL_FOLDER = "flow-ideate";
|
|
4
6
|
const IDEATE_SKILL_NAME = "flow-ideate";
|
|
5
7
|
/**
|
|
@@ -10,15 +12,13 @@ const IDEATE_SKILL_NAME = "flow-ideate";
|
|
|
10
12
|
const IDEATE_ARTIFACT_GLOB = ".cclaw/artifacts/ideate-*.md";
|
|
11
13
|
const IDEATE_ARTIFACT_PATTERN = ".cclaw/artifacts/ideate-<YYYY-MM-DD-slug>.md";
|
|
12
14
|
const IDEATE_RESUME_WINDOW_DAYS = 30;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"`request_user_input` on Codex in Plan / Collaboration mode; " +
|
|
21
|
-
"fall back to a plain-text lettered list when the tool is hidden or errors";
|
|
15
|
+
const STRUCTURED_ASK_TOOLS = ideateStructuredAskToolsWithFallback();
|
|
16
|
+
export function minimumDistinctIdeateFrames(frameCount, mode = "repo-grounded") {
|
|
17
|
+
if (frameCount <= 0)
|
|
18
|
+
return 0;
|
|
19
|
+
const cap = mode === "repo-grounded" ? 4 : 2;
|
|
20
|
+
return Math.min(cap, frameCount);
|
|
21
|
+
}
|
|
22
22
|
function renderFrameBullets(frameIds) {
|
|
23
23
|
return resolveIdeateFrames(frameIds)
|
|
24
24
|
.map((frame) => ` - ${frame.label} (\`${frame.id}\`)`)
|
|
@@ -32,7 +32,7 @@ function renderFrameNames(frameIds) {
|
|
|
32
32
|
export function ideateCommandContract(options = {}) {
|
|
33
33
|
const frames = resolveIdeateFrames(options.frameIds);
|
|
34
34
|
const frameBullets = renderFrameBullets(options.frameIds);
|
|
35
|
-
const minimumDistinctFrames =
|
|
35
|
+
const minimumDistinctFrames = minimumDistinctIdeateFrames(frames.length, options.mode);
|
|
36
36
|
return `# /cc-ideate
|
|
37
37
|
|
|
38
38
|
## Purpose
|
|
@@ -44,6 +44,7 @@ same session, or save/discard the backlog.
|
|
|
44
44
|
|
|
45
45
|
## HARD-GATE
|
|
46
46
|
|
|
47
|
+
${conversationLanguagePolicyMarkdown()}
|
|
47
48
|
- Ideate mode only. Never mutate \`.cclaw/state/flow-state.json\`.
|
|
48
49
|
- Every recommendation cites evidence from the current repository
|
|
49
50
|
(file path, command output, or knowledge-store entry id).
|
|
@@ -58,8 +59,10 @@ same session, or save/discard the backlog.
|
|
|
58
59
|
has been modified within the last ${IDEATE_RESUME_WINDOW_DAYS} days,
|
|
59
60
|
offer the user: continue that backlog, start fresh, or cancel.
|
|
60
61
|
2. **Mode classification.** Explicitly classify subject:
|
|
61
|
-
\`repo-grounded\` / \`elsewhere-software\` / \`elsewhere-non-software\`.
|
|
62
|
-
Do not assume repo-grounded by default.
|
|
62
|
+
\`repo-grounded\` / \`elsewhere-software\` / \`elsewhere-non-software\` / \`narrow\`.
|
|
63
|
+
Do not assume repo-grounded by default. Repo-grounded scans keep the
|
|
64
|
+
broadest frame minimum; narrow and non-repo modes use the smaller minimum
|
|
65
|
+
shown below.
|
|
63
66
|
3. **Mode-aware grounding (parallel).**
|
|
64
67
|
- Repo-grounded: repo signal scan + \`${RUNTIME_ROOT}/knowledge.jsonl\`
|
|
65
68
|
repetition scan.
|
|
@@ -68,7 +71,9 @@ same session, or save/discard the backlog.
|
|
|
68
71
|
4. **Divergent ideation frames (parallel).** Generate candidates with
|
|
69
72
|
configured frames (${frames.length} total):
|
|
70
73
|
${frameBullets}
|
|
71
|
-
Keep at least ${minimumDistinctFrames} distinct frame outputs in
|
|
74
|
+
Keep at least ${minimumDistinctFrames} distinct frame outputs in this rendered mode.
|
|
75
|
+
Deterministic minimum: repo-grounded = 4, narrow/non-repo = 2, always capped
|
|
76
|
+
by configured frame count.
|
|
72
77
|
5. **Adversarial critique pass.** For each candidate, write the strongest
|
|
73
78
|
counter-argument, kill weak ideas, and keep survivors only.
|
|
74
79
|
6. **Produce 5-10 survivors** with impact (High/Medium/Low),
|
|
@@ -91,7 +96,7 @@ ${frameBullets}
|
|
|
91
96
|
For skill-to-skill invocation, emit exactly one JSON envelope:
|
|
92
97
|
|
|
93
98
|
\`\`\`json
|
|
94
|
-
{"version":"1","kind":"stage-output","stage":"
|
|
99
|
+
{"version":"1","kind":"stage-output","stage":"non-flow","payload":{"command":"/cc-ideate","artifact":".cclaw/artifacts/ideate-<date>-<slug>.md","recommendation":"I-1"},"emittedAt":"<ISO-8601>"}
|
|
95
100
|
\`\`\`
|
|
96
101
|
|
|
97
102
|
Validate envelopes with:
|
|
@@ -105,7 +110,7 @@ Validate envelopes with:
|
|
|
105
110
|
export function ideateCommandSkillMarkdown(options = {}) {
|
|
106
111
|
const frames = resolveIdeateFrames(options.frameIds);
|
|
107
112
|
const frameBullets = renderFrameBullets(options.frameIds);
|
|
108
|
-
const minimumDistinctFrames =
|
|
113
|
+
const minimumDistinctFrames = minimumDistinctIdeateFrames(frames.length, options.mode);
|
|
109
114
|
const frameNames = renderFrameNames(options.frameIds);
|
|
110
115
|
return `---
|
|
111
116
|
name: ${IDEATE_SKILL_NAME}
|
|
@@ -122,6 +127,7 @@ repository. Will persist a ranked backlog to
|
|
|
122
127
|
|
|
123
128
|
## HARD-GATE
|
|
124
129
|
|
|
130
|
+
${conversationLanguagePolicyMarkdown()}
|
|
125
131
|
- Do not start coding in ideate mode.
|
|
126
132
|
- Do not mutate \`.cclaw/state/flow-state.json\` — ideate mode sits outside
|
|
127
133
|
the critical-path flow.
|
|
@@ -148,6 +154,7 @@ repository. Will persist a ranked backlog to
|
|
|
148
154
|
- \`repo-grounded\` — explicitly tied to this repository.
|
|
149
155
|
- \`elsewhere-software\` — software problem not tied to this repository.
|
|
150
156
|
- \`elsewhere-non-software\` — process/business/non-software problem.
|
|
157
|
+
- \`narrow\` — a focused prompt where broad frame coverage would be performative.
|
|
151
158
|
6. Record the chosen mode in the artifact.
|
|
152
159
|
|
|
153
160
|
### Phase 1 — Mode-aware grounding
|
|
@@ -161,8 +168,7 @@ Run grounding in parallel where available:
|
|
|
161
168
|
- Module size outliers (\`wc -l\` or \`du\`) with weak direct test coverage.
|
|
162
169
|
- Docs drift: check that \`README.md\` / \`docs/\` reference files that still
|
|
163
170
|
exist and flags/APIs that still match \`src/\`.
|
|
164
|
-
- \`${RUNTIME_ROOT}/knowledge.jsonl\` entries with \`type
|
|
165
|
-
or repeated \`subject:\` values.
|
|
171
|
+
- \`${RUNTIME_ROOT}/knowledge.jsonl\` entries with recurring \`type\` in \`rule | pattern | lesson | compound\` and repeated \`trigger/action\` pairs; prefer clusters that already show stable \`origin_run\` history.
|
|
166
172
|
- For \`elsewhere-software\`:
|
|
167
173
|
- Gather current framework/library docs first.
|
|
168
174
|
- Add one comparison scan for established solutions.
|
|
@@ -177,8 +183,11 @@ Generate candidate ideas by frame, in parallel when possible:
|
|
|
177
183
|
|
|
178
184
|
${frameBullets}
|
|
179
185
|
|
|
180
|
-
Require at least ${minimumDistinctFrames} distinct frames in
|
|
181
|
-
|
|
186
|
+
Require at least ${minimumDistinctFrames} distinct frames in this rendered mode. The
|
|
187
|
+
runtime rule is deterministic: repo-grounded scans require 4 distinct frames;
|
|
188
|
+
narrow, elsewhere-software, and elsewhere-non-software runs require 2; all modes
|
|
189
|
+
are capped by the configured frame count. Avoid frame-collapse (same idea
|
|
190
|
+
rewritten many times). Keep raw outputs for auditability.
|
|
182
191
|
|
|
183
192
|
### Phase 3 — Critique all, keep survivors
|
|
184
193
|
|
|
@@ -217,7 +226,7 @@ Only survivors advance to ranking.
|
|
|
217
226
|
# Ideation — <date>
|
|
218
227
|
|
|
219
228
|
**Focus:** <user-supplied focus or "open-ended scan">
|
|
220
|
-
**Mode:** <repo-grounded | elsewhere-software | elsewhere-non-software>
|
|
229
|
+
**Mode:** <repo-grounded | elsewhere-software | elsewhere-non-software | narrow>
|
|
221
230
|
**Generated:** <ISO-8601 timestamp>
|
|
222
231
|
**Frames used:** <comma-separated list>
|
|
223
232
|
**Raw candidates:** <N>
|
|
@@ -239,15 +248,15 @@ Only survivors advance to ranking.
|
|
|
239
248
|
|
|
240
249
|
| ID | Improvement | Impact | Effort | Confidence | Evidence |
|
|
241
250
|
|---|---|---|---|---|---|
|
|
242
|
-
|
|
251
|
+
| I-1 | Simplify a confusing generated prompt surface | High | S | High | <path-to-generated-surface> |
|
|
243
252
|
| … | … | … | … | … | … |
|
|
244
253
|
|
|
245
254
|
## Candidate detail
|
|
246
255
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
256
|
+
### I-1 — Simplify a confusing generated prompt surface
|
|
257
|
+
- **Evidence:** \`<path>\` contains repeated or stale guidance that a user would see.
|
|
258
|
+
- **Counter-argument:** Trimming too hard can remove useful orientation for new users.
|
|
259
|
+
- **Handoff:** \`/cc Simplify the confusing generated prompt surface while preserving behavior\`
|
|
251
260
|
|
|
252
261
|
### I-2 — …
|
|
253
262
|
\`\`\`
|
|
@@ -79,8 +79,8 @@ export declare const IRON_LAWS: readonly [{
|
|
|
79
79
|
readonly title: "Review layers are sequential";
|
|
80
80
|
readonly rule: "Review stage must complete Layer 1 spec compliance before Layer 2 quality/security passes.";
|
|
81
81
|
readonly rationale: "Stops premature quality discussion when acceptance criteria are not yet satisfied.";
|
|
82
|
-
readonly enforcement: "
|
|
83
|
-
readonly severity: "
|
|
82
|
+
readonly enforcement: "PreToolUse";
|
|
83
|
+
readonly severity: "hard-gate";
|
|
84
84
|
readonly appliesTo: ["review"];
|
|
85
85
|
}, {
|
|
86
86
|
readonly id: "review-criticals-close-before-ship";
|
|
@@ -123,9 +123,9 @@ export declare const IRON_LAWS: readonly [{
|
|
|
123
123
|
readonly severity: "hard-gate";
|
|
124
124
|
readonly appliesTo: "all";
|
|
125
125
|
}, {
|
|
126
|
-
readonly id: "stop-clean-or-
|
|
127
|
-
readonly title: "Stop only from clean
|
|
128
|
-
readonly rule: "Do not end a session with dirty state unless
|
|
126
|
+
readonly id: "stop-clean-or-handoff";
|
|
127
|
+
readonly title: "Stop only from clean handoff";
|
|
128
|
+
readonly rule: "Do not end a session with dirty state unless the current artifact records unresolved work and blockers.";
|
|
129
129
|
readonly rationale: "Protects continuity and prevents silent half-finished sessions.";
|
|
130
130
|
readonly enforcement: "Stop";
|
|
131
131
|
readonly severity: "hard-gate";
|
|
@@ -49,8 +49,8 @@ export const IRON_LAWS = [
|
|
|
49
49
|
title: "Review layers are sequential",
|
|
50
50
|
rule: "Review stage must complete Layer 1 spec compliance before Layer 2 quality/security passes.",
|
|
51
51
|
rationale: "Stops premature quality discussion when acceptance criteria are not yet satisfied.",
|
|
52
|
-
enforcement: "
|
|
53
|
-
severity: "
|
|
52
|
+
enforcement: "PreToolUse",
|
|
53
|
+
severity: "hard-gate",
|
|
54
54
|
appliesTo: ["review"]
|
|
55
55
|
},
|
|
56
56
|
{
|
|
@@ -99,9 +99,9 @@ export const IRON_LAWS = [
|
|
|
99
99
|
appliesTo: "all"
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
|
-
id: "stop-clean-or-
|
|
103
|
-
title: "Stop only from clean
|
|
104
|
-
rule: "Do not end a session with dirty state unless
|
|
102
|
+
id: "stop-clean-or-handoff",
|
|
103
|
+
title: "Stop only from clean handoff",
|
|
104
|
+
rule: "Do not end a session with dirty state unless the current artifact records unresolved work and blockers.",
|
|
105
105
|
rationale: "Protects continuity and prevents silent half-finished sessions.",
|
|
106
106
|
enforcement: "Stop",
|
|
107
107
|
severity: "hard-gate",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function conversationLanguagePolicyMarkdown() {
|
|
2
|
+
return `## Conversation Language Policy
|
|
3
|
+
|
|
4
|
+
- Infer the user-facing language from the latest substantive user message.
|
|
5
|
+
- Write user-facing prose, summaries, recommendations, and structured question text/options in that language unless the user asks otherwise.
|
|
6
|
+
- Do not translate stable machine surfaces: commands, file paths, stage ids, gate ids, JSON keys, enum/status values, artifact headings/frontmatter, logs, code identifiers, and quoted source text.
|
|
7
|
+
- If the request mixes languages, use the language of the actual ask sentence for narrative output.
|
|
8
|
+
`;
|
|
9
|
+
}
|
|
10
|
+
export function conversationLanguagePolicyBullets() {
|
|
11
|
+
return `- User-facing narrative follows the latest substantive user message language.
|
|
12
|
+
- Do not translate commands, paths, ids, JSON keys/enums, artifact headings, logs, code identifiers, or quoted source.`;
|
|
13
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Canonical required JSONL field order (matches strict validator keys).
|
|
3
|
-
* Optional keys (
|
|
4
|
-
* required fields.
|
|
3
|
+
* Optional keys (`source`, `severity`, `supersedes`, `superseded_by`) may
|
|
4
|
+
* be appended after these required fields.
|
|
5
5
|
* Exported for tests and any programmatic writer that wants a stable base shape.
|
|
6
6
|
*/
|
|
7
|
-
export declare const KNOWLEDGE_JSONL_FIELDS: readonly ["type", "trigger", "action", "confidence", "domain", "stage", "origin_stage", "
|
|
7
|
+
export declare const KNOWLEDGE_JSONL_FIELDS: readonly ["type", "trigger", "action", "confidence", "domain", "stage", "origin_stage", "origin_run", "frequency", "universality", "maturity", "created", "first_seen_ts", "last_seen_ts", "project"];
|
|
8
8
|
export declare function learnSkillMarkdown(): string;
|
|
9
|
-
export declare function learnCommandContract(): string;
|