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.
Files changed (183) hide show
  1. package/README.md +57 -84
  2. package/dist/artifact-linter.d.ts +4 -0
  3. package/dist/artifact-linter.js +24 -3
  4. package/dist/cli.d.ts +1 -19
  5. package/dist/cli.js +49 -491
  6. package/dist/constants.d.ts +2 -13
  7. package/dist/constants.js +1 -43
  8. package/dist/content/closeout-guidance.d.ts +14 -0
  9. package/dist/content/closeout-guidance.js +42 -0
  10. package/dist/content/core-agents.js +55 -17
  11. package/dist/content/decision-protocol.d.ts +12 -0
  12. package/dist/content/decision-protocol.js +20 -0
  13. package/dist/content/diff-command.d.ts +1 -2
  14. package/dist/content/diff-command.js +8 -94
  15. package/dist/content/examples.d.ts +4 -10
  16. package/dist/content/examples.js +10 -20
  17. package/dist/content/hook-events.js +2 -2
  18. package/dist/content/hook-inline-snippets.d.ts +5 -2
  19. package/dist/content/hook-inline-snippets.js +33 -1
  20. package/dist/content/hook-manifest.d.ts +3 -4
  21. package/dist/content/hook-manifest.js +11 -12
  22. package/dist/content/hooks.js +44 -21
  23. package/dist/content/ideate-command.d.ts +2 -0
  24. package/dist/content/ideate-command.js +34 -25
  25. package/dist/content/iron-laws.d.ts +5 -5
  26. package/dist/content/iron-laws.js +5 -5
  27. package/dist/content/language-policy.d.ts +2 -0
  28. package/dist/content/language-policy.js +13 -0
  29. package/dist/content/learnings.d.ts +3 -4
  30. package/dist/content/learnings.js +26 -50
  31. package/dist/content/meta-skill.js +33 -22
  32. package/dist/content/next-command.js +41 -38
  33. package/dist/content/node-hooks.js +17 -345
  34. package/dist/content/opencode-plugin.js +5 -103
  35. package/dist/content/research-playbooks.js +14 -14
  36. package/dist/content/review-loop.d.ts +2 -0
  37. package/dist/content/review-loop.js +8 -0
  38. package/dist/content/session-hooks.js +15 -47
  39. package/dist/content/skills.d.ts +0 -5
  40. package/dist/content/skills.js +55 -128
  41. package/dist/content/stage-common-guidance.d.ts +0 -1
  42. package/dist/content/stage-common-guidance.js +17 -14
  43. package/dist/content/stage-schema.d.ts +26 -1
  44. package/dist/content/stage-schema.js +121 -40
  45. package/dist/content/stages/_lint-metadata/index.js +9 -15
  46. package/dist/content/stages/brainstorm.js +22 -43
  47. package/dist/content/stages/design.js +37 -57
  48. package/dist/content/stages/plan.js +22 -13
  49. package/dist/content/stages/review.js +24 -27
  50. package/dist/content/stages/scope.js +34 -46
  51. package/dist/content/stages/ship.js +7 -4
  52. package/dist/content/stages/spec.js +20 -9
  53. package/dist/content/stages/tdd.js +64 -44
  54. package/dist/content/start-command.js +13 -12
  55. package/dist/content/status-command.d.ts +2 -7
  56. package/dist/content/status-command.js +19 -146
  57. package/dist/content/subagents.d.ts +0 -5
  58. package/dist/content/subagents.js +51 -28
  59. package/dist/content/templates.d.ts +1 -1
  60. package/dist/content/templates.js +126 -135
  61. package/dist/content/track-render-context.d.ts +17 -0
  62. package/dist/content/track-render-context.js +44 -0
  63. package/dist/content/tree-command.d.ts +1 -2
  64. package/dist/content/tree-command.js +4 -87
  65. package/dist/content/utility-skills.d.ts +2 -29
  66. package/dist/content/utility-skills.js +2 -1534
  67. package/dist/content/view-command.js +31 -11
  68. package/dist/delegation.d.ts +1 -1
  69. package/dist/delegation.js +5 -15
  70. package/dist/doctor-registry.js +20 -21
  71. package/dist/doctor.js +88 -344
  72. package/dist/flow-state.d.ts +3 -0
  73. package/dist/flow-state.js +2 -0
  74. package/dist/harness-adapters.d.ts +1 -1
  75. package/dist/harness-adapters.js +51 -58
  76. package/dist/install.js +128 -358
  77. package/dist/internal/advance-stage.js +3 -9
  78. package/dist/internal/compound-readiness.d.ts +1 -1
  79. package/dist/internal/compound-readiness.js +1 -1
  80. package/dist/internal/tdd-loop-status.d.ts +1 -1
  81. package/dist/internal/tdd-loop-status.js +1 -1
  82. package/dist/knowledge-store.d.ts +16 -10
  83. package/dist/knowledge-store.js +51 -15
  84. package/dist/policy.js +16 -105
  85. package/dist/run-archive.d.ts +4 -6
  86. package/dist/run-archive.js +15 -20
  87. package/dist/run-persistence.d.ts +2 -2
  88. package/dist/run-persistence.js +3 -9
  89. package/package.json +1 -2
  90. package/dist/content/archive-command.d.ts +0 -2
  91. package/dist/content/archive-command.js +0 -124
  92. package/dist/content/compound-command.d.ts +0 -5
  93. package/dist/content/compound-command.js +0 -193
  94. package/dist/content/contexts.d.ts +0 -18
  95. package/dist/content/contexts.js +0 -24
  96. package/dist/content/contracts.d.ts +0 -2
  97. package/dist/content/contracts.js +0 -51
  98. package/dist/content/doctor-references.d.ts +0 -2
  99. package/dist/content/doctor-references.js +0 -150
  100. package/dist/content/eval-scaffold.d.ts +0 -15
  101. package/dist/content/eval-scaffold.js +0 -370
  102. package/dist/content/feature-command.d.ts +0 -2
  103. package/dist/content/feature-command.js +0 -123
  104. package/dist/content/flow-map.d.ts +0 -23
  105. package/dist/content/flow-map.js +0 -134
  106. package/dist/content/harness-doc.d.ts +0 -2
  107. package/dist/content/harness-doc.js +0 -202
  108. package/dist/content/harness-playbooks.d.ts +0 -24
  109. package/dist/content/harness-playbooks.js +0 -393
  110. package/dist/content/harness-tool-refs.d.ts +0 -20
  111. package/dist/content/harness-tool-refs.js +0 -268
  112. package/dist/content/ops-command.d.ts +0 -2
  113. package/dist/content/ops-command.js +0 -71
  114. package/dist/content/protocols.d.ts +0 -7
  115. package/dist/content/protocols.js +0 -215
  116. package/dist/content/retro-command.d.ts +0 -2
  117. package/dist/content/retro-command.js +0 -165
  118. package/dist/content/rewind-command.d.ts +0 -2
  119. package/dist/content/rewind-command.js +0 -106
  120. package/dist/content/tdd-log-command.d.ts +0 -2
  121. package/dist/content/tdd-log-command.js +0 -85
  122. package/dist/eval/agents/single-shot.d.ts +0 -27
  123. package/dist/eval/agents/single-shot.js +0 -79
  124. package/dist/eval/agents/with-tools.d.ts +0 -44
  125. package/dist/eval/agents/with-tools.js +0 -261
  126. package/dist/eval/agents/workflow.d.ts +0 -31
  127. package/dist/eval/agents/workflow.js +0 -155
  128. package/dist/eval/baseline.d.ts +0 -38
  129. package/dist/eval/baseline.js +0 -282
  130. package/dist/eval/config-loader.d.ts +0 -14
  131. package/dist/eval/config-loader.js +0 -395
  132. package/dist/eval/corpus.d.ts +0 -30
  133. package/dist/eval/corpus.js +0 -330
  134. package/dist/eval/cost-guard.d.ts +0 -102
  135. package/dist/eval/cost-guard.js +0 -190
  136. package/dist/eval/diff.d.ts +0 -64
  137. package/dist/eval/diff.js +0 -323
  138. package/dist/eval/llm-client.d.ts +0 -176
  139. package/dist/eval/llm-client.js +0 -267
  140. package/dist/eval/mode.d.ts +0 -28
  141. package/dist/eval/mode.js +0 -61
  142. package/dist/eval/progress.d.ts +0 -83
  143. package/dist/eval/progress.js +0 -59
  144. package/dist/eval/report.d.ts +0 -11
  145. package/dist/eval/report.js +0 -181
  146. package/dist/eval/rubric-loader.d.ts +0 -20
  147. package/dist/eval/rubric-loader.js +0 -143
  148. package/dist/eval/runner.d.ts +0 -81
  149. package/dist/eval/runner.js +0 -746
  150. package/dist/eval/runs.d.ts +0 -41
  151. package/dist/eval/runs.js +0 -114
  152. package/dist/eval/sandbox.d.ts +0 -38
  153. package/dist/eval/sandbox.js +0 -137
  154. package/dist/eval/tools/glob.d.ts +0 -2
  155. package/dist/eval/tools/glob.js +0 -163
  156. package/dist/eval/tools/grep.d.ts +0 -2
  157. package/dist/eval/tools/grep.js +0 -152
  158. package/dist/eval/tools/index.d.ts +0 -7
  159. package/dist/eval/tools/index.js +0 -35
  160. package/dist/eval/tools/read.d.ts +0 -2
  161. package/dist/eval/tools/read.js +0 -122
  162. package/dist/eval/tools/types.d.ts +0 -49
  163. package/dist/eval/tools/types.js +0 -41
  164. package/dist/eval/tools/write.d.ts +0 -2
  165. package/dist/eval/tools/write.js +0 -92
  166. package/dist/eval/types.d.ts +0 -561
  167. package/dist/eval/types.js +0 -47
  168. package/dist/eval/verifiers/judge.d.ts +0 -40
  169. package/dist/eval/verifiers/judge.js +0 -256
  170. package/dist/eval/verifiers/rules.d.ts +0 -24
  171. package/dist/eval/verifiers/rules.js +0 -218
  172. package/dist/eval/verifiers/structural.d.ts +0 -14
  173. package/dist/eval/verifiers/structural.js +0 -171
  174. package/dist/eval/verifiers/traceability.d.ts +0 -23
  175. package/dist/eval/verifiers/traceability.js +0 -84
  176. package/dist/eval/verifiers/workflow-consistency.d.ts +0 -21
  177. package/dist/eval/verifiers/workflow-consistency.js +0 -225
  178. package/dist/eval/workflow-corpus.d.ts +0 -7
  179. package/dist/eval/workflow-corpus.js +0 -207
  180. package/dist/feature-system.d.ts +0 -42
  181. package/dist/feature-system.js +0 -432
  182. package/dist/internal/knowledge-digest.d.ts +0 -7
  183. 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-checkpoint", "pre-compact", "verify-current-state"];
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", "stop_checkpoint", "precompact_digest"];
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 by
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-checkpoint",
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
- "stop_checkpoint",
38
- "precompact_digest"
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-checkpoint",
94
- description: "Persist checkpoint with stage + run context on session stop.",
95
- semantic: "stop_checkpoint",
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: "Write pre-compact digest (Claude+Cursor have a native event; Codex has no PreCompact covered by `/cc-ops retro`).",
105
- semantic: "precompact_digest",
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
- // pre-compact must capture the digest BEFORE session-start
109
- // rehydrates on cursor `sessionCompact`.
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 by
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 = {};
@@ -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, spawnSync } from "node:child_process";
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
- if (process.platform === "win32") {
62
- const probe = spawnSync("where", ["cclaw"], {
63
- cwd: root,
64
- env: process.env,
65
- stdio: "ignore"
66
- });
67
- if ((probe.status ?? 1) !== 0) {
68
- process.stderr.write(
69
- "[cclaw] stage-complete: cclaw binary not found in PATH. Install cclaw CLI and rerun stage completion.\\n"
70
- );
71
- process.exitCode = 1;
72
- return;
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
- isWindows ? "cmd.exe" : "cclaw",
79
- isWindows
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: cclaw binary not found in PATH. Install cclaw CLI and rerun stage completion.\\n"
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 cclaw internal advance-stage (" +
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
- * Structured-ask tool list reused across cclaw skills. Kept inline here (small
15
- * enough) to avoid cross-module coupling; larger stage skills cite the shared
16
- * protocol file instead.
17
- */
18
- const STRUCTURED_ASK_TOOLS = "`AskUserQuestion` on Claude, `AskQuestion` on Cursor, " +
19
- "`question` on OpenCode when `permission.question: \"allow\"` is set, " +
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 = Math.min(4, frames.length);
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 every run.
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":"brainstorm","payload":{"command":"/cc-ideate","artifact":".cclaw/artifacts/ideate-<date>-<slug>.md","recommendation":"I-1"},"emittedAt":"<ISO-8601>"}
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 = Math.min(4, frames.length);
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: "heuristic"\`
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 every run. Avoid frame-collapse
181
- (same idea rewritten 6 times). Keep raw outputs for auditability.
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
- | I-1 | Fix feature-worktree test timeouts | High | S | High | tests/unit/feature-system.test.ts:31 |
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
- ### I-1 — Fix feature-worktree test timeouts
248
- - **Evidence:** \`npm test\` hangs 40s on tests/unit/feature-system.test.ts:31.
249
- - **Counter-argument:** Fix may hide deeper orchestration race.
250
- - **Handoff:** \`/cc Fix feature-worktree test timeouts on macOS\`
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: "advisory";
83
- readonly severity: "soft-gate";
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-checkpointed";
127
- readonly title: "Stop only from clean checkpoint";
128
- readonly rule: "Do not end a session with dirty state unless checkpoint explicitly records unresolved work and blockers.";
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: "advisory",
53
- severity: "soft-gate",
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-checkpointed",
103
- title: "Stop only from clean checkpoint",
104
- rule: "Do not end a session with dirty state unless checkpoint explicitly records unresolved work and blockers.",
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,2 @@
1
+ export declare function conversationLanguagePolicyMarkdown(): string;
2
+ export declare function conversationLanguagePolicyBullets(): string;
@@ -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 (for now: `source`, `severity`) may be appended after these
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", "origin_feature", "frequency", "universality", "maturity", "created", "first_seen_ts", "last_seen_ts", "project"];
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;