cclaw-cli 7.7.1 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +210 -134
- package/dist/artifact-frontmatter.d.ts +51 -0
- package/dist/artifact-frontmatter.js +131 -0
- package/dist/artifact-paths.d.ts +7 -27
- package/dist/artifact-paths.js +20 -249
- package/dist/cancel.d.ts +16 -0
- package/dist/cancel.js +66 -0
- package/dist/cli.d.ts +2 -27
- package/dist/cli.js +90 -508
- package/dist/compound.d.ts +26 -0
- package/dist/compound.js +96 -0
- package/dist/config.d.ts +14 -51
- package/dist/config.js +23 -359
- package/dist/constants.d.ts +11 -18
- package/dist/constants.js +19 -106
- package/dist/content/antipatterns.d.ts +1 -0
- package/dist/content/antipatterns.js +109 -0
- package/dist/content/artifact-templates.d.ts +10 -0
- package/dist/content/artifact-templates.js +550 -0
- package/dist/content/cancel-command.d.ts +2 -2
- package/dist/content/cancel-command.js +25 -17
- package/dist/content/core-agents.d.ts +9 -233
- package/dist/content/core-agents.js +39 -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/install.d.ts +27 -15
- package/dist/install.js +230 -1342
- package/dist/knowledge-store.d.ts +19 -163
- package/dist/knowledge-store.js +56 -590
- package/dist/logger.d.ts +8 -3
- package/dist/logger.js +13 -4
- package/dist/orchestrator-routing.d.ts +29 -0
- package/dist/orchestrator-routing.js +156 -0
- package/dist/run-persistence.d.ts +7 -118
- package/dist/run-persistence.js +29 -845
- package/dist/runtime/run-hook.entry.d.ts +1 -3
- package/dist/runtime/run-hook.entry.js +19 -4
- package/dist/runtime/run-hook.mjs +13 -1024
- package/dist/types.d.ts +25 -261
- package/dist/types.js +8 -36
- package/package.json +6 -3
- package/dist/artifact-linter/brainstorm.d.ts +0 -2
- package/dist/artifact-linter/brainstorm.js +0 -353
- package/dist/artifact-linter/design.d.ts +0 -18
- package/dist/artifact-linter/design.js +0 -444
- package/dist/artifact-linter/findings-dedup.d.ts +0 -56
- package/dist/artifact-linter/findings-dedup.js +0 -232
- package/dist/artifact-linter/plan.d.ts +0 -2
- package/dist/artifact-linter/plan.js +0 -826
- package/dist/artifact-linter/review-army.d.ts +0 -49
- package/dist/artifact-linter/review-army.js +0 -520
- package/dist/artifact-linter/review.d.ts +0 -2
- package/dist/artifact-linter/review.js +0 -113
- package/dist/artifact-linter/scope.d.ts +0 -2
- package/dist/artifact-linter/scope.js +0 -158
- package/dist/artifact-linter/shared.d.ts +0 -637
- package/dist/artifact-linter/shared.js +0 -2163
- package/dist/artifact-linter/ship.d.ts +0 -2
- package/dist/artifact-linter/ship.js +0 -250
- package/dist/artifact-linter/spec.d.ts +0 -2
- package/dist/artifact-linter/spec.js +0 -176
- package/dist/artifact-linter/tdd.d.ts +0 -118
- package/dist/artifact-linter/tdd.js +0 -1404
- package/dist/artifact-linter.d.ts +0 -15
- package/dist/artifact-linter.js +0 -517
- package/dist/codex-feature-flag.d.ts +0 -58
- package/dist/codex-feature-flag.js +0 -193
- package/dist/content/closeout-guidance.d.ts +0 -14
- package/dist/content/closeout-guidance.js +0 -44
- package/dist/content/diff-command.d.ts +0 -1
- package/dist/content/diff-command.js +0 -43
- package/dist/content/harness-doc.d.ts +0 -1
- package/dist/content/harness-doc.js +0 -65
- package/dist/content/hook-events.d.ts +0 -9
- package/dist/content/hook-events.js +0 -23
- package/dist/content/hook-manifest.d.ts +0 -81
- package/dist/content/hook-manifest.js +0 -156
- package/dist/content/hooks.d.ts +0 -11
- package/dist/content/hooks.js +0 -1972
- package/dist/content/idea.d.ts +0 -60
- package/dist/content/idea.js +0 -416
- package/dist/content/language-policy.d.ts +0 -2
- package/dist/content/language-policy.js +0 -13
- package/dist/content/learnings.d.ts +0 -6
- package/dist/content/learnings.js +0 -141
- package/dist/content/observe.d.ts +0 -19
- package/dist/content/observe.js +0 -86
- package/dist/content/opencode-plugin.d.ts +0 -1
- package/dist/content/opencode-plugin.js +0 -635
- package/dist/content/review-prompts.d.ts +0 -1
- package/dist/content/review-prompts.js +0 -104
- package/dist/content/runtime-shared-snippets.d.ts +0 -8
- package/dist/content/runtime-shared-snippets.js +0 -80
- package/dist/content/session-hooks.d.ts +0 -7
- package/dist/content/session-hooks.js +0 -107
- package/dist/content/skills-elicitation.d.ts +0 -1
- package/dist/content/skills-elicitation.js +0 -167
- package/dist/content/stage-command.d.ts +0 -2
- package/dist/content/stage-command.js +0 -17
- package/dist/content/stage-schema.d.ts +0 -117
- package/dist/content/stage-schema.js +0 -955
- package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
- package/dist/content/stages/_lint-metadata/index.js +0 -97
- package/dist/content/stages/brainstorm.d.ts +0 -2
- package/dist/content/stages/brainstorm.js +0 -184
- package/dist/content/stages/design.d.ts +0 -2
- package/dist/content/stages/design.js +0 -288
- package/dist/content/stages/index.d.ts +0 -8
- package/dist/content/stages/index.js +0 -11
- package/dist/content/stages/plan.d.ts +0 -2
- package/dist/content/stages/plan.js +0 -191
- package/dist/content/stages/review.d.ts +0 -2
- package/dist/content/stages/review.js +0 -240
- package/dist/content/stages/schema-types.d.ts +0 -203
- package/dist/content/stages/schema-types.js +0 -1
- package/dist/content/stages/scope.d.ts +0 -2
- package/dist/content/stages/scope.js +0 -254
- package/dist/content/stages/ship.d.ts +0 -2
- package/dist/content/stages/ship.js +0 -159
- package/dist/content/stages/spec.d.ts +0 -2
- package/dist/content/stages/spec.js +0 -170
- package/dist/content/stages/tdd.d.ts +0 -4
- package/dist/content/stages/tdd.js +0 -273
- package/dist/content/state-contracts.d.ts +0 -1
- package/dist/content/state-contracts.js +0 -63
- package/dist/content/status-command.d.ts +0 -4
- package/dist/content/status-command.js +0 -109
- package/dist/content/subagent-context-skills.d.ts +0 -4
- package/dist/content/subagent-context-skills.js +0 -279
- package/dist/content/subagents.d.ts +0 -3
- package/dist/content/subagents.js +0 -997
- package/dist/content/templates.d.ts +0 -26
- package/dist/content/templates.js +0 -1692
- package/dist/content/track-render-context.d.ts +0 -18
- package/dist/content/track-render-context.js +0 -53
- package/dist/content/tree-command.d.ts +0 -1
- package/dist/content/tree-command.js +0 -64
- package/dist/content/utility-skills.d.ts +0 -30
- package/dist/content/utility-skills.js +0 -160
- package/dist/content/view-command.d.ts +0 -2
- package/dist/content/view-command.js +0 -92
- package/dist/delegation.d.ts +0 -649
- package/dist/delegation.js +0 -1539
- package/dist/early-loop.d.ts +0 -70
- package/dist/early-loop.js +0 -302
- package/dist/execution-topology.d.ts +0 -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,193 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Manage the `codex_hooks` feature flag in `~/.codex/config.toml`.
|
|
3
|
-
*
|
|
4
|
-
* Codex CLI ≥ v0.114 (Mar 2026) exposes lifecycle hooks via
|
|
5
|
-
* `.codex/hooks.json`, but the hooks engine is inert unless the user has
|
|
6
|
-
* opted into it with:
|
|
7
|
-
*
|
|
8
|
-
* ```toml
|
|
9
|
-
* [features]
|
|
10
|
-
* codex_hooks = true
|
|
11
|
-
* ```
|
|
12
|
-
*
|
|
13
|
-
* in `$CODEX_HOME/config.toml` (default: `~/.codex/config.toml`).
|
|
14
|
-
* cclaw init/sync can prompt the user to flip this flag for them; sync/runtime diagnostics report the concrete repair when it is missing;
|
|
15
|
-
* this module owns the detection / mutation code so the prompt logic in
|
|
16
|
-
* `cli.ts` stays small and testable.
|
|
17
|
-
*
|
|
18
|
-
* The TOML mutations here are intentionally surgical — we never reparse
|
|
19
|
-
* or rewrite the whole document. A deliberately narrow regex based
|
|
20
|
-
* approach lets the function stay dependency-free and preserves the
|
|
21
|
-
* user's comments, whitespace, and custom key ordering.
|
|
22
|
-
*/
|
|
23
|
-
import fs from "node:fs/promises";
|
|
24
|
-
import os from "node:os";
|
|
25
|
-
import path from "node:path";
|
|
26
|
-
/**
|
|
27
|
-
* Absolute path of the Codex config file. Respects `$CODEX_HOME` when
|
|
28
|
-
* present (the only override Codex CLI documents); falls back to
|
|
29
|
-
* `~/.codex/config.toml` otherwise.
|
|
30
|
-
*/
|
|
31
|
-
export function codexConfigPath(env = process.env) {
|
|
32
|
-
const codexHome = env.CODEX_HOME && env.CODEX_HOME.trim().length > 0
|
|
33
|
-
? env.CODEX_HOME
|
|
34
|
-
: path.join(os.homedir(), ".codex");
|
|
35
|
-
return path.join(codexHome, "config.toml");
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Inspect a TOML document and decide which of the five canonical states
|
|
39
|
-
* it represents. Comments and blank lines are ignored. Only the first
|
|
40
|
-
* `[features]` section is considered — duplicates are technically invalid
|
|
41
|
-
* TOML and Codex rejects them, so cclaw does not try to be clever there.
|
|
42
|
-
*/
|
|
43
|
-
export function classifyCodexHooksFlag(toml) {
|
|
44
|
-
if (toml === null) {
|
|
45
|
-
return "missing-file";
|
|
46
|
-
}
|
|
47
|
-
const lines = toml.split(/\r?\n/);
|
|
48
|
-
let inFeaturesSection = false;
|
|
49
|
-
let sawFeaturesHeader = false;
|
|
50
|
-
for (const rawLine of lines) {
|
|
51
|
-
const stripped = stripTomlComment(rawLine).trim();
|
|
52
|
-
if (stripped.length === 0)
|
|
53
|
-
continue;
|
|
54
|
-
const headerMatch = /^\[\s*([A-Za-z0-9_.-]+)\s*\]$/u.exec(stripped);
|
|
55
|
-
if (headerMatch) {
|
|
56
|
-
const section = headerMatch[1];
|
|
57
|
-
if (section === "features") {
|
|
58
|
-
inFeaturesSection = true;
|
|
59
|
-
sawFeaturesHeader = true;
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
inFeaturesSection = false;
|
|
63
|
-
}
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (inFeaturesSection) {
|
|
67
|
-
const keyMatch = /^codex_hooks\s*=\s*(.*)$/u.exec(stripped);
|
|
68
|
-
if (keyMatch) {
|
|
69
|
-
const value = keyMatch[1].trim().toLowerCase();
|
|
70
|
-
return value === "true" ? "enabled" : "disabled";
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (sawFeaturesHeader)
|
|
75
|
-
return "missing-key";
|
|
76
|
-
return "missing-section";
|
|
77
|
-
}
|
|
78
|
-
function stripTomlComment(line) {
|
|
79
|
-
// Naive but sufficient for our narrow use case: we only read cclaw's
|
|
80
|
-
// own writes back, and cclaw never emits `=` after a `#` inside a
|
|
81
|
-
// string literal in config.toml. If a user has complex string values
|
|
82
|
-
// with `#` inside them, worst case we trip `classifyCodexHooksFlag`
|
|
83
|
-
// and prompt them again — non-destructive.
|
|
84
|
-
const hashIndex = line.indexOf("#");
|
|
85
|
-
return hashIndex === -1 ? line : line.slice(0, hashIndex);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Return a TOML document with `[features] codex_hooks = true` set.
|
|
89
|
-
* Preserves all other content verbatim:
|
|
90
|
-
* - If the document lacks a `[features]` section, we append one at the
|
|
91
|
-
* end of the file (separated by a blank line).
|
|
92
|
-
* - If `[features]` exists without `codex_hooks`, we insert the key
|
|
93
|
-
* immediately after the header.
|
|
94
|
-
* - If `codex_hooks` exists with any non-`true` value, we rewrite
|
|
95
|
-
* just that line.
|
|
96
|
-
* - If the flag is already `true`, the input is returned unchanged.
|
|
97
|
-
*/
|
|
98
|
-
export function patchCodexHooksFlag(toml) {
|
|
99
|
-
const initial = toml ?? "";
|
|
100
|
-
const state = classifyCodexHooksFlag(toml);
|
|
101
|
-
if (state === "enabled") {
|
|
102
|
-
return { updated: initial, changed: false };
|
|
103
|
-
}
|
|
104
|
-
if (state === "missing-file" || state === "missing-section") {
|
|
105
|
-
const prefix = initial.length === 0
|
|
106
|
-
? ""
|
|
107
|
-
: initial.endsWith("\n") ? initial : `${initial}\n`;
|
|
108
|
-
const separator = initial.trim().length === 0 ? "" : "\n";
|
|
109
|
-
const block = `${separator}[features]\ncodex_hooks = true\n`;
|
|
110
|
-
return { updated: `${prefix}${block}`, changed: true };
|
|
111
|
-
}
|
|
112
|
-
if (state === "missing-key") {
|
|
113
|
-
const updated = insertKeyInFeaturesSection(initial);
|
|
114
|
-
return { updated, changed: true };
|
|
115
|
-
}
|
|
116
|
-
const updated = replaceCodexHooksLineInFeaturesSection(initial);
|
|
117
|
-
return { updated, changed: true };
|
|
118
|
-
}
|
|
119
|
-
function insertKeyInFeaturesSection(toml) {
|
|
120
|
-
// Walk into `[features]`, remember the index of the last key / non-blank
|
|
121
|
-
// line inside that section, and splice `codex_hooks = true` immediately
|
|
122
|
-
// after it. This keeps the inserted key adjacent to existing features,
|
|
123
|
-
// never stranded after a blank line or pushed down past a later section
|
|
124
|
-
// header. If `[features]` is empty, we insert right after its header.
|
|
125
|
-
const lines = toml.split(/\r?\n/);
|
|
126
|
-
let inFeaturesSection = false;
|
|
127
|
-
let featuresHeaderIndex = -1;
|
|
128
|
-
let lastFeatureKeyIndex = -1;
|
|
129
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
130
|
-
const rawLine = lines[index];
|
|
131
|
-
const stripped = stripTomlComment(rawLine).trim();
|
|
132
|
-
const headerMatch = /^\[\s*([A-Za-z0-9_.-]+)\s*\]$/u.exec(stripped);
|
|
133
|
-
if (headerMatch) {
|
|
134
|
-
if (inFeaturesSection)
|
|
135
|
-
break;
|
|
136
|
-
if (headerMatch[1] === "features") {
|
|
137
|
-
inFeaturesSection = true;
|
|
138
|
-
featuresHeaderIndex = index;
|
|
139
|
-
lastFeatureKeyIndex = index;
|
|
140
|
-
}
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
if (inFeaturesSection && stripped.length > 0) {
|
|
144
|
-
lastFeatureKeyIndex = index;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
if (featuresHeaderIndex === -1) {
|
|
148
|
-
// caller should have short-circuited before getting here; defensive
|
|
149
|
-
return toml;
|
|
150
|
-
}
|
|
151
|
-
lines.splice(lastFeatureKeyIndex + 1, 0, "codex_hooks = true");
|
|
152
|
-
const joined = lines.join("\n");
|
|
153
|
-
return joined.endsWith("\n") ? joined : `${joined}\n`;
|
|
154
|
-
}
|
|
155
|
-
function replaceCodexHooksLineInFeaturesSection(toml) {
|
|
156
|
-
const lines = toml.split(/\r?\n/);
|
|
157
|
-
let inFeaturesSection = false;
|
|
158
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
159
|
-
const rawLine = lines[index];
|
|
160
|
-
const stripped = stripTomlComment(rawLine).trim();
|
|
161
|
-
const headerMatch = /^\[\s*([A-Za-z0-9_.-]+)\s*\]$/u.exec(stripped);
|
|
162
|
-
if (headerMatch) {
|
|
163
|
-
inFeaturesSection = headerMatch[1] === "features";
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
if (inFeaturesSection && /^codex_hooks\s*=/u.test(stripped)) {
|
|
167
|
-
const indent = /^\s*/u.exec(rawLine)?.[0] ?? "";
|
|
168
|
-
lines[index] = `${indent}codex_hooks = true`;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
const joined = lines.join("\n");
|
|
172
|
-
return joined.endsWith("\n") ? joined : `${joined}\n`;
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Read the Codex config, return `null` when the file does not exist.
|
|
176
|
-
* All other read errors propagate so callers can surface a useful
|
|
177
|
-
* message instead of silently degrading.
|
|
178
|
-
*/
|
|
179
|
-
export async function readCodexConfig(configPath) {
|
|
180
|
-
try {
|
|
181
|
-
return await fs.readFile(configPath, "utf8");
|
|
182
|
-
}
|
|
183
|
-
catch (err) {
|
|
184
|
-
if (err.code === "ENOENT") {
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
throw err;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
export async function writeCodexConfig(configPath, content) {
|
|
191
|
-
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
192
|
-
await fs.writeFile(configPath, content, "utf8");
|
|
193
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared post-ship closeout wording.
|
|
3
|
-
*
|
|
4
|
-
* Keep closeout chain and ship substate language in one place across command
|
|
5
|
-
* contracts, skills, and stage/docs surfaces.
|
|
6
|
-
*/
|
|
7
|
-
export declare const CLOSEOUT_CHAIN = "post_ship_review -> archive";
|
|
8
|
-
export declare const CLOSEOUT_SUBSTATE_KEY = "closeout.shipSubstate";
|
|
9
|
-
export declare function closeoutChainInline(): string;
|
|
10
|
-
export declare function closeoutSubstateInline(): string;
|
|
11
|
-
export declare function closeoutNextCommandGuidance(): string;
|
|
12
|
-
export declare function closeoutSubstateProtocolBullets(): string;
|
|
13
|
-
export declare function closeoutFlowMapSentence(): string;
|
|
14
|
-
export declare function closeoutProtocolBehaviorSentence(): string;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared post-ship closeout wording.
|
|
3
|
-
*
|
|
4
|
-
* Keep closeout chain and ship substate language in one place across command
|
|
5
|
-
* contracts, skills, and stage/docs surfaces.
|
|
6
|
-
*/
|
|
7
|
-
export const CLOSEOUT_CHAIN = "post_ship_review -> archive";
|
|
8
|
-
export const CLOSEOUT_SUBSTATE_KEY = "closeout.shipSubstate";
|
|
9
|
-
export function closeoutChainInline() {
|
|
10
|
-
return `\`${CLOSEOUT_CHAIN}\``;
|
|
11
|
-
}
|
|
12
|
-
export function closeoutSubstateInline() {
|
|
13
|
-
return `\`${CLOSEOUT_SUBSTATE_KEY}\``;
|
|
14
|
-
}
|
|
15
|
-
export function closeoutNextCommandGuidance() {
|
|
16
|
-
return `After ship completes, the closeout chain ${closeoutChainInline()} runs automatically, driven by ${closeoutSubstateInline()}. Continue through \`/cc\`; do not branch into \`ce:compound\`, a separate operations router, or a one-off closeout command. Ralph Loop may be mentioned only as tdd carry-forward context when it explains the next \`/cc\` move; it is not part of compound/archive routing.`;
|
|
17
|
-
}
|
|
18
|
-
export function closeoutSubstateProtocolBullets() {
|
|
19
|
-
return `When \`currentStage === "ship"\`, route by **${closeoutSubstateInline()}**:
|
|
20
|
-
- \`"idle"\` or missing -> outcome: initialize closeout by setting
|
|
21
|
-
${closeoutSubstateInline()} = \`"post_ship_review"\`, then continue \`/cc\`
|
|
22
|
-
into the in-stage retro protocol (draft + one structured accept/edit/no changes ask).
|
|
23
|
-
- \`"post_ship_review"\` -> outcome: execute the unified post-ship closeout leg
|
|
24
|
-
(retro acceptance/edit/no changes + in-stage compound scan, not \`ce:compound\`)
|
|
25
|
-
and advance toward archive readiness:
|
|
26
|
-
read \`.cclaw/state/compound-readiness.json\` plus the relevant tail of
|
|
27
|
-
\`.cclaw/knowledge.jsonl\`, assess overlap before adding duplicate knowledge,
|
|
28
|
-
separate bug-track learnings (turn into rules/tests/remediation) from
|
|
29
|
-
knowledge-track learnings (durable project/process guidance), and refresh stale
|
|
30
|
-
guidance in place instead of introducing extra lineage metadata. Optionally ask
|
|
31
|
-
whether to scan Cursor/Claude/Codex
|
|
32
|
-
session transcripts for matching historical learnings; only do it after opt-in.
|
|
33
|
-
Ask **one** structured question (apply / no changes) per candidate cluster or a
|
|
34
|
-
single accept-all / no-changes choice, then advance substate.
|
|
35
|
-
- \`"ready_to_archive"\` -> outcome: continue \`/cc\` so the runtime archive step
|
|
36
|
-
executes, snapshots, and resets active state.
|
|
37
|
-
- \`"archived"\` (transient) -> outcome: report "run archived" and stop (flow complete).`;
|
|
38
|
-
}
|
|
39
|
-
export function closeoutFlowMapSentence() {
|
|
40
|
-
return `The first stage names are the critical path. \`post_ship_review\` and \`archive\` are post-ship closeout substates under ${closeoutSubstateInline()}, not separate stage schemas or commands. Continue them with \`/cc\`; do not route compound closeout through \`ce:compound\`.`;
|
|
41
|
-
}
|
|
42
|
-
export function closeoutProtocolBehaviorSentence() {
|
|
43
|
-
return `Keep decision, completion, and preamble discipline inline: ask only decision-changing questions, verify gates before advancing, and keep context compact. After \`ship\`, keep using \`/cc\` through ${closeoutChainInline()}; do not route normal closeout through \`ce:compound\` or a separate operations command. Inside \`post_ship_review\`, assess overlap before appending knowledge: refresh recurring bug-track learnings as actionable rules/tests and keep knowledge-track learnings as durable process/project guidance without extra lineage metadata.`;
|
|
44
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function diffSubcommandMarkdown(): string;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { RUNTIME_ROOT } from "../constants.js";
|
|
2
|
-
function flowStatePath() {
|
|
3
|
-
return `${RUNTIME_ROOT}/state/flow-state.json`;
|
|
4
|
-
}
|
|
5
|
-
function delegationLogPath() {
|
|
6
|
-
return `${RUNTIME_ROOT}/state/delegation-log.json`;
|
|
7
|
-
}
|
|
8
|
-
function retroArtifactPath() {
|
|
9
|
-
return `${RUNTIME_ROOT}/artifacts/09-retro.md`;
|
|
10
|
-
}
|
|
11
|
-
export function diffSubcommandMarkdown() {
|
|
12
|
-
return `# /cc-view diff
|
|
13
|
-
|
|
14
|
-
## HARD-GATE
|
|
15
|
-
|
|
16
|
-
Never mutate state from \`/cc-view diff\`. It is a read-only inspection command.
|
|
17
|
-
|
|
18
|
-
## Protocol
|
|
19
|
-
|
|
20
|
-
1. Read \`${flowStatePath()}\`.
|
|
21
|
-
2. Read \`${delegationLogPath()}\` (missing → treat as empty list).
|
|
22
|
-
3. Inspect git diff for \`${flowStatePath()}\`, \`${delegationLogPath()}\`, and \`${retroArtifactPath()}\`.
|
|
23
|
-
4. Build deltas for:
|
|
24
|
-
- stage, completed/skipped/stale sets,
|
|
25
|
-
- current-stage gate arrays (\`passed\`, \`blocked\`),
|
|
26
|
-
- \`closeout.shipSubstate\` transitions (\`from -> to\`),
|
|
27
|
-
- \`closeout.retroDraftedAt\` / \`retroAcceptedAt\` / \`retroSkipped\` flips,
|
|
28
|
-
- \`closeout.compoundPromoted\` / \`compoundSkipped\` / \`compoundCompletedAt\` flips,
|
|
29
|
-
- per-agent \`fulfillmentMode\` changes visible in delegation diffs,
|
|
30
|
-
- appearance or removal of \`${retroArtifactPath()}\` on disk.
|
|
31
|
-
5. If git has no baseline for these files, print \`baseline: unavailable (read-only mode)\`.
|
|
32
|
-
6. Print a compact diff map with explicit \`+\`, \`-\`, and \`->\` markers.
|
|
33
|
-
|
|
34
|
-
## Validation
|
|
35
|
-
|
|
36
|
-
- Diff output must be deterministic for identical states ("no visible changes").
|
|
37
|
-
- The command must not create or update any \`.cclaw/state/*.snapshot*\` file.
|
|
38
|
-
- Do not suppress removed values; removals are first-class evidence.
|
|
39
|
-
- Closeout diff lines must use the same \`shipSubstate\` vocabulary as the
|
|
40
|
-
state machine (\`idle\` / \`post_ship_review\` /
|
|
41
|
-
\`ready_to_archive\` / \`archived\`).
|
|
42
|
-
`;
|
|
43
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function harnessIntegrationDocMarkdown(): string;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { DELEGATION_DISPATCH_SURFACES, DELEGATION_DISPATCH_SURFACE_PATH_PREFIXES } from "../delegation.js";
|
|
2
|
-
import { harnessDelegationRecipes } from "../harness-adapters.js";
|
|
3
|
-
/**
|
|
4
|
-
* One-line description per `--dispatch-surface` enum value. Sourced from
|
|
5
|
-
* `src/delegation.ts::DELEGATION_DISPATCH_SURFACES` so the generated doc
|
|
6
|
-
* stays in lockstep with the runtime enum. Add a new key here whenever a
|
|
7
|
-
* new surface is introduced upstream — TypeScript's `Record` enforces it.
|
|
8
|
-
*/
|
|
9
|
-
const DISPATCH_SURFACE_DESCRIPTIONS = {
|
|
10
|
-
"claude-task": "Claude Code native Task launch against `.claude/agents/<agent-name>.md`; fulfillmentMode: `isolated`.",
|
|
11
|
-
"cursor-task": "Cursor generic Task/Subagent dispatch against `.cclaw/agents/<agent-name>.md` with a role prompt; fulfillmentMode: `generic-dispatch`. Requires non-empty `evidenceRefs` on completion.",
|
|
12
|
-
"opencode-agent": "OpenCode native subagent (`@<agent-name>` or Task) against `.opencode/agents/<agent-name>.md`; fulfillmentMode: `isolated`.",
|
|
13
|
-
"codex-agent": "OpenAI Codex CLI native custom agent against `.codex/agents/<agent-name>.toml`; fulfillmentMode: `isolated`.",
|
|
14
|
-
"generic-task": "Generic Task dispatch against `.cclaw/agents/<agent-name>.md` for harnesses without a vendor-specific surface; fulfillmentMode: `generic-dispatch`.",
|
|
15
|
-
"role-switch": "In-session role-switch fallback when no isolated dispatch surface is available. No agent-definition-path prefix is enforced; completion requires non-empty `evidenceRefs`. fulfillmentMode: `role-switch`.",
|
|
16
|
-
"manual": "Out-of-band manual dispatch (e.g. operator hand-off, external ticketing system). The agent-definition-path is intentionally free-form; recorded for audit only."
|
|
17
|
-
};
|
|
18
|
-
function dispatchSurfaceTableMarkdown() {
|
|
19
|
-
const rows = DELEGATION_DISPATCH_SURFACES
|
|
20
|
-
.map((surface) => {
|
|
21
|
-
const prefixes = DELEGATION_DISPATCH_SURFACE_PATH_PREFIXES[surface];
|
|
22
|
-
const prefixCell = prefixes.length === 0
|
|
23
|
-
? "(any)"
|
|
24
|
-
: prefixes.map((prefix) => `\`${prefix}\``).join(", ");
|
|
25
|
-
return `| \`${surface}\` | ${DISPATCH_SURFACE_DESCRIPTIONS[surface]} | ${prefixCell} |`;
|
|
26
|
-
})
|
|
27
|
-
.join("\n");
|
|
28
|
-
return `### Dispatch surfaces (\`--dispatch-surface\` enum)\n\nGenerated from \`src/delegation.ts::DELEGATION_DISPATCH_SURFACES\` and \`DELEGATION_DISPATCH_SURFACE_PATH_PREFIXES\`. Any surface not in this table is rejected by \`.cclaw/hooks/delegation-record.mjs\` with a non-zero exit. The deprecated \`task\` surface is **not** in this enum.\n\n| Surface | Purpose | Allowed agent-definition-path prefixes |\n|---|---|---|\n${rows}\n`;
|
|
29
|
-
}
|
|
30
|
-
function perHarnessRecipeMarkdown() {
|
|
31
|
-
const recipes = harnessDelegationRecipes();
|
|
32
|
-
const rows = recipes
|
|
33
|
-
.map((recipe) => `| \`${recipe.harnessId}\` | \`${recipe.dispatchSurface}\` | \`${recipe.agentDefinitionExample}\` | ${recipe.fulfillmentMode} | scheduled -> launched -> acknowledged -> completed (reuse \`<span-id>\` + \`<dispatch-id>\`; \`--ack-ts=<iso-ts>\` for completed isolated/generic) |`)
|
|
34
|
-
.join("\n");
|
|
35
|
-
const examples = recipes
|
|
36
|
-
.map((recipe) => `**${recipe.harnessId}**:\n\n` + recipe.lifecycleCommands.map((cmd) => ` ${cmd}`).join("\n"))
|
|
37
|
-
.join("\n\n");
|
|
38
|
-
return `\n\n## Per-Harness Lifecycle Recipe\n\n| Harness | Surface | Agent definition path | fulfillmentMode | Lifecycle |\n|---|---|---|---|---|\n${rows}\n\nNeutral placeholder tokens only: \`<agent-name>\`, \`<stage>\`, \`<run-id>\`, \`<span-id>\`, \`<dispatch-id>\`, \`<agent-def-path>\`, \`<iso-ts>\`, \`<artifact-anchor>\`. See \`docs/quality-gates.md\` for stage-by-stage gate mapping.\n\nThe four shipped harnesses (\`claude\`, \`cursor\`, \`opencode\`, \`codex\`) each ship with a canonical primary surface in the table above. Repair hints: \`npx cclaw-cli sync\` safely regenerates shims/plugins/agents; Codex also needs \`[features] codex_hooks = true\`; OpenCode needs \`opencode.json(.c)\` plugin registration; role-switch completions require evidenceRefs. The remaining enum values \`generic-task\`, \`role-switch\`, and \`manual\` are documented in the dispatch-surface table below and are available to any harness as fallback paths when the primary surface is unavailable.\n\n${examples}\n\n${dispatchSurfaceTableMarkdown()}\n\n### Legacy ledger upgrade\n\nPre-v3 ledger entries that lack a recorded \`dispatchSurface\` are tagged \`fulfillmentMode: "legacy-inferred"\` on read. Stage-complete blocks completion until those rows are re-recorded with the v3 helper:\n\n node .cclaw/hooks/delegation-record.mjs \\\n --rerecord \\\n --span-id=<span-id> \\\n --dispatch-id=<dispatch-id> \\\n --dispatch-surface=<surface> \\\n --agent-definition-path=<agent-def-path> \\\n --ack-ts=<iso-ts> \\\n --completed-ts=<iso-ts> \\\n --json\n\n\`--dispatch-surface\` must be one of the values listed in the dispatch-surface table above (the enum is generated verbatim from \`src/delegation.ts::DELEGATION_DISPATCH_SURFACES\`). Surfaces must align with the allowed agent-definition-path prefixes shown alongside each surface; \`role-switch\` and \`manual\` accept any path. The deprecated \`task\` surface is rejected.\n\n`;
|
|
39
|
-
}
|
|
40
|
-
function hookLayeringSectionMarkdown() {
|
|
41
|
-
return `## Hook layering
|
|
42
|
-
|
|
43
|
-
Hook behavior is intentionally split into three layers so docs, generation, and runtime checks stay in sync:
|
|
44
|
-
|
|
45
|
-
| Layer | Source of truth | Responsibility |
|
|
46
|
-
|---|---|---|
|
|
47
|
-
| 1) Manifest projection | \`src/content/hook-manifest.ts\` | Canonical handler/event map per harness. This is the authoring surface for new handlers or reroutes. |
|
|
48
|
-
| 2) JSON schema descriptors | \`src/hook-schemas/*.json\` + \`src/hook-schema.ts\` descriptor map | Declares required harness-native event arrays and schema version for each harness document. |
|
|
49
|
-
| 3) Runtime TS validation | \`src/hook-schema.ts::validateHookDocument\` + sync hook checks | Validates generated hook JSON shape/required events and reports actionable diagnostics. |
|
|
50
|
-
|
|
51
|
-
Flow:
|
|
52
|
-
1. Manifest defines handler bindings.
|
|
53
|
-
2. Hook documents are generated from manifest projections.
|
|
54
|
-
3. Schema descriptors + TS validators enforce structure at sync time.
|
|
55
|
-
`;
|
|
56
|
-
}
|
|
57
|
-
export function harnessIntegrationDocMarkdown() {
|
|
58
|
-
const head = "# Harness Integration Matrix\n\nGenerated from `src/harness-adapters.ts` capabilities and hook event mappings.";
|
|
59
|
-
return [
|
|
60
|
-
head + " For the end-to-end subagent dispatch model, proof sequence, controller/worker responsibilities, and future roadmap, see [`docs/subagent-flow.md`](./subagent-flow.md).\n\n## Capability tiers\n\n| Harness | ID | Tier | declaredSupport | runtimeLaunch | Fallback | proofRequired | proofSource | Hook surface | Structured ask |\n|---|---|---|---|---|---|---|---|---|---|\n| Claude Code | `claude` | `tier1` (full native automation) | full | native Task launch | native | spanId+dispatchId or workerRunId+ACK | `.cclaw/state/delegation-events.jsonl` + ledger | full | AskUserQuestion |\n| Cursor | `cursor` | `tier2` (supported with fallback paths) | generic | generic Task/Subagent role prompt | generic-dispatch | spanId+dispatchId/evidenceRefs | events + artifact evidenceRefs | full | AskQuestion |\n| OpenCode | `opencode` | `tier2` hooks, native dispatch declared | full | prompt-level launch via Task / `@agent` against `.opencode/agents` | native | spanId+dispatchId+ackTs+completedTs | `.opencode/agents/<agent>.md` + events | plugin | question |\n| OpenAI Codex | `codex` | `tier2` hooks, native dispatch declared | full | prompt-level request to spawn `.codex/agents` custom agents | native | spanId+dispatchId+ackTs+completedTs | `.codex/agents/<agent>.toml` + events | limited | request_user_input |\n",
|
|
61
|
-
perHarnessRecipeMarkdown(),
|
|
62
|
-
hookLayeringSectionMarkdown(),
|
|
63
|
-
"\nFallback legend:\n\n- `native` \u2014 first-class named subagent dispatch (Claude).\n- `generic-dispatch` \u2014 generic Task dispatcher mapped to cclaw roles (Cursor).\n- `role-switch` \u2014 degraded fallback for a runtime where declared native/generic dispatch is unavailable; explicit role headers, artifact outputs, and non-empty delegation-log evidenceRefs are required.\n- `waiver` \u2014 no parity path; reserved for harnesses that cannot role-switch (none shipped).\n\n## Stage-Aware Native Dispatch Workflow\n\nOpenCode and Codex receive generated native isolated subagents. Use them before considering role-switch fallback:\n\n1. Use the active stage skill's generated dispatch table as the source of truth.\n2. OpenCode: invoke `.opencode/agents/<agent>.md` via Task or `@<agent>`; Codex: ask Codex to spawn `.codex/agents/<agent>.toml` by name, in parallel when lanes are independent.\n3. Load `.cclaw/agents/<agent>.md`, execute only that role's stage task, and write outputs into the active stage artifact.\n4. Append `.cclaw/state/delegation-events.jsonl` for scheduled/launched/acknowledged/completed/failed/waived/stale, then mirror current state in `.cclaw/state/delegation-log.json`. The ledger is current state; the event log is proof/audit.\n5. Treat completed role-switch rows without `evidenceRefs` as unresolved; treat native isolated completion without matching `spanId` + `dispatchId`/`workerRunId` + `ackTs` + `completedTs` as fake isolated completion. Native isolated rows are not a role-switch substitute and should reflect a real dispatched worker.\n\nThis is staged agent work backed by the harness-native subagent surfaces. Role-switch remains only a degraded fallback when that surface is unavailable in the active runtime.\n\n## Parallel research dispatch semantics\n\nDesign-stage research fleet uses the same parity model:\n\n- **Claude / Cursor**: dispatch all four research lenses in one turn\n (stack, features, architecture, pitfalls) and synthesize into\n `.cclaw/artifacts/02a-research.md`.\n- **OpenCode / Codex**: dispatch generated native subagents for the same\n four lenses and run independent lanes in parallel where the active runtime\n permits. Use role-switch with evidence only as a degraded fallback.\n\n## Semantic hook event coverage\n\nRuntime Honesty 6.9.0 reduced the runtime to two dispatched handlers:\n`session-start` (rehydrate) and `stop-handoff` (clean handoff). Earlier\nreleases also generated `prompt-guard`, `workflow-guard`,\n`context-monitor`, `pre-compact`, and `verify-current-state` handlers, but\nthose entry points were unreachable via the dispatch table they shipped\nwith and have been removed.\n\n| Event | Claude | Cursor | OpenCode | Codex |\n|---|---|---|---|---|\n| `session_rehydrate` | SessionStart matcher startup|resume|clear|compact | sessionStart/sessionResume/sessionClear/sessionCompact | plugin event handlers + transform rehydration | SessionStart matcher startup|resume |\n| `stop_handoff` | Stop -> stop-handoff | stop -> stop-handoff | plugin session.idle -> stop-handoff | Stop -> stop-handoff |\n\n## Hook lifecycle aliases\n\nThe generated Node dispatcher accepts a small compatibility alias set for lifecycle names: `stop` and `stop-checkpoint` route to `stop-handoff`, and `session-rehydrate` routes to `session-start`. Rehydration remains the `session-start` responsibility after compact events. Harness JSON should still emit the canonical handler names from `src/content/hook-manifest.ts`.\n\n## Hook event casing\n\nHook keys are intentionally harness-native and must not be normalized:\n\n| Harness | ID | Event key casing |\n|---|---|---|\n| Claude Code | `claude` | PascalCase (`SessionStart`, `Stop`) |\n| Cursor | `cursor` | camelCase (`sessionStart`, `stop`) |\n| OpenCode | `opencode` | camelCase (`sessionStart`, `stop`) |\n| OpenAI Codex | `codex` | PascalCase (`SessionStart`, `Stop`) |\n\nUse the exact event names from each harness schema. Treating all hooks as one\nshared casing silently breaks generated wiring.\n\n## Interpretation\n\n- `tier1`: full native delegation + structured asks + full hook surface.\n- `tier2`: usable flow with capability gaps; mandatory delegation can require waivers.\n- Hook-level pre-tool blocking (prompt-guard / workflow-guard) was removed\n in 6.9.0. Stage transitions are owned by the canonical CLI path\n `node .cclaw/hooks/stage-complete.mjs <stage>`; harness sessions enforce\n workflow discipline via the iron-laws block surfaced at session-start\n rather than via per-tool hook interception.\n\n## Shared command contract\n\nAll harnesses receive the same utility commands:\n\n- `/cc` - flow entry and resume\n- `/cc` - stage progression and post-ship closeout\n- `/cc-idea` - idea mode for ranked repo-improvement backlog\n- `/cc-view` - read-only router for status/tree/diff\n\nRead-only subcommands:\n- `/cc-view status` - visual flow snapshot\n- `/cc-view tree` - deep flow tree (stages, artifacts, stale markers)\n- `/cc-view diff` - before/after flow-state diff map\n\nOperational work is handled by `/cc`, `/cc-idea`, `/cc-view`, and `node .cclaw/hooks/stage-complete.mjs <stage>` inside the installed harness runtime. `npx cclaw-cli` is the installer/support surface for init, sync, upgrade, and explicit/manual archive; the normal stage flow must not depend on a runtime `cclaw` binary in PATH.\n\nCritical-path stage order remains canonical:\n`brainstorm -> scope -> design -> spec -> plan -> tdd -> review -> ship`\n\nEvery track then closes out through:\n`post_ship_review -> archive`\n\n## Stage -> skill folder mapping\n\n| Stage | Skill folder |\n|---|---|\n| `brainstorm` | `brainstorm` |\n| `scope` | `scope` |\n| `design` | `design` |\n| `spec` | `spec` |\n| `plan` | `plan` |\n| `tdd` | `tdd` |\n| `review` | `review` |\n| `ship` | `ship` |\n\nThis map is generated from `src/constants.ts::STAGE_TO_SKILL_FOLDER` so\nskill-path naming stays explicit and stable even when stage ids differ from\nfolder names.\n\n## Install surfaces\n\nAlways generated:\n\n- `.cclaw/commands/*.md`\n- `.cclaw/skills/*/SKILL.md`\n- `.cclaw/state/*.json|*.jsonl`\n- `AGENTS.md` managed block\n\nHarness-specific additions:\n\n- `claude`: `.claude/commands/cc*.md`, `.claude/hooks/hooks.json`\n- `cursor`: `.cursor/commands/cc*.md`, `.cursor/hooks.json`, `.cursor/rules/cclaw-workflow.mdc`\n- `opencode`: `.opencode/commands/cc*.md`, `.opencode/plugins/cclaw-plugin.mjs`, opencode plugin registration with `permission.question: \"allow\"`; set `OPENCODE_ENABLE_QUESTION_TOOL=1` for ACP clients so structured asks can route through question tooling. Sync/runtime checks validate the config permission and warn when the environment hint is absent.\n- `codex`: `.agents/skills/cc/SKILL.md`, `.agents/skills/cc-idea/SKILL.md`, `.agents/skills/cc-view/SKILL.md`, `.codex/hooks.json` (Codex CLI reads `.agents/skills/` for custom skills and consumes `.codex/hooks.json` on v0.114+ when `[features] codex_hooks = true` is set in `~/.codex/config.toml`. `.codex/commands/` and the legacy `.agents/skills/cclaw-cc*/` layout from v0.39.x are auto-cleaned on sync.)\n\n## Runtime observability\n\n- `npx cclaw-cli sync` validates shim, hook, and lifecycle surfaces against this capability model.\n- `/cc-view status` and `/cc-view tree` surface the same harness tier/fallback facts from the generated runtime metadata.\n\n## Delegation Proof Model\n\nRuntime state is split deliberately:\n\n- `.cclaw/state/delegation-log.json` is the compact current ledger used by stage gates and `/cc-view` summaries.\n- `.cclaw/state/delegation-events.jsonl` is append-only audit proof for `scheduled`, `launched`, `acknowledged`, `completed`, `failed`, `waived`, and `stale` lifecycle transitions.\n- `.cclaw/state/subagents.json` is a lightweight active-worker tracker for status/tree/sync reports.\n- `.cclaw/hooks/delegation-record.mjs` is the generated helper for lifecycle rows/events. It validates required fields and emits JSON diagnostics with `--json`.\n\nIsolated completion requires `spanId`, `dispatchId` or `workerRunId`, `dispatchSurface`, `agentDefinitionPath`, `ackTs`, `launchedTs`, and `completedTs`. Cursor/generic dispatch and role-switch also require evidence refs when artifact evidence is the proof source. Legacy inferred completions remain readable, but sync reports them as warnings because they predate event-log proof.\n\n## Reference Audit Appendix\n\nStatus meanings: `deep` = read for transferable implementation contract; `targeted` = inspected the relevant files only; `skimmed` = searched/read enough to classify; `not relevant` = intentionally excluded from implementation influence.\n\n| Reference path under `<repo-relative references dir>` | Status | Findings preserved |\n|---|---|---|\n| `evanklem-evanflow/skills/evanflow-coder-overseer/SKILL.md` | deep | Contract-first coder/overseer loop, reviewer reads code rather than worker narrative, and integration overseer pattern map cleanly onto cclaw subagent guidance. |\n| `evanklem-evanflow/agents/evanflow-coder.md` | targeted | Worker role is narrow: implement the pasted contract, avoid broad orchestration, and return evidence for overseer verification. |\n| `evanklem-evanflow/agents/evanflow-overseer.md` | targeted | Overseer validates actual code and acceptance evidence before controller marks work complete. |\n| `oh-my-codex/src/agents/native-config.ts` | deep | Native agent config shape supports explicit metadata/model/tool posture; cclaw should validate generated `.codex/agents/*.toml` shape instead of trusting file presence. |\n| `oh-my-codex/src/team/state/events.ts` and `src/team/state/workers.ts` | targeted | Append-only events plus worker state are useful as separate audit/current-state layers; cclaw mirrors that with `delegation-events.jsonl` and `subagents.json`. |\n| `oh-my-openagent/src/tools/delegate-task/tools.ts` | deep | Delegation should have an explicit dispatch surface and mode instead of relying on a prose claim that an agent was launched. |\n| `oh-my-openagent/src/tools/delegate-task/subagent-resolver.ts` | targeted | Agent discovery should be checked by sync so missing/corrupt generated agent definitions are visible before dispatch. |\n| `oh-my-openagent/src/tools/delegate-task/prompt-builder.ts` | targeted | Prompt builders should include exact invocation/return contracts; cclaw generated worker prompts now carry ACK/result schemas. |\n| `giancarloerra-socraticode/**` | skimmed | Useful for workflow/e2e and graph-oriented contract testing, but not a subagent dispatch implementation reference; no runtime pattern imported. |\n| unrelated large reference trees not named above | not relevant | Searched/skipped because they did not contain flow/subagent/harness dispatch patterns relevant to this plan. |\n"
|
|
64
|
-
].join("");
|
|
65
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { HarnessId } from "../types.js";
|
|
2
|
-
import { type HookSemanticEvent } from "./hook-manifest.js";
|
|
3
|
-
export { HOOK_SEMANTIC_EVENTS, type HookSemanticEvent } from "./hook-manifest.js";
|
|
4
|
-
/**
|
|
5
|
-
* Public semantic coverage map derived from `HOOK_MANIFEST` for
|
|
6
|
-
* claude/cursor/codex, plus the static OpenCode descriptor. Consumers
|
|
7
|
-
* should treat this as read-only.
|
|
8
|
-
*/
|
|
9
|
-
export declare const HOOK_EVENTS_BY_HARNESS: Record<HarnessId, Partial<Record<HookSemanticEvent, string>>>;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { semanticEventCoverage } from "./hook-manifest.js";
|
|
2
|
-
export { HOOK_SEMANTIC_EVENTS } from "./hook-manifest.js";
|
|
3
|
-
/**
|
|
4
|
-
* OpenCode is covered by the inline plugin (`opencode-plugin.ts`), not
|
|
5
|
-
* by the generated `run-hook.mjs` dispatcher. We keep its semantic
|
|
6
|
-
* coverage table here as an explicit descriptor, since it does not
|
|
7
|
-
* flow through the hook manifest.
|
|
8
|
-
*/
|
|
9
|
-
const OPENCODE_SEMANTIC_COVERAGE = {
|
|
10
|
-
session_rehydrate: "plugin event handlers + transform rehydration",
|
|
11
|
-
stop_handoff: "plugin session.idle -> stop-handoff"
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* Public semantic coverage map derived from `HOOK_MANIFEST` for
|
|
15
|
-
* claude/cursor/codex, plus the static OpenCode descriptor. Consumers
|
|
16
|
-
* should treat this as read-only.
|
|
17
|
-
*/
|
|
18
|
-
export const HOOK_EVENTS_BY_HARNESS = Object.freeze({
|
|
19
|
-
claude: semanticEventCoverage("claude"),
|
|
20
|
-
cursor: semanticEventCoverage("cursor"),
|
|
21
|
-
codex: semanticEventCoverage("codex"),
|
|
22
|
-
opencode: OPENCODE_SEMANTIC_COVERAGE
|
|
23
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical operational manifest for cclaw hooks.
|
|
3
|
-
*
|
|
4
|
-
* This is the **single source of truth** for:
|
|
5
|
-
*
|
|
6
|
-
* - the per-harness JSON generators in `./observe.ts`
|
|
7
|
-
* (claude/cursor/codex hook documents),
|
|
8
|
-
* - the semantic coverage map in `./hook-events.ts` (docs + sync/runtime checks),
|
|
9
|
-
* - the `requiredEvents` list embedded in `src/hook-schemas/*.v1.json`
|
|
10
|
-
* (enforced by a parity test).
|
|
11
|
-
*
|
|
12
|
-
* When adding a new hook handler or rerouting an existing one, edit
|
|
13
|
-
* this file and let the downstream modules rebuild from it. Never
|
|
14
|
-
* hard-code a `SessionStart`, `PreToolUse`, etc. mapping outside of
|
|
15
|
-
* this manifest.
|
|
16
|
-
*
|
|
17
|
-
* OpenCode is deliberately out of scope here: its plugin
|
|
18
|
-
* (`opencode-plugin.ts`) implements the handlers inline rather than
|
|
19
|
-
* dispatching through `run-hook.mjs`, so its coverage is tracked
|
|
20
|
-
* separately in `HOOK_EVENTS_BY_HARNESS`.
|
|
21
|
-
*/
|
|
22
|
-
export declare const HOOK_MANIFEST_HARNESSES: readonly ["claude", "cursor", "codex"];
|
|
23
|
-
export type HookManifestHarness = (typeof HOOK_MANIFEST_HARNESSES)[number];
|
|
24
|
-
export declare const HOOK_HANDLERS: readonly ["session-start", "stop-handoff"];
|
|
25
|
-
export type HookHandlerId = (typeof HOOK_HANDLERS)[number];
|
|
26
|
-
export interface HookBinding {
|
|
27
|
-
/**
|
|
28
|
-
* Harness-native event name (exact string; PascalCase for
|
|
29
|
-
* claude/codex, camelCase for cursor). Do not normalize casing.
|
|
30
|
-
*/
|
|
31
|
-
event: string;
|
|
32
|
-
matcher?: string;
|
|
33
|
-
timeout?: number;
|
|
34
|
-
/** Optional harness UI status line while this hook runs. */
|
|
35
|
-
statusMessage?: string;
|
|
36
|
-
/**
|
|
37
|
-
* Within a single (harness, event) group, entries are sorted by
|
|
38
|
-
* `priority` ASC, ties broken by manifest-declaration order. Use
|
|
39
|
-
* this to express "this handler must run BEFORE/AFTER that handler
|
|
40
|
-
* on the same event". Default `0`.
|
|
41
|
-
*/
|
|
42
|
-
priority?: number;
|
|
43
|
-
}
|
|
44
|
-
export interface HookHandlerSpec {
|
|
45
|
-
handler: HookHandlerId;
|
|
46
|
-
description: string;
|
|
47
|
-
/**
|
|
48
|
-
* Semantic event id used by `HOOK_EVENTS_BY_HARNESS` / docs.
|
|
49
|
-
* `null` means this handler contributes no semantic coverage row.
|
|
50
|
-
*/
|
|
51
|
-
semantic: HookSemanticEvent | null;
|
|
52
|
-
bindings: Partial<Record<HookManifestHarness, HookBinding[]>>;
|
|
53
|
-
}
|
|
54
|
-
export declare const HOOK_SEMANTIC_EVENTS: readonly ["session_rehydrate", "stop_handoff"];
|
|
55
|
-
export type HookSemanticEvent = (typeof HOOK_SEMANTIC_EVENTS)[number];
|
|
56
|
-
export declare const HOOK_MANIFEST: readonly HookHandlerSpec[];
|
|
57
|
-
export interface EventGroup {
|
|
58
|
-
event: string;
|
|
59
|
-
/**
|
|
60
|
-
* Entries sorted by (priority ASC, declaration order). Default
|
|
61
|
-
* priority is 0. Stable — ties preserve manifest order.
|
|
62
|
-
*/
|
|
63
|
-
entries: Array<{
|
|
64
|
-
handler: HookHandlerId;
|
|
65
|
-
matcher?: string;
|
|
66
|
-
timeout?: number;
|
|
67
|
-
statusMessage?: string;
|
|
68
|
-
}>;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Group manifest bindings by harness-native event name. This is the
|
|
72
|
-
* core projection that observe.ts generators consume to emit the
|
|
73
|
-
* harness-specific JSON document.
|
|
74
|
-
*/
|
|
75
|
-
export declare function groupBindingsByEvent(harness: HookManifestHarness): EventGroup[];
|
|
76
|
-
/** Distinct harness-native event names covered by the manifest. */
|
|
77
|
-
export declare function requiredEventsFor(harness: HookManifestHarness): string[];
|
|
78
|
-
/**
|
|
79
|
-
* Human-readable per-harness semantic coverage used by docs and sync/runtime diagnostics.
|
|
80
|
-
*/
|
|
81
|
-
export declare function semanticEventCoverage(harness: HookManifestHarness): Partial<Record<HookSemanticEvent, string>>;
|