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.
- package/.claude-plugin/marketplace.json +66 -0
- package/CHANGELOG.md +216 -0
- package/QUICKSTART.md +79 -12
- package/README.md +229 -349
- package/SKILL.md +87 -9
- package/action.yml +1 -1
- package/bin/analyze.sh +9 -1
- package/bin/backfill.mjs +172 -0
- package/bin/check-doc-runtime-claims.mjs +120 -0
- package/bin/check-docs-substrings.mjs +333 -0
- package/bin/check-everything-mirror.mjs +145 -0
- package/bin/check-routing-targets.mjs +151 -0
- package/bin/check-skill-law-tag.mjs +128 -0
- package/bin/check-skill-mirror.mjs +119 -0
- package/bin/check-skill-tiers.mjs +116 -0
- package/bin/check-third-party-shape.mjs +202 -0
- package/bin/generate-plugin-manifests.mjs +171 -0
- package/bin/harvest-friction.mjs +279 -0
- package/bin/hook-stats.mjs +258 -0
- package/bin/install.mjs +407 -499
- package/bin/lint-transcript.mjs +182 -210
- package/bin/mcp-server.mjs +834 -608
- package/bin/observe.mjs +148 -0
- package/bin/pre-commit-block-strays.sh +49 -0
- package/bin/refresh-third-party.mjs +416 -0
- package/bin/unified-cli.mjs +533 -0
- package/commands/continuous-improvement.md +43 -2
- package/commands/discipline.md +14 -0
- package/commands/harvest.md +76 -0
- package/commands/learn-eval.md +117 -0
- package/commands/planning-with-files.md +66 -0
- package/commands/proceed-with-the-recommendation.md +62 -0
- package/commands/ralph.md +103 -0
- package/commands/release-train.md +81 -0
- package/commands/seven-laws.md +16 -0
- package/commands/superpowers.md +180 -0
- package/commands/swarm.md +101 -0
- package/commands/workspace-surface-audit.md +77 -0
- package/hooks/gateguard.mjs +172 -0
- package/hooks/observe.sh +42 -4
- package/hooks/session.sh +3 -3
- package/hooks/three-section-close.mjs +181 -0
- package/instinct-packs/meta.json +16 -0
- package/lib/cli-anything.mjs +401 -0
- package/lib/compound-engineering.mjs +831 -0
- package/lib/gateguard-state.mjs +85 -0
- package/lib/observe-event.mjs +128 -0
- package/lib/plugin-metadata.mjs +435 -0
- package/lib/pm-marketplace.mjs +61 -0
- package/lib/pm-skills.mjs +1274 -0
- package/lib/resolve-home-dir.mjs +43 -0
- package/lib/skill-tiers.mjs +137 -0
- package/lib/unified-plugin.mjs +924 -0
- package/llms.txt +32 -7
- package/package.json +29 -19
- package/plugins/beginner.json +17 -6
- package/plugins/continuous-improvement/.claude-plugin/marketplace.json +20 -0
- package/plugins/continuous-improvement/.claude-plugin/plugin.json +26 -0
- package/plugins/continuous-improvement/LICENSE +21 -0
- package/plugins/continuous-improvement/README.md +57 -0
- package/plugins/continuous-improvement/agents/README.md +120 -0
- package/plugins/continuous-improvement/agents/code-reviewer.md +97 -0
- package/plugins/continuous-improvement/agents/security-auditor.md +101 -0
- package/plugins/continuous-improvement/agents/test-engineer.md +95 -0
- package/plugins/continuous-improvement/bin/backfill.mjs +172 -0
- package/plugins/continuous-improvement/bin/mcp-server.mjs +889 -0
- package/plugins/continuous-improvement/bin/observe.mjs +148 -0
- package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -0
- package/plugins/continuous-improvement/commands/dashboard.md +56 -0
- package/plugins/continuous-improvement/commands/discipline.md +51 -0
- package/plugins/continuous-improvement/commands/harvest.md +76 -0
- package/plugins/continuous-improvement/commands/learn-eval.md +117 -0
- package/plugins/continuous-improvement/commands/planning-with-files.md +66 -0
- package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +62 -0
- package/plugins/continuous-improvement/commands/ralph.md +103 -0
- package/plugins/continuous-improvement/commands/release-train.md +81 -0
- package/plugins/continuous-improvement/commands/seven-laws.md +16 -0
- package/plugins/continuous-improvement/commands/superpowers.md +180 -0
- package/plugins/continuous-improvement/commands/swarm.md +101 -0
- package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -0
- package/plugins/continuous-improvement/hooks/gateguard.mjs +172 -0
- package/plugins/continuous-improvement/hooks/hooks.json +65 -0
- package/plugins/continuous-improvement/hooks/observe.sh +172 -0
- package/plugins/continuous-improvement/hooks/session.sh +106 -0
- package/plugins/continuous-improvement/hooks/three-section-close.mjs +181 -0
- package/plugins/continuous-improvement/instinct-packs/go.json +58 -0
- package/plugins/continuous-improvement/instinct-packs/meta.json +16 -0
- package/plugins/continuous-improvement/instinct-packs/python.json +58 -0
- package/plugins/continuous-improvement/instinct-packs/react.json +58 -0
- package/plugins/continuous-improvement/lib/observe-event.mjs +128 -0
- package/plugins/continuous-improvement/lib/plugin-metadata.mjs +435 -0
- package/plugins/continuous-improvement/lib/resolve-home-dir.mjs +43 -0
- package/plugins/continuous-improvement/skills/README.md +37 -0
- package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +249 -0
- package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +178 -0
- package/plugins/continuous-improvement/skills/gateguard/SKILL.md +163 -0
- package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +108 -0
- package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +447 -0
- package/plugins/continuous-improvement/skills/ralph/SKILL.md +221 -0
- package/plugins/continuous-improvement/skills/recovery-classification/SKILL.md +73 -0
- package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +76 -0
- package/plugins/continuous-improvement/skills/state-reconciliation/SKILL.md +63 -0
- package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +104 -0
- package/plugins/continuous-improvement/skills/superpowers/SKILL.md +219 -0
- package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -0
- package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +136 -0
- package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +224 -0
- package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +191 -0
- package/plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md +147 -0
- package/plugins/continuous-improvement/skills/worktree-safety/SKILL.md +66 -0
- package/plugins/continuous-improvement/templates/planning-with-files/findings.md +8 -0
- package/plugins/continuous-improvement/templates/planning-with-files/progress.md +7 -0
- package/plugins/continuous-improvement/templates/planning-with-files/task_plan.md +23 -0
- package/plugins/expert.json +26 -5
- package/skills/README.md +79 -0
- package/skills/deploy-receipt.md +178 -0
- package/skills/gateguard.md +163 -0
- package/skills/para-memory-files.md +108 -0
- package/skills/proceed-with-the-recommendation.md +447 -0
- package/skills/ralph.md +221 -0
- package/skills/recovery-classification.md +73 -0
- package/skills/safety-guard.md +76 -0
- package/skills/state-reconciliation.md +63 -0
- package/skills/strategic-compact.md +104 -0
- package/skills/superpowers.md +219 -0
- package/skills/tdd-workflow.md +411 -0
- package/skills/token-budget-advisor.md +136 -0
- package/skills/verification-loop.md +224 -0
- package/skills/wild-risa-balance.md +191 -0
- package/skills/workspace-surface-audit.md +147 -0
- package/skills/worktree-safety.md +66 -0
- package/templates/insights-claude-md.md +91 -0
- package/templates/planning-with-files/findings.md +8 -0
- package/templates/planning-with-files/progress.md +7 -0
- package/templates/planning-with-files/task_plan.md +23 -0
- 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
|
|
8
|
-
* npx continuous-improvement install --
|
|
9
|
-
* npx continuous-improvement install --
|
|
10
|
-
* npx continuous-improvement install --
|
|
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 {
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
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
|
-
|
|
95
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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(
|
|
203
|
-
console.log(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
settings.hooks[hookType]
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
-
|
|
400
|
-
Usage: npx continuous-improvement
|
|
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
|
|
406
|
-
expert —
|
|
407
|
-
|
|
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
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
|
424
|
-
npx continuous-improvement install --mode expert
|
|
425
|
-
npx continuous-improvement install --
|
|
426
|
-
npx continuous-improvement
|
|
427
|
-
npx continuous-improvement
|
|
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
|
-
|
|
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
|
-
|
|
438
|
-
|
|
377
|
+
printUsage();
|
|
378
|
+
process.exit(0);
|
|
439
379
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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
|
-
|
|
448
|
-
|
|
399
|
+
uninstallAll();
|
|
400
|
+
process.exit(0);
|
|
449
401
|
}
|
|
450
|
-
|
|
451
402
|
console.log(`
|
|
452
|
-
continuous-improvement
|
|
403
|
+
continuous-improvement (mode: ${INSTALL_MODE})
|
|
453
404
|
Research → Plan → Execute → Verify → Reflect → Learn → Iterate
|
|
454
405
|
`);
|
|
455
|
-
|
|
456
|
-
const
|
|
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
|
-
|
|
491
|
-
|
|
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
|
-
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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
|
|
549
|
-
${
|
|
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.
|
|
554
|
-
4.
|
|
555
|
-
|
|
556
|
-
${INSTALL_MODE === "
|
|
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
|
`);
|