continuous-improvement 3.1.0 → 3.9.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 (136) hide show
  1. package/.claude-plugin/marketplace.json +66 -0
  2. package/CHANGELOG.md +216 -0
  3. package/QUICKSTART.md +79 -12
  4. package/README.md +229 -349
  5. package/SKILL.md +87 -9
  6. package/action.yml +1 -1
  7. package/bin/analyze.sh +9 -1
  8. package/bin/backfill.mjs +172 -0
  9. package/bin/check-doc-runtime-claims.mjs +120 -0
  10. package/bin/check-docs-substrings.mjs +333 -0
  11. package/bin/check-everything-mirror.mjs +145 -0
  12. package/bin/check-routing-targets.mjs +151 -0
  13. package/bin/check-skill-law-tag.mjs +128 -0
  14. package/bin/check-skill-mirror.mjs +119 -0
  15. package/bin/check-skill-tiers.mjs +116 -0
  16. package/bin/check-third-party-shape.mjs +202 -0
  17. package/bin/generate-plugin-manifests.mjs +171 -0
  18. package/bin/harvest-friction.mjs +279 -0
  19. package/bin/hook-stats.mjs +258 -0
  20. package/bin/install.mjs +407 -499
  21. package/bin/lint-transcript.mjs +182 -210
  22. package/bin/mcp-server.mjs +834 -608
  23. package/bin/observe.mjs +148 -0
  24. package/bin/pre-commit-block-strays.sh +49 -0
  25. package/bin/refresh-third-party.mjs +416 -0
  26. package/bin/unified-cli.mjs +533 -0
  27. package/commands/continuous-improvement.md +43 -2
  28. package/commands/discipline.md +14 -0
  29. package/commands/harvest.md +76 -0
  30. package/commands/learn-eval.md +117 -0
  31. package/commands/planning-with-files.md +66 -0
  32. package/commands/proceed-with-the-recommendation.md +62 -0
  33. package/commands/ralph.md +103 -0
  34. package/commands/release-train.md +81 -0
  35. package/commands/seven-laws.md +16 -0
  36. package/commands/superpowers.md +180 -0
  37. package/commands/swarm.md +101 -0
  38. package/commands/workspace-surface-audit.md +77 -0
  39. package/hooks/gateguard.mjs +172 -0
  40. package/hooks/observe.sh +42 -4
  41. package/hooks/session.sh +3 -3
  42. package/hooks/three-section-close.mjs +181 -0
  43. package/instinct-packs/meta.json +16 -0
  44. package/lib/cli-anything.mjs +401 -0
  45. package/lib/compound-engineering.mjs +831 -0
  46. package/lib/gateguard-state.mjs +85 -0
  47. package/lib/observe-event.mjs +128 -0
  48. package/lib/plugin-metadata.mjs +435 -0
  49. package/lib/pm-marketplace.mjs +61 -0
  50. package/lib/pm-skills.mjs +1274 -0
  51. package/lib/resolve-home-dir.mjs +43 -0
  52. package/lib/skill-tiers.mjs +137 -0
  53. package/lib/unified-plugin.mjs +924 -0
  54. package/llms.txt +32 -7
  55. package/package.json +29 -19
  56. package/plugins/beginner.json +17 -6
  57. package/plugins/continuous-improvement/.claude-plugin/marketplace.json +20 -0
  58. package/plugins/continuous-improvement/.claude-plugin/plugin.json +26 -0
  59. package/plugins/continuous-improvement/LICENSE +21 -0
  60. package/plugins/continuous-improvement/README.md +57 -0
  61. package/plugins/continuous-improvement/agents/README.md +120 -0
  62. package/plugins/continuous-improvement/agents/code-reviewer.md +97 -0
  63. package/plugins/continuous-improvement/agents/security-auditor.md +101 -0
  64. package/plugins/continuous-improvement/agents/test-engineer.md +95 -0
  65. package/plugins/continuous-improvement/bin/backfill.mjs +172 -0
  66. package/plugins/continuous-improvement/bin/mcp-server.mjs +889 -0
  67. package/plugins/continuous-improvement/bin/observe.mjs +148 -0
  68. package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -0
  69. package/plugins/continuous-improvement/commands/dashboard.md +56 -0
  70. package/plugins/continuous-improvement/commands/discipline.md +51 -0
  71. package/plugins/continuous-improvement/commands/harvest.md +76 -0
  72. package/plugins/continuous-improvement/commands/learn-eval.md +117 -0
  73. package/plugins/continuous-improvement/commands/planning-with-files.md +66 -0
  74. package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +62 -0
  75. package/plugins/continuous-improvement/commands/ralph.md +103 -0
  76. package/plugins/continuous-improvement/commands/release-train.md +81 -0
  77. package/plugins/continuous-improvement/commands/seven-laws.md +16 -0
  78. package/plugins/continuous-improvement/commands/superpowers.md +180 -0
  79. package/plugins/continuous-improvement/commands/swarm.md +101 -0
  80. package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -0
  81. package/plugins/continuous-improvement/hooks/gateguard.mjs +172 -0
  82. package/plugins/continuous-improvement/hooks/hooks.json +65 -0
  83. package/plugins/continuous-improvement/hooks/observe.sh +172 -0
  84. package/plugins/continuous-improvement/hooks/session.sh +106 -0
  85. package/plugins/continuous-improvement/hooks/three-section-close.mjs +181 -0
  86. package/plugins/continuous-improvement/instinct-packs/go.json +58 -0
  87. package/plugins/continuous-improvement/instinct-packs/meta.json +16 -0
  88. package/plugins/continuous-improvement/instinct-packs/python.json +58 -0
  89. package/plugins/continuous-improvement/instinct-packs/react.json +58 -0
  90. package/plugins/continuous-improvement/lib/observe-event.mjs +128 -0
  91. package/plugins/continuous-improvement/lib/plugin-metadata.mjs +435 -0
  92. package/plugins/continuous-improvement/lib/resolve-home-dir.mjs +43 -0
  93. package/plugins/continuous-improvement/skills/README.md +37 -0
  94. package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +249 -0
  95. package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +178 -0
  96. package/plugins/continuous-improvement/skills/gateguard/SKILL.md +163 -0
  97. package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +108 -0
  98. package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +447 -0
  99. package/plugins/continuous-improvement/skills/ralph/SKILL.md +221 -0
  100. package/plugins/continuous-improvement/skills/recovery-classification/SKILL.md +73 -0
  101. package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +76 -0
  102. package/plugins/continuous-improvement/skills/state-reconciliation/SKILL.md +63 -0
  103. package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +104 -0
  104. package/plugins/continuous-improvement/skills/superpowers/SKILL.md +219 -0
  105. package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -0
  106. package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +136 -0
  107. package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +224 -0
  108. package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +191 -0
  109. package/plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md +147 -0
  110. package/plugins/continuous-improvement/skills/worktree-safety/SKILL.md +66 -0
  111. package/plugins/continuous-improvement/templates/planning-with-files/findings.md +8 -0
  112. package/plugins/continuous-improvement/templates/planning-with-files/progress.md +7 -0
  113. package/plugins/continuous-improvement/templates/planning-with-files/task_plan.md +23 -0
  114. package/plugins/expert.json +26 -5
  115. package/skills/README.md +79 -0
  116. package/skills/deploy-receipt.md +178 -0
  117. package/skills/gateguard.md +163 -0
  118. package/skills/para-memory-files.md +108 -0
  119. package/skills/proceed-with-the-recommendation.md +447 -0
  120. package/skills/ralph.md +221 -0
  121. package/skills/recovery-classification.md +73 -0
  122. package/skills/safety-guard.md +76 -0
  123. package/skills/state-reconciliation.md +63 -0
  124. package/skills/strategic-compact.md +104 -0
  125. package/skills/superpowers.md +219 -0
  126. package/skills/tdd-workflow.md +411 -0
  127. package/skills/token-budget-advisor.md +136 -0
  128. package/skills/verification-loop.md +224 -0
  129. package/skills/wild-risa-balance.md +191 -0
  130. package/skills/workspace-surface-audit.md +147 -0
  131. package/skills/worktree-safety.md +66 -0
  132. package/templates/insights-claude-md.md +91 -0
  133. package/templates/planning-with-files/findings.md +8 -0
  134. package/templates/planning-with-files/progress.md +7 -0
  135. package/templates/planning-with-files/task_plan.md +23 -0
  136. package/templates/verify-ladder.example.json +60 -0
package/bin/install.mjs CHANGED
@@ -1,558 +1,466 @@
1
1
  #!/usr/bin/env node
2
-
3
2
  /**
4
- * continuous-improvement installer
3
+ * continuous-improvement installer (Claude Code)
5
4
  *
6
5
  * Usage:
7
- * npx continuous-improvement install # auto-detect & install (beginner)
8
- * npx continuous-improvement install --target claude # install to ~/.claude/skills/ + Mulahazah
9
- * npx continuous-improvement install --target openclaw # install to ~/.openclaw/skills/
10
- * npx continuous-improvement install --target cursor # install to ~/.cursor/skills/
11
- * npx continuous-improvement install --target all # install to all detected targets
12
- * npx continuous-improvement install --mode beginner # hooks only (default)
13
- * npx continuous-improvement install --mode expert # hooks + MCP server + session hooks
14
- * npx continuous-improvement install --mode mcp # MCP server only (any editor)
15
- * npx continuous-improvement install --uninstall # remove from all targets
6
+ * npx continuous-improvement install # beginner mode (default)
7
+ * npx continuous-improvement install --mode expert # + MCP server + session hooks
8
+ * npx continuous-improvement install --pack react # load starter instinct pack
9
+ * npx continuous-improvement install --uninstall # remove everything
16
10
  */
17
-
18
- import {
19
- existsSync,
20
- mkdirSync,
21
- copyFileSync,
22
- readFileSync,
23
- writeFileSync,
24
- rmSync,
25
- chmodSync,
26
- readdirSync,
27
- } from "node:fs";
28
- import { join, dirname } from "node:path";
11
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync, } from "node:fs";
12
+ import { execSync } from "node:child_process";
29
13
  import { homedir } from "node:os";
14
+ import { dirname, join } from "node:path";
30
15
  import { fileURLToPath } from "node:url";
31
- import { execSync } from "node:child_process";
32
-
16
+ import { createHash } from "node:crypto";
33
17
  const __filename = fileURLToPath(import.meta.url);
34
18
  const __dirname = dirname(__filename);
35
19
  const SKILL_SOURCE = join(__dirname, "..", "SKILL.md");
36
20
  const SKILL_NAME = "continuous-improvement";
37
21
  const REPO_ROOT = join(__dirname, "..");
38
-
39
- // Parse --mode flag
40
- const _args = process.argv.slice(2);
41
- const _modeIdx = _args.indexOf("--mode");
42
- const INSTALL_MODE = _modeIdx !== -1 && _args[_modeIdx + 1] ? _args[_modeIdx + 1] : "beginner";
43
-
44
- const TARGETS = {
45
- claude: {
46
- label: "Claude Code",
47
- dir: join(homedir(), ".claude", "skills", SKILL_NAME),
48
- },
49
- openclaw: {
50
- label: "OpenClaw",
51
- dir: join(homedir(), ".openclaw", "skills", SKILL_NAME),
52
- },
53
- cursor: {
54
- label: "Cursor",
55
- dir: join(homedir(), ".cursor", "skills", SKILL_NAME),
56
- },
57
- codex: {
58
- label: "Codex",
59
- dir: join(homedir(), ".codex", "skills", SKILL_NAME),
60
- },
61
- };
62
-
63
- function detectTargets() {
64
- const detected = [];
65
- for (const [key, target] of Object.entries(TARGETS)) {
66
- const parentDir = dirname(target.dir);
67
- const configDir = dirname(parentDir);
68
- if (existsSync(configDir)) {
69
- detected.push(key);
70
- }
71
- }
72
- return detected;
22
+ const COMMAND_FILES = [
23
+ "continuous-improvement.md",
24
+ "dashboard.md",
25
+ "discipline.md",
26
+ "harvest.md",
27
+ "learn-eval.md",
28
+ "planning-with-files.md",
29
+ "proceed-with-the-recommendation.md",
30
+ "ralph.md",
31
+ "release-train.md",
32
+ "seven-laws.md",
33
+ "superpowers.md",
34
+ "swarm.md",
35
+ "workspace-surface-audit.md",
36
+ ];
37
+ const HOOK_TYPES = ["PreToolUse", "PostToolUse"];
38
+ const SESSION_HOOK_TYPES = ["SessionStart", "SessionEnd"];
39
+ function getHomeDir() {
40
+ return process.env.HOME || process.env.USERPROFILE || homedir();
73
41
  }
74
-
75
- function installTo(key) {
76
- const target = TARGETS[key];
77
- if (!target) {
78
- console.error(` Unknown target: ${key}`);
79
- return false;
80
- }
81
-
82
- try {
83
- // MCP-only mode: skip skill file copy, just register MCP server
84
- if (INSTALL_MODE === "mcp") {
85
- if (key === "claude") {
42
+ function isInstallMode(value) {
43
+ return value === "beginner" || value === "expert";
44
+ }
45
+ function getErrorMessage(error) {
46
+ return error instanceof Error ? error.message : String(error);
47
+ }
48
+ function readJsonFile(filePath) {
49
+ try {
50
+ return JSON.parse(readFileSync(filePath, "utf8"));
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
56
+ const rawArgs = process.argv.slice(2);
57
+ const modeIndex = rawArgs.indexOf("--mode");
58
+ const requestedMode = modeIndex !== -1 ? rawArgs[modeIndex + 1] : undefined;
59
+ const INSTALL_MODE = isInstallMode(requestedMode) ? requestedMode : "beginner";
60
+ const SKILL_DIR = join(getHomeDir(), ".claude", "skills", SKILL_NAME);
61
+ function installSkill() {
62
+ try {
63
+ mkdirSync(SKILL_DIR, { recursive: true });
64
+ copyFileSync(SKILL_SOURCE, join(SKILL_DIR, "SKILL.md"));
65
+ console.log(` ✓ Claude Code skill → ${SKILL_DIR}/SKILL.md`);
86
66
  setupMulahazah();
87
- console.log(` ✓ ${target.label} → MCP server only`);
88
- } else {
89
- console.log(` ⊘ ${target.label} — MCP mode only applies to Claude Code`);
90
- }
91
- return true;
67
+ return true;
92
68
  }
93
-
94
- mkdirSync(target.dir, { recursive: true });
95
- copyFileSync(SKILL_SOURCE, join(target.dir, "SKILL.md"));
96
- console.log(` ✓ ${target.label} → ${target.dir}/SKILL.md`);
97
-
98
- if (key === "claude") {
99
- setupMulahazah();
69
+ catch (error) {
70
+ console.error(` ✗ Install failed: ${getErrorMessage(error)}`);
71
+ return false;
100
72
  }
101
-
102
- return true;
103
- } catch (err) {
104
- console.error(` ✗ ${target.label}: ${err.message}`);
105
- return false;
106
- }
107
73
  }
108
-
109
74
  function setupMulahazah() {
110
- const home = homedir();
111
- const instinctsDir = join(home, ".claude", "instincts");
112
- const globalDir = join(instinctsDir, "global");
113
-
114
- // 1. Create directory structure
115
- mkdirSync(globalDir, { recursive: true });
116
- console.log(` ✓ Instincts dir ${instinctsDir}/`);
117
-
118
- // 2. Copy observe.sh and make executable
119
- const observeSrc = join(REPO_ROOT, "hooks", "observe.sh");
120
- const observeDest = join(instinctsDir, "observe.sh");
121
- if (existsSync(observeSrc)) {
122
- copyFileSync(observeSrc, observeDest);
123
- chmodSync(observeDest, 0o755);
124
- console.log(` ✓ observe.sh ${observeDest}`);
125
- }
126
-
127
- // 3. Copy session.sh for expert mode
128
- if (INSTALL_MODE === "expert") {
129
- const sessionSrc = join(REPO_ROOT, "hooks", "session.sh");
130
- const sessionDest = join(instinctsDir, "session.sh");
131
- if (existsSync(sessionSrc)) {
132
- copyFileSync(sessionSrc, sessionDest);
133
- chmodSync(sessionDest, 0o755);
134
- console.log(` ✓ session.sh → ${sessionDest}`);
135
- }
136
- }
137
-
138
- // 4. Copy all commands
139
- const commandsDir = join(home, ".claude", "commands");
140
- mkdirSync(commandsDir, { recursive: true });
141
- const commandFiles = ["continuous-improvement.md", "discipline.md", "dashboard.md"];
142
- for (const cmdFile of commandFiles) {
143
- const cmdSrc = join(REPO_ROOT, "commands", cmdFile);
144
- const cmdDest = join(commandsDir, cmdFile);
145
- if (existsSync(cmdSrc)) {
146
- copyFileSync(cmdSrc, cmdDest);
147
- console.log(` ✓ /${cmdFile.replace(".md", "")} command → ${cmdDest}`);
148
- }
149
- }
150
-
151
- // 5. Patch ~/.claude/settings.json with hooks
152
- patchClaudeSettings(observeDest);
153
-
154
- // 6. Setup MCP server for expert or mcp mode
155
- if (INSTALL_MODE === "expert" || INSTALL_MODE === "mcp") {
156
- setupMcpServer();
157
- }
75
+ const home = getHomeDir();
76
+ const instinctsDir = join(home, ".claude", "instincts");
77
+ const globalDir = join(instinctsDir, "global");
78
+ mkdirSync(globalDir, { recursive: true });
79
+ console.log(` Instincts dir ${instinctsDir}/`);
80
+ const observeSrc = join(REPO_ROOT, "hooks", "observe.sh");
81
+ const observeDest = join(instinctsDir, "observe.sh");
82
+ if (existsSync(observeSrc)) {
83
+ copyFileSync(observeSrc, observeDest);
84
+ chmodSync(observeDest, 0o755);
85
+ console.log(` observe.sh → ${observeDest}`);
86
+ }
87
+ // Node observer (Phase 1 of the two-phase hook). The bash shim above
88
+ // exec's this when `node` and the file are both present; otherwise it
89
+ // falls back to the in-bash thin-schema path. Layout under instinctsDir
90
+ // mirrors the repo's bin/ + lib/ structure so the relative import in
91
+ // observe.mjs (`../lib/observe-event.mjs`) resolves correctly.
92
+ const observerJsSrc = join(REPO_ROOT, "bin", "observe.mjs");
93
+ const observeEventSrc = join(REPO_ROOT, "lib", "observe-event.mjs");
94
+ if (existsSync(observerJsSrc) && existsSync(observeEventSrc)) {
95
+ const binDir = join(instinctsDir, "bin");
96
+ const libDir = join(instinctsDir, "lib");
97
+ mkdirSync(binDir, { recursive: true });
98
+ mkdirSync(libDir, { recursive: true });
99
+ const observerJsDest = join(binDir, "observe.mjs");
100
+ const observeEventDest = join(libDir, "observe-event.mjs");
101
+ copyFileSync(observerJsSrc, observerJsDest);
102
+ copyFileSync(observeEventSrc, observeEventDest);
103
+ console.log(` Node observer ${observerJsDest}`);
104
+ }
105
+ if (INSTALL_MODE === "expert") {
106
+ const sessionSrc = join(REPO_ROOT, "hooks", "session.sh");
107
+ const sessionDest = join(instinctsDir, "session.sh");
108
+ if (existsSync(sessionSrc)) {
109
+ copyFileSync(sessionSrc, sessionDest);
110
+ chmodSync(sessionDest, 0o755);
111
+ console.log(` ✓ session.sh → ${sessionDest}`);
112
+ }
113
+ }
114
+ const commandsDir = join(home, ".claude", "commands");
115
+ mkdirSync(commandsDir, { recursive: true });
116
+ for (const commandFile of COMMAND_FILES) {
117
+ const commandSource = join(REPO_ROOT, "commands", commandFile);
118
+ const commandDest = join(commandsDir, commandFile);
119
+ if (existsSync(commandSource)) {
120
+ copyFileSync(commandSource, commandDest);
121
+ console.log(` ✓ /${commandFile.replace(".md", "")} command → ${commandDest}`);
122
+ }
123
+ }
124
+ patchClaudeSettings(observeDest);
125
+ if (INSTALL_MODE === "expert") {
126
+ setupMcpServer();
127
+ }
158
128
  }
159
-
160
129
  function setupMcpServer() {
161
- const home = homedir();
162
- const mcpServerPath = join(REPO_ROOT, "bin", "mcp-server.mjs");
163
- const mcpMode = INSTALL_MODE === "mcp" ? "beginner" : "expert";
164
-
165
- // Patch Claude Code settings.json with MCP server config
166
- const settingsPath = join(home, ".claude", "settings.json");
167
- let settings = {};
168
- if (existsSync(settingsPath)) {
169
- try {
170
- settings = JSON.parse(readFileSync(settingsPath, "utf8"));
171
- } catch {
172
- console.warn(` ! Could not parse settings.json — skipping MCP setup`);
173
- return;
130
+ const home = getHomeDir();
131
+ const mcpServerPath = join(REPO_ROOT, "bin", "mcp-server.mjs");
132
+ const settingsPath = join(home, ".claude", "settings.json");
133
+ const settings = existsSync(settingsPath) ? readJsonFile(settingsPath) : {};
134
+ if (settings === null) {
135
+ console.warn(" ! Could not parse settings.json — skipping MCP setup");
136
+ return;
174
137
  }
175
- }
176
-
177
- if (!settings.mcpServers) settings.mcpServers = {};
178
-
179
- const alreadySetup = settings.mcpServers["continuous-improvement"];
180
- if (!alreadySetup) {
181
- settings.mcpServers["continuous-improvement"] = {
182
- command: "node",
183
- args: [mcpServerPath, "--mode", mcpMode],
184
- };
185
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
186
- console.log(` ✓ MCP server registered (mode: ${mcpMode})`);
187
- } else {
188
- console.log(` ✓ MCP server already registered — no change`);
189
- }
190
-
191
- // Also write claude_desktop_config.json if it exists
192
- const desktopConfig = join(home, ".claude", "claude_desktop_config.json");
193
- if (existsSync(desktopConfig)) {
194
- try {
195
- const config = JSON.parse(readFileSync(desktopConfig, "utf8"));
196
- if (!config.mcpServers) config.mcpServers = {};
197
- if (!config.mcpServers["continuous-improvement"]) {
198
- config.mcpServers["continuous-improvement"] = {
199
- command: "node",
200
- args: [mcpServerPath, "--mode", mcpMode],
138
+ if (!settings.mcpServers) {
139
+ settings.mcpServers = {};
140
+ }
141
+ if (!settings.mcpServers["continuous-improvement"]) {
142
+ settings.mcpServers["continuous-improvement"] = {
143
+ command: "node",
144
+ args: [mcpServerPath, "--mode", "expert"],
201
145
  };
202
- writeFileSync(desktopConfig, JSON.stringify(config, null, 2) + "\n");
203
- console.log(`Claude Desktop MCP config updated`);
204
- }
205
- } catch {
206
- // skip
146
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
147
+ console.log("MCP server registered (mode: expert)");
148
+ }
149
+ else {
150
+ console.log(" ✓ MCP server already registered — no change");
151
+ }
152
+ const desktopConfigPath = join(home, ".claude", "claude_desktop_config.json");
153
+ if (!existsSync(desktopConfigPath)) {
154
+ return;
155
+ }
156
+ const desktopConfig = readJsonFile(desktopConfigPath);
157
+ if (!desktopConfig) {
158
+ return;
159
+ }
160
+ if (!desktopConfig.mcpServers) {
161
+ desktopConfig.mcpServers = {};
162
+ }
163
+ if (!desktopConfig.mcpServers["continuous-improvement"]) {
164
+ desktopConfig.mcpServers["continuous-improvement"] = {
165
+ command: "node",
166
+ args: [mcpServerPath, "--mode", "expert"],
167
+ };
168
+ writeFileSync(desktopConfigPath, JSON.stringify(desktopConfig, null, 2) + "\n");
169
+ console.log(" ✓ Claude Desktop MCP config updated");
207
170
  }
208
- }
209
171
  }
210
-
172
+ function hookAlreadyPatched(entries, scriptName) {
173
+ return entries.some((entry) => Array.isArray(entry.hooks) &&
174
+ entry.hooks.some((hook) => hook.command.includes(scriptName)));
175
+ }
211
176
  function patchClaudeSettings(observePath) {
212
- const settingsPath = join(homedir(), ".claude", "settings.json");
213
-
214
- let settings = {};
215
- if (existsSync(settingsPath)) {
216
- try {
217
- settings = JSON.parse(readFileSync(settingsPath, "utf8"));
218
- } catch {
219
- console.warn(` ! Could not parse ${settingsPath} — skipping hook patch`);
220
- return;
177
+ const settingsPath = join(getHomeDir(), ".claude", "settings.json");
178
+ const settings = existsSync(settingsPath) ? readJsonFile(settingsPath) : {};
179
+ if (settings === null) {
180
+ console.warn(` ! Could not parse ${settingsPath} — skipping hook patch`);
181
+ return;
221
182
  }
222
- }
223
-
224
- if (!settings.hooks) settings.hooks = {};
225
-
226
- const hookEntry = {
227
- matcher: "",
228
- hooks: [
229
- {
230
- type: "command",
231
- command: `bash "${observePath}"`,
232
- },
233
- ],
234
- };
235
-
236
- let changed = false;
237
-
238
- for (const hookType of ["PreToolUse", "PostToolUse"]) {
239
- if (!Array.isArray(settings.hooks[hookType])) {
240
- settings.hooks[hookType] = [];
241
- }
242
- const alreadyPatched = settings.hooks[hookType].some(
243
- (h) =>
244
- Array.isArray(h.hooks) &&
245
- h.hooks.some((hh) => hh.command && hh.command.includes("observe.sh"))
246
- );
247
- if (!alreadyPatched) {
248
- settings.hooks[hookType].push(hookEntry);
249
- changed = true;
250
- }
251
- }
252
-
253
- // Expert mode: add session hooks
254
- if (INSTALL_MODE === "expert") {
255
- const sessionPath = join(homedir(), ".claude", "instincts", "session.sh");
256
- const sessionHook = {
257
- matcher: "",
258
- hooks: [{ type: "command", command: `bash "${sessionPath}"` }],
183
+ if (!settings.hooks) {
184
+ settings.hooks = {};
185
+ }
186
+ const hookEntry = {
187
+ matcher: "",
188
+ hooks: [
189
+ {
190
+ type: "command",
191
+ command: `bash "${observePath}"`,
192
+ },
193
+ ],
259
194
  };
260
-
261
- // Note: SessionStart/SessionEnd hooks may not be supported in all versions.
262
- // We register them — they'll be silently ignored if unsupported.
263
- for (const hookType of ["SessionStart", "SessionEnd"]) {
264
- if (!Array.isArray(settings.hooks[hookType])) {
265
- settings.hooks[hookType] = [];
266
- }
267
- const alreadyPatched = settings.hooks[hookType].some(
268
- (h) =>
269
- Array.isArray(h.hooks) &&
270
- h.hooks.some((hh) => hh.command && hh.command.includes("session.sh"))
271
- );
272
- if (!alreadyPatched) {
273
- settings.hooks[hookType].push(sessionHook);
274
- changed = true;
275
- }
276
- }
277
- }
278
-
279
- if (changed) {
280
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
281
- const hookTypes = INSTALL_MODE === "expert"
282
- ? "PreToolUse/PostToolUse/SessionStart/SessionEnd"
283
- : "PreToolUse/PostToolUse";
284
- console.log(` ✓ Patched ~/.claude/settings.json with ${hookTypes} hooks`);
285
- } else {
286
- console.log(` ✓ settings.json already has hooks — no change needed`);
287
- }
195
+ let changed = false;
196
+ for (const hookType of HOOK_TYPES) {
197
+ if (!Array.isArray(settings.hooks[hookType])) {
198
+ settings.hooks[hookType] = [];
199
+ }
200
+ const hookEntries = settings.hooks[hookType];
201
+ if (!hookAlreadyPatched(hookEntries, "observe.sh")) {
202
+ hookEntries.push(hookEntry);
203
+ changed = true;
204
+ }
205
+ }
206
+ if (INSTALL_MODE === "expert") {
207
+ const sessionPath = join(getHomeDir(), ".claude", "instincts", "session.sh");
208
+ const sessionHook = {
209
+ matcher: "",
210
+ hooks: [{ type: "command", command: `bash "${sessionPath}"` }],
211
+ };
212
+ for (const hookType of SESSION_HOOK_TYPES) {
213
+ if (!Array.isArray(settings.hooks[hookType])) {
214
+ settings.hooks[hookType] = [];
215
+ }
216
+ const hookEntries = settings.hooks[hookType];
217
+ if (!hookAlreadyPatched(hookEntries, "session.sh")) {
218
+ hookEntries.push(sessionHook);
219
+ changed = true;
220
+ }
221
+ }
222
+ }
223
+ if (changed) {
224
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
225
+ const hookTypes = INSTALL_MODE === "expert"
226
+ ? "PreToolUse/PostToolUse/SessionStart/SessionEnd"
227
+ : "PreToolUse/PostToolUse";
228
+ console.log(` ✓ Patched ~/.claude/settings.json with ${hookTypes} hooks`);
229
+ }
230
+ else {
231
+ console.log(" ✓ settings.json already has hooks — no change needed");
232
+ }
288
233
  }
289
-
290
234
  function uninstallAll() {
291
- console.log("\nUninstalling continuous-improvement skill...\n");
292
- const home = homedir();
293
- let removed = 0;
294
-
295
- // 1. Remove skill files from all targets
296
- for (const [key, target] of Object.entries(TARGETS)) {
297
- const skillFile = join(target.dir, "SKILL.md");
298
- if (existsSync(skillFile)) {
299
- try {
300
- rmSync(target.dir, { recursive: true });
301
- console.log(` Removed skill from ${target.label}`);
302
- removed++;
303
- } catch (err) {
304
- console.error(` ✗ ${target.label}: ${err.message}`);
305
- }
306
- }
307
- }
308
-
309
- // 2. Remove all commands
310
- for (const cmdName of ["continuous-improvement.md", "discipline.md", "dashboard.md"]) {
311
- const cmdFile = join(home, ".claude", "commands", cmdName);
312
- if (existsSync(cmdFile)) {
313
- try {
314
- rmSync(cmdFile);
315
- console.log(` ✓ Removed /${cmdName.replace(".md", "")} command`);
316
- } catch (err) {
317
- console.error(` ✗ ${cmdName}: ${err.message}`);
318
- }
319
- }
320
- }
321
-
322
- // 3. Remove observe.sh and session.sh from instincts dir
323
- for (const hookFile of ["observe.sh", "session.sh"]) {
324
- const filePath = join(home, ".claude", "instincts", hookFile);
325
- if (existsSync(filePath)) {
326
- try {
327
- rmSync(filePath);
328
- console.log(` ✓ Removed ${hookFile}`);
329
- } catch (err) {
330
- console.error(` ✗ ${hookFile}: ${err.message}`);
331
- }
332
- }
333
- }
334
-
335
- // 4. Remove hooks and MCP server from settings.json
336
- const settingsPath = join(home, ".claude", "settings.json");
337
- if (existsSync(settingsPath)) {
338
- try {
339
- const settings = JSON.parse(readFileSync(settingsPath, "utf8"));
340
- let changed = false;
341
-
342
- // Remove all hook types
343
- for (const hookType of ["PreToolUse", "PostToolUse", "SessionStart", "SessionEnd"]) {
344
- if (Array.isArray(settings.hooks?.[hookType])) {
345
- const before = settings.hooks[hookType].length;
346
- settings.hooks[hookType] = settings.hooks[hookType].filter(
347
- (h) =>
348
- !(
349
- Array.isArray(h.hooks) &&
350
- h.hooks.some(
351
- (hh) => hh.command && (hh.command.includes("observe.sh") || hh.command.includes("session.sh"))
352
- )
353
- )
354
- );
355
- if (settings.hooks[hookType].length < before) changed = true;
235
+ console.log("\nUninstalling continuous-improvement skill...\n");
236
+ const home = getHomeDir();
237
+ let removed = 0;
238
+ if (existsSync(SKILL_DIR)) {
239
+ try {
240
+ rmSync(SKILL_DIR, { recursive: true });
241
+ console.log(" ✓ Removed Claude Code skill");
242
+ removed++;
243
+ }
244
+ catch (error) {
245
+ console.error(` Skill removal failed: ${getErrorMessage(error)}`);
356
246
  }
357
- }
358
-
359
- // Remove MCP server
360
- if (settings.mcpServers?.["continuous-improvement"]) {
361
- delete settings.mcpServers["continuous-improvement"];
362
- changed = true;
363
- }
364
-
365
- if (changed) {
366
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
367
- console.log(` ✓ Removed hooks and MCP server from settings.json`);
368
- }
369
- } catch {
370
- console.warn(` ! Could not clean settings.json — remove hooks manually`);
371
247
  }
372
- }
373
-
374
- // 5. Clean claude_desktop_config.json MCP entry
375
- const desktopConfig = join(home, ".claude", "claude_desktop_config.json");
376
- if (existsSync(desktopConfig)) {
377
- try {
378
- const config = JSON.parse(readFileSync(desktopConfig, "utf8"));
379
- if (config.mcpServers?.["continuous-improvement"]) {
380
- delete config.mcpServers["continuous-improvement"];
381
- writeFileSync(desktopConfig, JSON.stringify(config, null, 2) + "\n");
382
- console.log(` Removed MCP server from Claude Desktop config`);
383
- }
384
- } catch {
385
- // skip
386
- }
387
- }
388
-
389
- if (removed === 0) {
390
- console.log(" No skill installations found.");
391
- }
392
- console.log(
393
- "\n Note: Instinct data in ~/.claude/instincts/ was preserved.\n" +
394
- " To remove learned data too: rm -rf ~/.claude/instincts/\n"
395
- );
248
+ for (const commandName of COMMAND_FILES) {
249
+ const commandFile = join(home, ".claude", "commands", commandName);
250
+ if (!existsSync(commandFile)) {
251
+ continue;
252
+ }
253
+ try {
254
+ rmSync(commandFile);
255
+ console.log(` ✓ Removed /${commandName.replace(".md", "")} command`);
256
+ }
257
+ catch (error) {
258
+ console.error(` ${commandName}: ${getErrorMessage(error)}`);
259
+ }
260
+ }
261
+ for (const hookFile of ["observe.sh", "session.sh"]) {
262
+ const filePath = join(home, ".claude", "instincts", hookFile);
263
+ if (!existsSync(filePath)) {
264
+ continue;
265
+ }
266
+ try {
267
+ rmSync(filePath);
268
+ console.log(` ✓ Removed ${hookFile}`);
269
+ }
270
+ catch (error) {
271
+ console.error(` ✗ ${hookFile}: ${getErrorMessage(error)}`);
272
+ }
273
+ }
274
+ // Remove the Node observer artifacts deployed alongside observe.sh.
275
+ for (const observerFile of [
276
+ join("bin", "observe.mjs"),
277
+ join("lib", "observe-event.mjs"),
278
+ ]) {
279
+ const filePath = join(home, ".claude", "instincts", observerFile);
280
+ if (!existsSync(filePath))
281
+ continue;
282
+ try {
283
+ rmSync(filePath);
284
+ console.log(` ✓ Removed ${observerFile}`);
285
+ }
286
+ catch (error) {
287
+ console.error(` ✗ ${observerFile}: ${getErrorMessage(error)}`);
288
+ }
289
+ }
290
+ const settingsPath = join(home, ".claude", "settings.json");
291
+ if (existsSync(settingsPath)) {
292
+ const settings = readJsonFile(settingsPath);
293
+ if (settings) {
294
+ let changed = false;
295
+ for (const hookType of [...HOOK_TYPES, ...SESSION_HOOK_TYPES]) {
296
+ const hookEntries = settings.hooks?.[hookType];
297
+ if (!Array.isArray(hookEntries)) {
298
+ continue;
299
+ }
300
+ const nextEntries = hookEntries.filter((entry) => !entry.hooks.some((hook) => hook.command.includes("observe.sh") || hook.command.includes("session.sh")));
301
+ if (nextEntries.length !== hookEntries.length) {
302
+ changed = true;
303
+ }
304
+ settings.hooks[hookType] = nextEntries;
305
+ }
306
+ if (settings.mcpServers?.["continuous-improvement"]) {
307
+ delete settings.mcpServers["continuous-improvement"];
308
+ changed = true;
309
+ }
310
+ if (changed) {
311
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
312
+ console.log(" ✓ Removed hooks and MCP server from settings.json");
313
+ }
314
+ }
315
+ else {
316
+ console.warn(" ! Could not clean settings.json — remove hooks manually");
317
+ }
318
+ }
319
+ const desktopConfigPath = join(home, ".claude", "claude_desktop_config.json");
320
+ if (existsSync(desktopConfigPath)) {
321
+ const desktopConfig = readJsonFile(desktopConfigPath);
322
+ if (desktopConfig?.mcpServers?.["continuous-improvement"]) {
323
+ delete desktopConfig.mcpServers["continuous-improvement"];
324
+ writeFileSync(desktopConfigPath, JSON.stringify(desktopConfig, null, 2) + "\n");
325
+ console.log(" ✓ Removed MCP server from Claude Desktop config");
326
+ }
327
+ }
328
+ if (removed === 0) {
329
+ console.log(" No skill installations found.");
330
+ }
331
+ console.log("\n Note: Instinct data in ~/.claude/instincts/ was preserved.\n" +
332
+ " To remove learned data too: rm -rf ~/.claude/instincts/\n");
396
333
  }
397
-
398
334
  function printUsage() {
399
- console.log(`
400
- Usage: npx continuous-improvement install [options]
335
+ console.log(`
336
+ Usage: npx continuous-improvement <subcommand> [options]
337
+
338
+ Subcommands:
339
+ install Install the plugin (default subcommand)
340
+ backfill Tag legacy thin-schema rows in observations.jsonl files
341
+ --uninstall Remove all installed files
401
342
 
402
- Options:
403
- --target <name> Install to specific target (claude, openclaw, cursor, codex, all)
343
+ Options for 'install':
404
344
  --mode <mode> Installation mode:
405
- beginner — hooks only, no MCP server (default)
406
- expert — hooks + MCP server + session hooks + all tools
407
- mcp — MCP server only (works with any MCP client)
408
- --uninstall Remove from all targets
345
+ beginner — hooks + skill + commands (default)
346
+ expert — beginner + MCP server + session hooks
347
+ --pack <name> Load a starter instinct pack (react, python, go, meta)
409
348
  --help Show this help
410
349
 
411
- Modes explained:
412
- BEGINNER (default) Just works. Hooks capture silently, instincts grow over time.
413
- 3 tools via /continuous-improvement command.
414
-
415
- EXPERT Everything in beginner + MCP server with 8 tools:
416
- import/export, manual instinct creation, observation viewer,
417
- confidence tuning. Plus session start/end hooks.
418
-
419
- MCP MCP server only — for editors that support MCP but not
420
- Claude Code hooks (Cursor, Zed, Windsurf, VS Code).
350
+ Options for 'backfill':
351
+ --dry-run Report counts only, no file writes
352
+ --help Show backfill-specific help
421
353
 
422
354
  Examples:
423
- npx continuous-improvement install # beginner (default)
424
- npx continuous-improvement install --mode expert # full power
425
- npx continuous-improvement install --mode mcp # MCP server only
426
- npx continuous-improvement install --target all # install everywhere
427
- npx continuous-improvement install --uninstall # remove all
355
+ npx continuous-improvement install # beginner (default)
356
+ npx continuous-improvement install --mode expert # full power
357
+ npx continuous-improvement install --pack react # load React instincts
358
+ npx continuous-improvement backfill --dry-run # report thin/rich row counts
359
+ npx continuous-improvement backfill # tag rows in place
360
+ npx continuous-improvement install --uninstall # remove everything
428
361
  `);
429
362
  }
430
-
431
- // --- Main ---
432
-
363
+ function getProjectHashSync() {
364
+ try {
365
+ const root = execSync("git rev-parse --show-toplevel 2>/dev/null", { encoding: "utf8" }).trim();
366
+ const hash = createHash("sha256").update(root).digest("hex").slice(0, 12);
367
+ return { root, hash };
368
+ }
369
+ catch {
370
+ return { root: "global", hash: "global" };
371
+ }
372
+ }
433
373
  const args = process.argv.slice(2);
434
374
  const command = args[0];
435
-
375
+ const validCommands = new Set(["install", "backfill", "--help", "-h", "--uninstall"]);
436
376
  if (args.includes("--help") || args.includes("-h")) {
437
- printUsage();
438
- process.exit(0);
377
+ printUsage();
378
+ process.exit(0);
439
379
  }
440
-
441
- if (!command || !["install", "--help", "-h", "--uninstall"].includes(command)) {
442
- printUsage();
443
- process.exit(command ? 1 : 0);
380
+ if (!command || !validCommands.has(command)) {
381
+ printUsage();
382
+ process.exit(command ? 1 : 0);
383
+ }
384
+ if (command === "backfill") {
385
+ // Delegate to bin/backfill.mjs without spawning a separate process so the
386
+ // user gets one binary surface. Forward the remaining args (e.g. --dry-run).
387
+ const { execFileSync } = await import("node:child_process");
388
+ const backfillBin = join(REPO_ROOT, "bin", "backfill.mjs");
389
+ try {
390
+ execFileSync("node", [backfillBin, ...args.slice(1)], { stdio: "inherit" });
391
+ }
392
+ catch {
393
+ // backfill.mjs always exits 0; if execFileSync threw, propagate the exit
394
+ // status without a stack trace so operator output stays clean.
395
+ }
396
+ process.exit(0);
444
397
  }
445
-
446
398
  if (args.includes("--uninstall")) {
447
- uninstallAll();
448
- process.exit(0);
399
+ uninstallAll();
400
+ process.exit(0);
449
401
  }
450
-
451
402
  console.log(`
452
- continuous-improvement v3.1 (mode: ${INSTALL_MODE})
403
+ continuous-improvement (mode: ${INSTALL_MODE})
453
404
  Research → Plan → Execute → Verify → Reflect → Learn → Iterate
454
405
  `);
455
-
456
- const targetIdx = args.indexOf("--target");
457
- let targets;
458
-
459
- if (targetIdx !== -1 && args[targetIdx + 1]) {
460
- const requested = args[targetIdx + 1].toLowerCase();
461
- if (requested === "all") {
462
- targets = Object.keys(TARGETS);
463
- } else if (TARGETS[requested]) {
464
- targets = [requested];
465
- } else {
466
- console.error(`Unknown target: ${requested}`);
467
- console.error(`Available: ${Object.keys(TARGETS).join(", ")}, all`);
468
- process.exit(1);
469
- }
470
- } else {
471
- targets = detectTargets();
472
- if (targets.length === 0) {
473
- console.log("No supported agent configs detected. Installing to Claude Code by default.\n");
474
- targets = ["claude"];
475
- } else {
476
- console.log(`Detected: ${targets.map((t) => TARGETS[t].label).join(", ")}\n`);
477
- }
478
- }
479
-
480
- console.log("Installing...\n");
481
-
482
- let installed = 0;
483
- for (const t of targets) {
484
- if (installTo(t)) installed++;
485
- }
486
-
487
- const hasClaude = targets.includes("claude");
488
-
406
+ console.log("Installing to Claude Code...\n");
407
+ const installed = installSkill() ? 1 : 0;
489
408
  const modeInfo = {
490
- beginner: "Hooks are capturing silently. System auto-levels as you use it.",
491
- expert: "Full plugin active: hooks + MCP server + session hooks. 8 tools available.",
492
- mcp: "MCP server registered. Connect from any MCP-compatible editor.",
409
+ beginner: "Hooks are capturing silently. System auto-levels as you use it.",
410
+ expert: "Full plugin active: hooks + MCP server + session hooks. 12 tools available.",
493
411
  };
494
-
495
- // Handle --pack flag
496
- const packIdx = _args.indexOf("--pack");
497
- if (packIdx !== -1 && _args[packIdx + 1]) {
498
- const packName = _args[packIdx + 1];
499
- const packPath = join(REPO_ROOT, "instinct-packs", `${packName}.json`);
500
- if (existsSync(packPath)) {
501
- const project = getProjectHashSync();
502
- const targetDir = join(homedir(), ".claude", "instincts", project.hash);
503
- mkdirSync(targetDir, { recursive: true });
504
-
505
- const instincts = JSON.parse(readFileSync(packPath, "utf8"));
506
- let loaded = 0;
507
- for (const inst of instincts) {
508
- const instPath = join(targetDir, `${inst.id}.yaml`);
509
- if (!existsSync(instPath)) {
510
- const yaml = [
511
- `id: ${inst.id}`,
512
- `trigger: "${inst.trigger}"`,
513
- `confidence: ${inst.confidence}`,
514
- `domain: ${inst.domain || "workflow"}`,
515
- `source: pack-${packName}`,
516
- `scope: project`,
517
- `project_id: ${project.hash}`,
518
- `created: "${new Date().toISOString().split("T")[0]}"`,
519
- `last_seen: "${new Date().toISOString().split("T")[0]}"`,
520
- `observation_count: 0`,
521
- "---",
522
- inst.body,
523
- ].join("\n");
524
- writeFileSync(instPath, yaml + "\n");
525
- loaded++;
526
- }
527
- }
528
- console.log(` ✓ Loaded ${loaded}/${instincts.length} instincts from ${packName} pack`);
529
- } else {
530
- const available = readdirSync(join(REPO_ROOT, "instinct-packs"))
531
- .filter((f) => f.endsWith(".json"))
532
- .map((f) => f.replace(".json", ""));
533
- console.error(` ✗ Unknown pack: ${packName}. Available: ${available.join(", ")}`);
534
- }
535
- }
536
-
537
- function getProjectHashSync() {
538
- try {
539
- const root = execSync("git rev-parse --show-toplevel 2>/dev/null", { encoding: "utf8" }).trim();
540
- const hash = execSync(`printf '%s' "${root}" | sha256sum | cut -c1-12`, { encoding: "utf8", shell: "/bin/bash" }).trim();
541
- return { root, hash };
542
- } catch {
543
- return { root: "global", hash: "global" };
544
- }
412
+ const packIndex = rawArgs.indexOf("--pack");
413
+ if (packIndex !== -1 && rawArgs[packIndex + 1]) {
414
+ const packName = rawArgs[packIndex + 1];
415
+ const packPath = join(REPO_ROOT, "instinct-packs", `${packName}.json`);
416
+ if (existsSync(packPath)) {
417
+ const project = getProjectHashSync();
418
+ const targetDir = join(getHomeDir(), ".claude", "instincts", project.hash);
419
+ mkdirSync(targetDir, { recursive: true });
420
+ const instincts = JSON.parse(readFileSync(packPath, "utf8"));
421
+ let loaded = 0;
422
+ for (const instinct of instincts) {
423
+ const instinctPath = join(targetDir, `${instinct.id}.yaml`);
424
+ if (existsSync(instinctPath)) {
425
+ continue;
426
+ }
427
+ const today = new Date().toISOString().split("T")[0];
428
+ const yaml = [
429
+ `id: ${instinct.id}`,
430
+ `trigger: "${instinct.trigger}"`,
431
+ `confidence: ${instinct.confidence}`,
432
+ `domain: ${instinct.domain || "workflow"}`,
433
+ `source: pack-${packName}`,
434
+ "scope: project",
435
+ `project_id: ${project.hash}`,
436
+ `created: "${today}"`,
437
+ `last_seen: "${today}"`,
438
+ "observation_count: 0",
439
+ "---",
440
+ instinct.body,
441
+ ].join("\n");
442
+ writeFileSync(instinctPath, yaml + "\n");
443
+ loaded++;
444
+ }
445
+ console.log(` ✓ Loaded ${loaded}/${instincts.length} instincts from ${packName} pack`);
446
+ }
447
+ else {
448
+ const available = readdirSync(join(REPO_ROOT, "instinct-packs"))
449
+ .filter((file) => file.endsWith(".json"))
450
+ .map((file) => file.replace(".json", ""));
451
+ console.error(` ✗ Unknown pack: ${packName}. Available: ${available.join(", ")}`);
452
+ }
545
453
  }
546
-
547
454
  console.log(`
548
- ${installed > 0 ? "Done." : "Failed."} Installed to ${installed}/${targets.length} target(s).
549
- ${hasClaude ? `\n${modeInfo[INSTALL_MODE] || modeInfo.beginner}` : ""}
455
+ ${installed === 1 ? "Done." : "Failed."}
456
+ ${modeInfo[INSTALL_MODE]}
457
+
550
458
  Next steps:
551
459
  1. Start a new Claude Code session
552
460
  2. Say: "Use the continuous-improvement framework to [your task]"
553
- 3. After your first task, run: /continuous-improvement
554
- 4. Try: /discipline for quick reference, /dashboard for instinct health
555
- ${INSTALL_MODE === "expert" ? "\nMCP tools available: ci_status, ci_instincts, ci_reflect, ci_reinforce,\n ci_create_instinct, ci_observations, ci_export, ci_import, ci_dashboard, ci_load_pack" : ""}
556
- ${INSTALL_MODE === "mcp" ? "\nMCP tools available: ci_status, ci_instincts, ci_reflect" : ""}
557
- Available instinct packs: npx continuous-improvement install --pack react|python|go
461
+ 3. If a task needs persistent planning, run: /planning-with-files
462
+ 4. After your first task, run: /continuous-improvement
463
+ 5. Try: /discipline for quick reference, /dashboard for instinct health
464
+ ${INSTALL_MODE === "expert" ? "\nMCP tools available: ci_status, ci_instincts, ci_reflect, ci_reinforce,\n ci_create_instinct, ci_observations, ci_export, ci_import, ci_plan_init,\n ci_plan_status, ci_dashboard, ci_load_pack" : ""}
465
+ Available instinct packs: npx continuous-improvement install --pack react|python|go|meta
558
466
  `);