continuous-improvement 3.1.0 → 3.8.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/.claude-plugin/marketplace.json +78 -0
- package/CHANGELOG.md +191 -0
- package/LICENSE +21 -21
- package/QUICKSTART.md +101 -81
- package/README.md +207 -359
- package/SKILL.md +87 -9
- package/action.yml +33 -33
- package/bin/analyze.sh +161 -153
- package/bin/backfill.mjs +172 -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 +169 -0
- package/bin/harvest-friction.mjs +279 -0
- package/bin/hook-stats.mjs +258 -0
- package/bin/install.mjs +417 -516
- package/bin/lint-transcript.mjs +182 -210
- package/bin/mcp-server.mjs +840 -617
- 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 +115 -74
- package/commands/dashboard.md +56 -56
- package/commands/discipline.md +51 -37
- 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 +153 -0
- package/commands/swarm.md +101 -0
- package/commands/workspace-surface-audit.md +77 -0
- package/hooks/observe.sh +172 -134
- package/hooks/session.sh +106 -106
- package/hooks/three-section-close.mjs +181 -0
- package/instinct-packs/go.json +58 -58
- package/instinct-packs/meta.json +16 -0
- package/instinct-packs/python.json +58 -58
- package/instinct-packs/react.json +58 -58
- package/lib/cli-anything.mjs +401 -0
- package/lib/compound-engineering.mjs +831 -0
- package/lib/observe-event.mjs +128 -0
- package/lib/plugin-metadata.mjs +432 -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 +68 -43
- package/package.json +28 -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 +56 -0
- package/plugins/continuous-improvement/bin/backfill.mjs +172 -0
- package/plugins/continuous-improvement/bin/mcp-server.mjs +886 -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 +153 -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/hooks.json +60 -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 +432 -0
- package/plugins/continuous-improvement/lib/resolve-home-dir.mjs +43 -0
- package/plugins/continuous-improvement/skills/README.md +34 -0
- package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +249 -0
- package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +131 -0
- package/plugins/continuous-improvement/skills/gateguard/SKILL.md +155 -0
- package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +108 -0
- package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +454 -0
- package/plugins/continuous-improvement/skills/ralph/SKILL.md +221 -0
- package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +76 -0
- package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +104 -0
- package/plugins/continuous-improvement/skills/superpowers/SKILL.md +212 -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 +192 -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/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 +131 -0
- package/skills/gateguard.md +155 -0
- package/skills/para-memory-files.md +108 -0
- package/skills/proceed-with-the-recommendation.md +454 -0
- package/skills/ralph.md +221 -0
- package/skills/safety-guard.md +76 -0
- package/skills/strategic-compact.md +104 -0
- package/skills/superpowers.md +212 -0
- package/skills/tdd-workflow.md +411 -0
- package/skills/token-budget-advisor.md +136 -0
- package/skills/verification-loop.md +192 -0
- package/skills/wild-risa-balance.md +191 -0
- package/skills/workspace-surface-audit.md +147 -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 +47 -0
package/bin/install.mjs
CHANGED
|
@@ -1,558 +1,459 @@
|
|
|
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
|
-
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
|
+
"planning-with-files.md",
|
|
25
|
+
"proceed-with-the-recommendation.md",
|
|
26
|
+
"discipline.md",
|
|
27
|
+
"dashboard.md",
|
|
28
|
+
"learn-eval.md",
|
|
29
|
+
];
|
|
30
|
+
const HOOK_TYPES = ["PreToolUse", "PostToolUse"];
|
|
31
|
+
const SESSION_HOOK_TYPES = ["SessionStart", "SessionEnd"];
|
|
32
|
+
function getHomeDir() {
|
|
33
|
+
return process.env.HOME || process.env.USERPROFILE || homedir();
|
|
73
34
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
35
|
+
function isInstallMode(value) {
|
|
36
|
+
return value === "beginner" || value === "expert";
|
|
37
|
+
}
|
|
38
|
+
function getErrorMessage(error) {
|
|
39
|
+
return error instanceof Error ? error.message : String(error);
|
|
40
|
+
}
|
|
41
|
+
function readJsonFile(filePath) {
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const rawArgs = process.argv.slice(2);
|
|
50
|
+
const modeIndex = rawArgs.indexOf("--mode");
|
|
51
|
+
const requestedMode = modeIndex !== -1 ? rawArgs[modeIndex + 1] : undefined;
|
|
52
|
+
const INSTALL_MODE = isInstallMode(requestedMode) ? requestedMode : "beginner";
|
|
53
|
+
const SKILL_DIR = join(getHomeDir(), ".claude", "skills", SKILL_NAME);
|
|
54
|
+
function installSkill() {
|
|
55
|
+
try {
|
|
56
|
+
mkdirSync(SKILL_DIR, { recursive: true });
|
|
57
|
+
copyFileSync(SKILL_SOURCE, join(SKILL_DIR, "SKILL.md"));
|
|
58
|
+
console.log(` ✓ Claude Code skill → ${SKILL_DIR}/SKILL.md`);
|
|
86
59
|
setupMulahazah();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
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();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return true;
|
|
103
|
-
} catch (err) {
|
|
104
|
-
console.error(` ✗ ${target.label}: ${err.message}`);
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error(` ✗ Install failed: ${getErrorMessage(error)}`);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
107
66
|
}
|
|
108
|
-
|
|
109
67
|
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
|
-
|
|
68
|
+
const home = getHomeDir();
|
|
69
|
+
const instinctsDir = join(home, ".claude", "instincts");
|
|
70
|
+
const globalDir = join(instinctsDir, "global");
|
|
71
|
+
mkdirSync(globalDir, { recursive: true });
|
|
72
|
+
console.log(` ✓ Instincts dir → ${instinctsDir}/`);
|
|
73
|
+
const observeSrc = join(REPO_ROOT, "hooks", "observe.sh");
|
|
74
|
+
const observeDest = join(instinctsDir, "observe.sh");
|
|
75
|
+
if (existsSync(observeSrc)) {
|
|
76
|
+
copyFileSync(observeSrc, observeDest);
|
|
77
|
+
chmodSync(observeDest, 0o755);
|
|
78
|
+
console.log(` ✓ observe.sh → ${observeDest}`);
|
|
79
|
+
}
|
|
80
|
+
// Node observer (Phase 1 of the two-phase hook). The bash shim above
|
|
81
|
+
// exec's this when `node` and the file are both present; otherwise it
|
|
82
|
+
// falls back to the in-bash thin-schema path. Layout under instinctsDir
|
|
83
|
+
// mirrors the repo's bin/ + lib/ structure so the relative import in
|
|
84
|
+
// observe.mjs (`../lib/observe-event.mjs`) resolves correctly.
|
|
85
|
+
const observerJsSrc = join(REPO_ROOT, "bin", "observe.mjs");
|
|
86
|
+
const observeEventSrc = join(REPO_ROOT, "lib", "observe-event.mjs");
|
|
87
|
+
if (existsSync(observerJsSrc) && existsSync(observeEventSrc)) {
|
|
88
|
+
const binDir = join(instinctsDir, "bin");
|
|
89
|
+
const libDir = join(instinctsDir, "lib");
|
|
90
|
+
mkdirSync(binDir, { recursive: true });
|
|
91
|
+
mkdirSync(libDir, { recursive: true });
|
|
92
|
+
const observerJsDest = join(binDir, "observe.mjs");
|
|
93
|
+
const observeEventDest = join(libDir, "observe-event.mjs");
|
|
94
|
+
copyFileSync(observerJsSrc, observerJsDest);
|
|
95
|
+
copyFileSync(observeEventSrc, observeEventDest);
|
|
96
|
+
console.log(` ✓ Node observer → ${observerJsDest}`);
|
|
97
|
+
}
|
|
98
|
+
if (INSTALL_MODE === "expert") {
|
|
99
|
+
const sessionSrc = join(REPO_ROOT, "hooks", "session.sh");
|
|
100
|
+
const sessionDest = join(instinctsDir, "session.sh");
|
|
101
|
+
if (existsSync(sessionSrc)) {
|
|
102
|
+
copyFileSync(sessionSrc, sessionDest);
|
|
103
|
+
chmodSync(sessionDest, 0o755);
|
|
104
|
+
console.log(` ✓ session.sh → ${sessionDest}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const commandsDir = join(home, ".claude", "commands");
|
|
108
|
+
mkdirSync(commandsDir, { recursive: true });
|
|
109
|
+
for (const commandFile of COMMAND_FILES) {
|
|
110
|
+
const commandSource = join(REPO_ROOT, "commands", commandFile);
|
|
111
|
+
const commandDest = join(commandsDir, commandFile);
|
|
112
|
+
if (existsSync(commandSource)) {
|
|
113
|
+
copyFileSync(commandSource, commandDest);
|
|
114
|
+
console.log(` ✓ /${commandFile.replace(".md", "")} command → ${commandDest}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
patchClaudeSettings(observeDest);
|
|
118
|
+
if (INSTALL_MODE === "expert") {
|
|
119
|
+
setupMcpServer();
|
|
120
|
+
}
|
|
158
121
|
}
|
|
159
|
-
|
|
160
122
|
function setupMcpServer() {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
config.mcpServers["continuous-improvement"] = {
|
|
199
|
-
command: "node",
|
|
200
|
-
args: [mcpServerPath, "--mode", mcpMode],
|
|
123
|
+
const home = getHomeDir();
|
|
124
|
+
const mcpServerPath = join(REPO_ROOT, "bin", "mcp-server.mjs");
|
|
125
|
+
const settingsPath = join(home, ".claude", "settings.json");
|
|
126
|
+
const settings = existsSync(settingsPath) ? readJsonFile(settingsPath) : {};
|
|
127
|
+
if (settings === null) {
|
|
128
|
+
console.warn(" ! Could not parse settings.json — skipping MCP setup");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (!settings.mcpServers) {
|
|
132
|
+
settings.mcpServers = {};
|
|
133
|
+
}
|
|
134
|
+
if (!settings.mcpServers["continuous-improvement"]) {
|
|
135
|
+
settings.mcpServers["continuous-improvement"] = {
|
|
136
|
+
command: "node",
|
|
137
|
+
args: [mcpServerPath, "--mode", "expert"],
|
|
138
|
+
};
|
|
139
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
140
|
+
console.log(" ✓ MCP server registered (mode: expert)");
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.log(" ✓ MCP server already registered — no change");
|
|
144
|
+
}
|
|
145
|
+
const desktopConfigPath = join(home, ".claude", "claude_desktop_config.json");
|
|
146
|
+
if (!existsSync(desktopConfigPath)) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const desktopConfig = readJsonFile(desktopConfigPath);
|
|
150
|
+
if (!desktopConfig) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (!desktopConfig.mcpServers) {
|
|
154
|
+
desktopConfig.mcpServers = {};
|
|
155
|
+
}
|
|
156
|
+
if (!desktopConfig.mcpServers["continuous-improvement"]) {
|
|
157
|
+
desktopConfig.mcpServers["continuous-improvement"] = {
|
|
158
|
+
command: "node",
|
|
159
|
+
args: [mcpServerPath, "--mode", "expert"],
|
|
201
160
|
};
|
|
202
|
-
writeFileSync(
|
|
203
|
-
console.log(
|
|
204
|
-
}
|
|
205
|
-
} catch {
|
|
206
|
-
// skip
|
|
161
|
+
writeFileSync(desktopConfigPath, JSON.stringify(desktopConfig, null, 2) + "\n");
|
|
162
|
+
console.log(" ✓ Claude Desktop MCP config updated");
|
|
207
163
|
}
|
|
208
|
-
}
|
|
209
164
|
}
|
|
210
|
-
|
|
165
|
+
function hookAlreadyPatched(entries, scriptName) {
|
|
166
|
+
return entries.some((entry) => Array.isArray(entry.hooks) &&
|
|
167
|
+
entry.hooks.some((hook) => hook.command.includes(scriptName)));
|
|
168
|
+
}
|
|
211
169
|
function patchClaudeSettings(observePath) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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}"` }],
|
|
170
|
+
const settingsPath = join(getHomeDir(), ".claude", "settings.json");
|
|
171
|
+
const settings = existsSync(settingsPath) ? readJsonFile(settingsPath) : {};
|
|
172
|
+
if (settings === null) {
|
|
173
|
+
console.warn(` ! Could not parse ${settingsPath} — skipping hook patch`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (!settings.hooks) {
|
|
177
|
+
settings.hooks = {};
|
|
178
|
+
}
|
|
179
|
+
const hookEntry = {
|
|
180
|
+
matcher: "",
|
|
181
|
+
hooks: [
|
|
182
|
+
{
|
|
183
|
+
type: "command",
|
|
184
|
+
command: `bash "${observePath}"`,
|
|
185
|
+
},
|
|
186
|
+
],
|
|
259
187
|
};
|
|
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
|
-
|
|
188
|
+
let changed = false;
|
|
189
|
+
for (const hookType of HOOK_TYPES) {
|
|
190
|
+
if (!Array.isArray(settings.hooks[hookType])) {
|
|
191
|
+
settings.hooks[hookType] = [];
|
|
192
|
+
}
|
|
193
|
+
const hookEntries = settings.hooks[hookType];
|
|
194
|
+
if (!hookAlreadyPatched(hookEntries, "observe.sh")) {
|
|
195
|
+
hookEntries.push(hookEntry);
|
|
196
|
+
changed = true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (INSTALL_MODE === "expert") {
|
|
200
|
+
const sessionPath = join(getHomeDir(), ".claude", "instincts", "session.sh");
|
|
201
|
+
const sessionHook = {
|
|
202
|
+
matcher: "",
|
|
203
|
+
hooks: [{ type: "command", command: `bash "${sessionPath}"` }],
|
|
204
|
+
};
|
|
205
|
+
for (const hookType of SESSION_HOOK_TYPES) {
|
|
206
|
+
if (!Array.isArray(settings.hooks[hookType])) {
|
|
207
|
+
settings.hooks[hookType] = [];
|
|
208
|
+
}
|
|
209
|
+
const hookEntries = settings.hooks[hookType];
|
|
210
|
+
if (!hookAlreadyPatched(hookEntries, "session.sh")) {
|
|
211
|
+
hookEntries.push(sessionHook);
|
|
212
|
+
changed = true;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (changed) {
|
|
217
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
218
|
+
const hookTypes = INSTALL_MODE === "expert"
|
|
219
|
+
? "PreToolUse/PostToolUse/SessionStart/SessionEnd"
|
|
220
|
+
: "PreToolUse/PostToolUse";
|
|
221
|
+
console.log(` ✓ Patched ~/.claude/settings.json with ${hookTypes} hooks`);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
console.log(" ✓ settings.json already has hooks — no change needed");
|
|
225
|
+
}
|
|
288
226
|
}
|
|
289
|
-
|
|
290
227
|
function uninstallAll() {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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;
|
|
228
|
+
console.log("\nUninstalling continuous-improvement skill...\n");
|
|
229
|
+
const home = getHomeDir();
|
|
230
|
+
let removed = 0;
|
|
231
|
+
if (existsSync(SKILL_DIR)) {
|
|
232
|
+
try {
|
|
233
|
+
rmSync(SKILL_DIR, { recursive: true });
|
|
234
|
+
console.log(" ✓ Removed Claude Code skill");
|
|
235
|
+
removed++;
|
|
356
236
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
237
|
+
catch (error) {
|
|
238
|
+
console.error(` ✗ Skill removal failed: ${getErrorMessage(error)}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
for (const commandName of COMMAND_FILES) {
|
|
242
|
+
const commandFile = join(home, ".claude", "commands", commandName);
|
|
243
|
+
if (!existsSync(commandFile)) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
rmSync(commandFile);
|
|
248
|
+
console.log(` ✓ Removed /${commandName.replace(".md", "")} command`);
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
console.error(` ✗ ${commandName}: ${getErrorMessage(error)}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
for (const hookFile of ["observe.sh", "session.sh"]) {
|
|
255
|
+
const filePath = join(home, ".claude", "instincts", hookFile);
|
|
256
|
+
if (!existsSync(filePath)) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
rmSync(filePath);
|
|
261
|
+
console.log(` ✓ Removed ${hookFile}`);
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
console.error(` ✗ ${hookFile}: ${getErrorMessage(error)}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Remove the Node observer artifacts deployed alongside observe.sh.
|
|
268
|
+
for (const observerFile of [
|
|
269
|
+
join("bin", "observe.mjs"),
|
|
270
|
+
join("lib", "observe-event.mjs"),
|
|
271
|
+
]) {
|
|
272
|
+
const filePath = join(home, ".claude", "instincts", observerFile);
|
|
273
|
+
if (!existsSync(filePath))
|
|
274
|
+
continue;
|
|
275
|
+
try {
|
|
276
|
+
rmSync(filePath);
|
|
277
|
+
console.log(` ✓ Removed ${observerFile}`);
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
console.error(` ✗ ${observerFile}: ${getErrorMessage(error)}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const settingsPath = join(home, ".claude", "settings.json");
|
|
284
|
+
if (existsSync(settingsPath)) {
|
|
285
|
+
const settings = readJsonFile(settingsPath);
|
|
286
|
+
if (settings) {
|
|
287
|
+
let changed = false;
|
|
288
|
+
for (const hookType of [...HOOK_TYPES, ...SESSION_HOOK_TYPES]) {
|
|
289
|
+
const hookEntries = settings.hooks?.[hookType];
|
|
290
|
+
if (!Array.isArray(hookEntries)) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
const nextEntries = hookEntries.filter((entry) => !entry.hooks.some((hook) => hook.command.includes("observe.sh") || hook.command.includes("session.sh")));
|
|
294
|
+
if (nextEntries.length !== hookEntries.length) {
|
|
295
|
+
changed = true;
|
|
296
|
+
}
|
|
297
|
+
settings.hooks[hookType] = nextEntries;
|
|
298
|
+
}
|
|
299
|
+
if (settings.mcpServers?.["continuous-improvement"]) {
|
|
300
|
+
delete settings.mcpServers["continuous-improvement"];
|
|
301
|
+
changed = true;
|
|
302
|
+
}
|
|
303
|
+
if (changed) {
|
|
304
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
305
|
+
console.log(" ✓ Removed hooks and MCP server from settings.json");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
console.warn(" ! Could not clean settings.json — remove hooks manually");
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const desktopConfigPath = join(home, ".claude", "claude_desktop_config.json");
|
|
313
|
+
if (existsSync(desktopConfigPath)) {
|
|
314
|
+
const desktopConfig = readJsonFile(desktopConfigPath);
|
|
315
|
+
if (desktopConfig?.mcpServers?.["continuous-improvement"]) {
|
|
316
|
+
delete desktopConfig.mcpServers["continuous-improvement"];
|
|
317
|
+
writeFileSync(desktopConfigPath, JSON.stringify(desktopConfig, null, 2) + "\n");
|
|
318
|
+
console.log(" ✓ Removed MCP server from Claude Desktop config");
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (removed === 0) {
|
|
322
|
+
console.log(" No skill installations found.");
|
|
323
|
+
}
|
|
324
|
+
console.log("\n Note: Instinct data in ~/.claude/instincts/ was preserved.\n" +
|
|
325
|
+
" To remove learned data too: rm -rf ~/.claude/instincts/\n");
|
|
396
326
|
}
|
|
397
|
-
|
|
398
327
|
function printUsage() {
|
|
399
|
-
|
|
400
|
-
Usage: npx continuous-improvement
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
--
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
npx continuous-improvement
|
|
424
|
-
npx continuous-improvement install --
|
|
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
|
|
328
|
+
console.log(`
|
|
329
|
+
Usage: npx continuous-improvement <subcommand> [options]
|
|
330
|
+
|
|
331
|
+
Subcommands:
|
|
332
|
+
install Install the plugin (default subcommand)
|
|
333
|
+
backfill Tag legacy thin-schema rows in observations.jsonl files
|
|
334
|
+
--uninstall Remove all installed files
|
|
335
|
+
|
|
336
|
+
Options for 'install':
|
|
337
|
+
--mode <mode> Installation mode:
|
|
338
|
+
beginner — hooks + skill + commands (default)
|
|
339
|
+
expert — beginner + MCP server + session hooks
|
|
340
|
+
--pack <name> Load a starter instinct pack (react, python, go, meta)
|
|
341
|
+
--help Show this help
|
|
342
|
+
|
|
343
|
+
Options for 'backfill':
|
|
344
|
+
--dry-run Report counts only, no file writes
|
|
345
|
+
--help Show backfill-specific help
|
|
346
|
+
|
|
347
|
+
Examples:
|
|
348
|
+
npx continuous-improvement install # beginner (default)
|
|
349
|
+
npx continuous-improvement install --mode expert # full power
|
|
350
|
+
npx continuous-improvement install --pack react # load React instincts
|
|
351
|
+
npx continuous-improvement backfill --dry-run # report thin/rich row counts
|
|
352
|
+
npx continuous-improvement backfill # tag rows in place
|
|
353
|
+
npx continuous-improvement install --uninstall # remove everything
|
|
428
354
|
`);
|
|
429
355
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
356
|
+
function getProjectHashSync() {
|
|
357
|
+
try {
|
|
358
|
+
const root = execSync("git rev-parse --show-toplevel 2>/dev/null", { encoding: "utf8" }).trim();
|
|
359
|
+
const hash = createHash("sha256").update(root).digest("hex").slice(0, 12);
|
|
360
|
+
return { root, hash };
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
return { root: "global", hash: "global" };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
433
366
|
const args = process.argv.slice(2);
|
|
434
367
|
const command = args[0];
|
|
435
|
-
|
|
368
|
+
const validCommands = new Set(["install", "backfill", "--help", "-h", "--uninstall"]);
|
|
436
369
|
if (args.includes("--help") || args.includes("-h")) {
|
|
437
|
-
|
|
438
|
-
|
|
370
|
+
printUsage();
|
|
371
|
+
process.exit(0);
|
|
372
|
+
}
|
|
373
|
+
if (!command || !validCommands.has(command)) {
|
|
374
|
+
printUsage();
|
|
375
|
+
process.exit(command ? 1 : 0);
|
|
439
376
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
377
|
+
if (command === "backfill") {
|
|
378
|
+
// Delegate to bin/backfill.mjs without spawning a separate process so the
|
|
379
|
+
// user gets one binary surface. Forward the remaining args (e.g. --dry-run).
|
|
380
|
+
const { execFileSync } = await import("node:child_process");
|
|
381
|
+
const backfillBin = join(REPO_ROOT, "bin", "backfill.mjs");
|
|
382
|
+
try {
|
|
383
|
+
execFileSync("node", [backfillBin, ...args.slice(1)], { stdio: "inherit" });
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
// backfill.mjs always exits 0; if execFileSync threw, propagate the exit
|
|
387
|
+
// status without a stack trace so operator output stays clean.
|
|
388
|
+
}
|
|
389
|
+
process.exit(0);
|
|
444
390
|
}
|
|
445
|
-
|
|
446
391
|
if (args.includes("--uninstall")) {
|
|
447
|
-
|
|
448
|
-
|
|
392
|
+
uninstallAll();
|
|
393
|
+
process.exit(0);
|
|
449
394
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
Research → Plan → Execute → Verify → Reflect → Learn → Iterate
|
|
395
|
+
console.log(`
|
|
396
|
+
continuous-improvement (mode: ${INSTALL_MODE})
|
|
397
|
+
Research → Plan → Execute → Verify → Reflect → Learn → Iterate
|
|
454
398
|
`);
|
|
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
|
-
|
|
399
|
+
console.log("Installing to Claude Code...\n");
|
|
400
|
+
const installed = installSkill() ? 1 : 0;
|
|
489
401
|
const modeInfo = {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
mcp: "MCP server registered. Connect from any MCP-compatible editor.",
|
|
402
|
+
beginner: "Hooks are capturing silently. System auto-levels as you use it.",
|
|
403
|
+
expert: "Full plugin active: hooks + MCP server + session hooks. 12 tools available.",
|
|
493
404
|
};
|
|
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
|
-
}
|
|
405
|
+
const packIndex = rawArgs.indexOf("--pack");
|
|
406
|
+
if (packIndex !== -1 && rawArgs[packIndex + 1]) {
|
|
407
|
+
const packName = rawArgs[packIndex + 1];
|
|
408
|
+
const packPath = join(REPO_ROOT, "instinct-packs", `${packName}.json`);
|
|
409
|
+
if (existsSync(packPath)) {
|
|
410
|
+
const project = getProjectHashSync();
|
|
411
|
+
const targetDir = join(getHomeDir(), ".claude", "instincts", project.hash);
|
|
412
|
+
mkdirSync(targetDir, { recursive: true });
|
|
413
|
+
const instincts = JSON.parse(readFileSync(packPath, "utf8"));
|
|
414
|
+
let loaded = 0;
|
|
415
|
+
for (const instinct of instincts) {
|
|
416
|
+
const instinctPath = join(targetDir, `${instinct.id}.yaml`);
|
|
417
|
+
if (existsSync(instinctPath)) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
const today = new Date().toISOString().split("T")[0];
|
|
421
|
+
const yaml = [
|
|
422
|
+
`id: ${instinct.id}`,
|
|
423
|
+
`trigger: "${instinct.trigger}"`,
|
|
424
|
+
`confidence: ${instinct.confidence}`,
|
|
425
|
+
`domain: ${instinct.domain || "workflow"}`,
|
|
426
|
+
`source: pack-${packName}`,
|
|
427
|
+
"scope: project",
|
|
428
|
+
`project_id: ${project.hash}`,
|
|
429
|
+
`created: "${today}"`,
|
|
430
|
+
`last_seen: "${today}"`,
|
|
431
|
+
"observation_count: 0",
|
|
432
|
+
"---",
|
|
433
|
+
instinct.body,
|
|
434
|
+
].join("\n");
|
|
435
|
+
writeFileSync(instinctPath, yaml + "\n");
|
|
436
|
+
loaded++;
|
|
437
|
+
}
|
|
438
|
+
console.log(` ✓ Loaded ${loaded}/${instincts.length} instincts from ${packName} pack`);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
const available = readdirSync(join(REPO_ROOT, "instinct-packs"))
|
|
442
|
+
.filter((file) => file.endsWith(".json"))
|
|
443
|
+
.map((file) => file.replace(".json", ""));
|
|
444
|
+
console.error(` ✗ Unknown pack: ${packName}. Available: ${available.join(", ")}`);
|
|
445
|
+
}
|
|
545
446
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
${
|
|
549
|
-
|
|
550
|
-
Next steps:
|
|
551
|
-
1. Start a new Claude Code session
|
|
552
|
-
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
|
|
447
|
+
console.log(`
|
|
448
|
+
${installed === 1 ? "Done." : "Failed."}
|
|
449
|
+
${modeInfo[INSTALL_MODE]}
|
|
450
|
+
|
|
451
|
+
Next steps:
|
|
452
|
+
1. Start a new Claude Code session
|
|
453
|
+
2. Say: "Use the continuous-improvement framework to [your task]"
|
|
454
|
+
3. If a task needs persistent planning, run: /planning-with-files
|
|
455
|
+
4. After your first task, run: /continuous-improvement
|
|
456
|
+
5. Try: /discipline for quick reference, /dashboard for instinct health
|
|
457
|
+
${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" : ""}
|
|
458
|
+
Available instinct packs: npx continuous-improvement install --pack react|python|go|meta
|
|
558
459
|
`);
|