continuous-improvement 3.9.2 → 3.12.3
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 +3 -3
- package/CHANGELOG.md +95 -0
- package/LICENSE +21 -21
- package/QUICKSTART.md +13 -8
- package/README.md +94 -162
- package/SKILL.md +1 -1
- package/bin/analyze.sh +161 -161
- package/bin/backfill.mjs +19 -19
- package/bin/check-docs-substrings.mjs +73 -0
- package/bin/check-scripts-citation-drift.mjs +210 -0
- package/bin/check-skill-count.mjs +110 -0
- package/bin/check-test-imports-only.mjs +126 -0
- package/bin/check-tool-count.mjs +129 -0
- package/bin/companion-preference-status.mjs +231 -0
- package/bin/gateguard-clear.mjs +53 -0
- package/bin/generate-plugin-manifests.mjs +8 -1
- package/bin/harvest-friction.mjs +1 -1
- package/bin/hook-stats.mjs +21 -21
- package/bin/install.mjs +185 -28
- package/bin/mcp-server.mjs +216 -3
- package/bin/refresh-third-party.mjs +315 -313
- package/commands/audit.md +34 -0
- package/commands/companion-preference.md +58 -0
- package/commands/continuous-improvement.md +115 -115
- package/commands/dashboard.md +56 -56
- package/commands/discipline.md +14 -0
- package/commands/distill.md +39 -0
- package/commands/goal-check.md +53 -0
- package/commands/grill-me.md +40 -0
- package/commands/grill-with-docs.md +38 -0
- package/commands/handoff.md +42 -0
- package/commands/harvest.md +1 -1
- package/commands/proceed-with-the-recommendation.md +20 -0
- package/commands/recall.md +49 -0
- package/commands/reconcile.md +47 -0
- package/commands/seven-laws.md +16 -16
- package/commands/superpowers.md +3 -3
- package/commands/verify-install.md +55 -0
- package/commands/workspace-surface-audit.md +77 -77
- package/hooks/companion-preference.mjs +190 -0
- package/hooks/gateguard.mjs +72 -25
- package/hooks/goal-drift-stop.mjs +183 -0
- package/hooks/observe.sh +15 -1
- package/hooks/recall-briefing.mjs +167 -0
- package/hooks/route-prompt.mjs +180 -0
- package/hooks/route-table.json +35 -0
- package/hooks/session.sh +106 -106
- package/hooks/three-section-close.mjs +134 -132
- package/instinct-packs/go.json +58 -58
- package/instinct-packs/meta.json +16 -16
- package/instinct-packs/python.json +58 -58
- package/instinct-packs/react.json +58 -58
- package/lib/gateguard-state.mjs +54 -2
- package/lib/goal-drift-gate.mjs +50 -0
- package/lib/goal-state.mjs +285 -0
- package/lib/plugin-metadata.mjs +134 -15
- package/lib/recall-briefing.mjs +57 -0
- package/lib/recall-index.mjs +175 -0
- package/lib/skill-distill.mjs +222 -0
- package/llms.txt +2 -2
- package/package.json +12 -7
- package/plugins/beginner.json +9 -4
- package/plugins/continuous-improvement/.claude-plugin/marketplace.json +2 -2
- package/plugins/continuous-improvement/.claude-plugin/plugin.json +2 -2
- package/plugins/continuous-improvement/LICENSE +21 -21
- package/plugins/continuous-improvement/agents/README.md +3 -3
- package/plugins/continuous-improvement/bin/backfill.mjs +19 -19
- package/plugins/continuous-improvement/bin/gateguard-clear.mjs +53 -0
- package/plugins/continuous-improvement/bin/mcp-server.mjs +216 -3
- package/plugins/continuous-improvement/commands/audit.md +34 -0
- package/plugins/continuous-improvement/commands/companion-preference.md +58 -0
- package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -115
- package/plugins/continuous-improvement/commands/dashboard.md +56 -56
- package/plugins/continuous-improvement/commands/discipline.md +14 -0
- package/plugins/continuous-improvement/commands/distill.md +39 -0
- package/plugins/continuous-improvement/commands/goal-check.md +53 -0
- package/plugins/continuous-improvement/commands/grill-me.md +40 -0
- package/plugins/continuous-improvement/commands/grill-with-docs.md +38 -0
- package/plugins/continuous-improvement/commands/handoff.md +42 -0
- package/plugins/continuous-improvement/commands/harvest.md +1 -1
- package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +20 -0
- package/plugins/continuous-improvement/commands/recall.md +49 -0
- package/plugins/continuous-improvement/commands/reconcile.md +47 -0
- package/plugins/continuous-improvement/commands/seven-laws.md +16 -16
- package/plugins/continuous-improvement/commands/superpowers.md +3 -3
- package/plugins/continuous-improvement/commands/verify-install.md +55 -0
- package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -77
- package/plugins/continuous-improvement/hooks/companion-preference.mjs +190 -0
- package/plugins/continuous-improvement/hooks/gateguard.mjs +72 -25
- package/plugins/continuous-improvement/hooks/goal-drift-stop.mjs +183 -0
- package/plugins/continuous-improvement/hooks/hooks.json +23 -2
- package/plugins/continuous-improvement/hooks/observe.sh +15 -1
- package/plugins/continuous-improvement/hooks/recall-briefing.mjs +167 -0
- package/plugins/continuous-improvement/hooks/route-prompt.mjs +180 -0
- package/plugins/continuous-improvement/hooks/route-table.json +35 -0
- package/plugins/continuous-improvement/hooks/session.sh +106 -106
- package/plugins/continuous-improvement/hooks/three-section-close.mjs +134 -132
- package/plugins/continuous-improvement/instinct-packs/go.json +58 -58
- package/plugins/continuous-improvement/instinct-packs/meta.json +16 -16
- package/plugins/continuous-improvement/instinct-packs/python.json +58 -58
- package/plugins/continuous-improvement/instinct-packs/react.json +58 -58
- package/plugins/continuous-improvement/lib/gateguard-state.mjs +137 -0
- package/plugins/continuous-improvement/lib/goal-drift-gate.mjs +50 -0
- package/plugins/continuous-improvement/lib/goal-state.mjs +285 -0
- package/plugins/continuous-improvement/lib/plugin-metadata.mjs +134 -15
- package/plugins/continuous-improvement/lib/recall-briefing.mjs +57 -0
- package/plugins/continuous-improvement/lib/recall-index.mjs +175 -0
- package/plugins/continuous-improvement/lib/skill-distill.mjs +222 -0
- package/plugins/continuous-improvement/skills/README.md +8 -0
- package/plugins/continuous-improvement/skills/audit/SKILL.md +73 -0
- package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +1 -1
- package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +13 -17
- package/plugins/continuous-improvement/skills/gateguard/SKILL.md +36 -17
- package/plugins/continuous-improvement/skills/goal-monitor/SKILL.md +81 -0
- package/plugins/continuous-improvement/skills/grill-me/SKILL.md +66 -0
- package/plugins/continuous-improvement/skills/grill-with-docs/SKILL.md +252 -0
- package/plugins/continuous-improvement/skills/handoff/SKILL.md +59 -0
- package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +1 -1
- package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +82 -6
- package/plugins/continuous-improvement/skills/ralph/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/recall/SKILL.md +50 -0
- package/plugins/continuous-improvement/skills/reconcile/SKILL.md +80 -0
- package/plugins/continuous-improvement/skills/recovery-classification/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/skill-distillation/SKILL.md +57 -0
- package/plugins/continuous-improvement/skills/state-reconciliation/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/superpowers/SKILL.md +77 -3
- package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -411
- package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +1 -1
- package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +28 -20
- package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md +1 -1
- package/plugins/continuous-improvement/skills/worktree-safety/SKILL.md +3 -2
- package/plugins/expert.json +28 -3
- package/skills/README.md +3 -0
- package/skills/audit.md +73 -0
- package/skills/deploy-receipt.md +13 -17
- package/skills/gateguard.md +36 -17
- package/skills/goal-monitor.md +81 -0
- package/skills/grill-me.md +66 -0
- package/skills/grill-with-docs.md +252 -0
- package/skills/handoff.md +59 -0
- package/skills/para-memory-files.md +1 -1
- package/skills/proceed-with-the-recommendation.md +82 -6
- package/skills/ralph.md +1 -0
- package/skills/recall.md +50 -0
- package/skills/reconcile.md +80 -0
- package/skills/recovery-classification.md +1 -0
- package/skills/safety-guard.md +1 -0
- package/skills/skill-distillation.md +57 -0
- package/skills/state-reconciliation.md +1 -0
- package/skills/strategic-compact.md +1 -0
- package/skills/superpowers.md +77 -3
- package/skills/tdd-workflow.md +411 -411
- package/skills/token-budget-advisor.md +1 -1
- package/skills/verification-loop.md +28 -20
- package/skills/wild-risa-balance.md +1 -0
- package/skills/workspace-surface-audit.md +1 -1
- package/skills/worktree-safety.md +3 -2
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Runtime UserPromptSubmit prompt-router hook.
|
|
4
|
+
*
|
|
5
|
+
* Reads the user prompt, matches it against patterns in
|
|
6
|
+
* hooks/route-table.json, and emits a single `<system-reminder>` recommending
|
|
7
|
+
* the matched skill. When no row matches, the hook emits nothing — the prompt
|
|
8
|
+
* passes through untouched.
|
|
9
|
+
*
|
|
10
|
+
* Stdin : JSON { prompt, session_id?, transcript_path?, cwd? }
|
|
11
|
+
* Stdout : JSON { hookSpecificOutput: { hookEventName: "UserPromptSubmit",
|
|
12
|
+
* additionalContext: string } }
|
|
13
|
+
* OR empty when there is no match.
|
|
14
|
+
* Exit : 0 always — routing decisions live in stdout, never in exit code.
|
|
15
|
+
*
|
|
16
|
+
* Fail-open: any unexpected error reading stdin / parsing the route table /
|
|
17
|
+
* compiling a pattern → emit nothing and exit 0. The hook never blocks a
|
|
18
|
+
* prompt on its own bugs.
|
|
19
|
+
*
|
|
20
|
+
* Telemetry: each match appends one JSONL line to
|
|
21
|
+
* ~/.claude/instincts/<project-hash>/route-prompt.jsonl with the row index,
|
|
22
|
+
* skill, and pattern. Telemetry failures never change the decision.
|
|
23
|
+
*
|
|
24
|
+
* Route table schema (hooks/route-table.json):
|
|
25
|
+
* {
|
|
26
|
+
* "rows": [
|
|
27
|
+
* { "pattern": "regex source", "flags": "i", "skill": "skill-name",
|
|
28
|
+
* "reason": "one-line description" }
|
|
29
|
+
* ]
|
|
30
|
+
* }
|
|
31
|
+
* Rows are evaluated in order; first match wins.
|
|
32
|
+
*/
|
|
33
|
+
import { createHash } from "node:crypto";
|
|
34
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
35
|
+
import { homedir } from "node:os";
|
|
36
|
+
import { dirname, join } from "node:path";
|
|
37
|
+
import { execFileSync } from "node:child_process";
|
|
38
|
+
import { fileURLToPath } from "node:url";
|
|
39
|
+
function readStdin() {
|
|
40
|
+
try {
|
|
41
|
+
return readFileSync(0, "utf8");
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function resolveHome() {
|
|
48
|
+
return process.env.HOME ?? process.env.USERPROFILE ?? homedir();
|
|
49
|
+
}
|
|
50
|
+
function resolveProjectRoot() {
|
|
51
|
+
const fromEnv = process.env.CLAUDE_PROJECT_DIR;
|
|
52
|
+
if (fromEnv)
|
|
53
|
+
return fromEnv;
|
|
54
|
+
try {
|
|
55
|
+
const root = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
56
|
+
encoding: "utf8",
|
|
57
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
58
|
+
}).trim();
|
|
59
|
+
if (root)
|
|
60
|
+
return root;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// not in a git repo
|
|
64
|
+
}
|
|
65
|
+
return "global";
|
|
66
|
+
}
|
|
67
|
+
function telemetryPath(home) {
|
|
68
|
+
const hash = createHash("sha256")
|
|
69
|
+
.update(resolveProjectRoot())
|
|
70
|
+
.digest("hex")
|
|
71
|
+
.slice(0, 12);
|
|
72
|
+
return join(home, ".claude", "instincts", hash, "route-prompt.jsonl");
|
|
73
|
+
}
|
|
74
|
+
function writeTelemetry(home, event) {
|
|
75
|
+
try {
|
|
76
|
+
const path = telemetryPath(home);
|
|
77
|
+
const dir = dirname(path);
|
|
78
|
+
if (!existsSync(dir))
|
|
79
|
+
mkdirSync(dir, { recursive: true });
|
|
80
|
+
appendFileSync(path, `${JSON.stringify(event)}\n`);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// fail-open
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function loadRouteTable() {
|
|
87
|
+
// Hook lives at <plugin-root>/hooks/route-prompt.mjs at runtime; the table
|
|
88
|
+
// sits next to it. import.meta.url gives the file:// URL of the compiled
|
|
89
|
+
// .mjs.
|
|
90
|
+
try {
|
|
91
|
+
const here = fileURLToPath(new URL(".", import.meta.url));
|
|
92
|
+
const tablePath = join(here, "route-table.json");
|
|
93
|
+
const raw = readFileSync(tablePath, "utf8");
|
|
94
|
+
const parsed = JSON.parse(raw);
|
|
95
|
+
if (!parsed || !Array.isArray(parsed.rows))
|
|
96
|
+
return null;
|
|
97
|
+
return parsed;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function findMatch(prompt, table) {
|
|
104
|
+
for (let i = 0; i < table.rows.length; i++) {
|
|
105
|
+
const row = table.rows[i];
|
|
106
|
+
if (!row || typeof row.pattern !== "string" || typeof row.skill !== "string") {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
let rx;
|
|
110
|
+
try {
|
|
111
|
+
rx = new RegExp(row.pattern, row.flags ?? "");
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (rx.test(prompt)) {
|
|
117
|
+
return { row, index: i };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function buildContext(row) {
|
|
123
|
+
const reason = row.reason
|
|
124
|
+
? `${row.reason}\nConsider invoking \`/${row.skill}\` now.`
|
|
125
|
+
: `Consider invoking \`/${row.skill}\` now.`;
|
|
126
|
+
return `<system-reminder>\nPrompt-router suggestion: ${reason}\n</system-reminder>`;
|
|
127
|
+
}
|
|
128
|
+
function emit(output) {
|
|
129
|
+
if (output !== null) {
|
|
130
|
+
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
131
|
+
}
|
|
132
|
+
process.exit(0);
|
|
133
|
+
}
|
|
134
|
+
function main() {
|
|
135
|
+
const raw = readStdin();
|
|
136
|
+
let payload;
|
|
137
|
+
try {
|
|
138
|
+
payload = JSON.parse(raw);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
emit(null);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const prompt = payload.prompt;
|
|
145
|
+
if (typeof prompt !== "string" || prompt.length === 0) {
|
|
146
|
+
emit(null);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const table = loadRouteTable();
|
|
150
|
+
if (!table) {
|
|
151
|
+
emit(null);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const match = findMatch(prompt, table);
|
|
155
|
+
const home = resolveHome();
|
|
156
|
+
if (!match) {
|
|
157
|
+
writeTelemetry(home, {
|
|
158
|
+
ts: new Date().toISOString(),
|
|
159
|
+
hook: "route-prompt",
|
|
160
|
+
matched: false,
|
|
161
|
+
});
|
|
162
|
+
emit(null);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
writeTelemetry(home, {
|
|
166
|
+
ts: new Date().toISOString(),
|
|
167
|
+
hook: "route-prompt",
|
|
168
|
+
matched: true,
|
|
169
|
+
row_index: match.index,
|
|
170
|
+
skill: match.row.skill,
|
|
171
|
+
pattern: match.row.pattern,
|
|
172
|
+
});
|
|
173
|
+
emit({
|
|
174
|
+
hookSpecificOutput: {
|
|
175
|
+
hookEventName: "UserPromptSubmit",
|
|
176
|
+
additionalContext: buildContext(match.row),
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
main();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Declarative prompt-router for the continuous-improvement UserPromptSubmit hook. Each row maps a regex (prompt-side trigger) to a skill the agent should consider invoking. First match wins; rows are evaluated in order. Edit this file to grow the routing table — no code change required.",
|
|
3
|
+
"rows": [
|
|
4
|
+
{
|
|
5
|
+
"pattern": "\\b(write|add|new)\\s+(a\\s+)?(failing\\s+)?test\\b|\\btdd\\b|\\bred[- ]green[- ]refactor\\b",
|
|
6
|
+
"flags": "i",
|
|
7
|
+
"skill": "tdd-workflow",
|
|
8
|
+
"reason": "Prompt mentions writing tests, TDD, or RED-GREEN-REFACTOR."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"pattern": "\\b(verify|verification|prove\\s+it\\s+works|smallest\\s+check|check\\s+it\\s+passes)\\b",
|
|
12
|
+
"flags": "i",
|
|
13
|
+
"skill": "verification-loop",
|
|
14
|
+
"reason": "Prompt asks for verification before declaring done."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"pattern": "\\b(plan|blueprint|design\\s+(the\\s+)?approach|step[- ]by[- ]step\\s+plan|roadmap)\\b",
|
|
18
|
+
"flags": "i",
|
|
19
|
+
"skill": "planning-with-files",
|
|
20
|
+
"reason": "Prompt asks for a plan, blueprint, or design before implementation."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"pattern": "\\b(security\\s+review|threat\\s+model|owasp|vulnerab|auth(entication|orization)\\s+check)\\b",
|
|
24
|
+
"flags": "i",
|
|
25
|
+
"skill": "security-review",
|
|
26
|
+
"reason": "Prompt touches security review, threat modeling, or auth surface."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"pattern": "\\b(code\\s+review|review\\s+(my|the|this)\\s+(code|pr|diff|patch)|critique\\s+(the|this)\\s+code)\\b",
|
|
30
|
+
"flags": "i",
|
|
31
|
+
"skill": "code-review",
|
|
32
|
+
"reason": "Prompt asks for a code review on existing changes."
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
package/hooks/session.sh
CHANGED
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# session.sh — SessionStart/SessionEnd hook for continuous-improvement
|
|
3
|
-
# SessionStart: loads instincts and prints status
|
|
4
|
-
# SessionEnd: prompts reflection
|
|
5
|
-
# Always exits 0 — never blocks the session
|
|
6
|
-
trap 'exit 0' EXIT ERR INT TERM
|
|
7
|
-
|
|
8
|
-
INSTINCTS_DIR="${HOME}/.claude/instincts"
|
|
9
|
-
|
|
10
|
-
# Read stdin
|
|
11
|
-
INPUT="$(cat)"
|
|
12
|
-
[[ -z "$INPUT" ]] && exit 0
|
|
13
|
-
|
|
14
|
-
# ---------------------------------------------------------------------------
|
|
15
|
-
# Detect event type from hook context
|
|
16
|
-
# ---------------------------------------------------------------------------
|
|
17
|
-
# SessionStart hooks receive no tool_name, SessionEnd hooks may vary.
|
|
18
|
-
# We detect based on the hook_type field or the calling context.
|
|
19
|
-
EVENT_TYPE=""
|
|
20
|
-
if command -v jq &>/dev/null; then
|
|
21
|
-
EVENT_TYPE="$(printf '%s' "$INPUT" | jq -r '.hook_type // .event_type // "unknown"' 2>/dev/null)"
|
|
22
|
-
else
|
|
23
|
-
if printf '%s' "$INPUT" | grep -q '"SessionStart"'; then
|
|
24
|
-
EVENT_TYPE="SessionStart"
|
|
25
|
-
elif printf '%s' "$INPUT" | grep -q '"SessionEnd"'; then
|
|
26
|
-
EVENT_TYPE="SessionEnd"
|
|
27
|
-
fi
|
|
28
|
-
fi
|
|
29
|
-
|
|
30
|
-
# ---------------------------------------------------------------------------
|
|
31
|
-
# Project detection (same as observe.sh)
|
|
32
|
-
# ---------------------------------------------------------------------------
|
|
33
|
-
PROJECT_ROOT=""
|
|
34
|
-
if [[ -n "${CLAUDE_PROJECT_DIR:-}" && -d "${CLAUDE_PROJECT_DIR}" ]]; then
|
|
35
|
-
PROJECT_ROOT="${CLAUDE_PROJECT_DIR}"
|
|
36
|
-
fi
|
|
37
|
-
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
38
|
-
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
39
|
-
fi
|
|
40
|
-
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
41
|
-
PROJECT_ROOT="global"
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | sha256sum | cut -c1-12)"
|
|
45
|
-
PROJECT_DIR="${INSTINCTS_DIR}/${PROJECT_HASH}"
|
|
46
|
-
|
|
47
|
-
# ---------------------------------------------------------------------------
|
|
48
|
-
# SessionStart: count observations and instincts, print brief status
|
|
49
|
-
# ---------------------------------------------------------------------------
|
|
50
|
-
if [[ "$EVENT_TYPE" == "SessionStart" || "$EVENT_TYPE" == "unknown" ]]; then
|
|
51
|
-
OBS_COUNT=0
|
|
52
|
-
INSTINCT_COUNT=0
|
|
53
|
-
|
|
54
|
-
OBS_FILE="${PROJECT_DIR}/observations.jsonl"
|
|
55
|
-
if [[ -f "$OBS_FILE" ]]; then
|
|
56
|
-
OBS_COUNT="$(wc -l < "$OBS_FILE" 2>/dev/null || echo 0)"
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
# Count yaml files in project + global
|
|
60
|
-
for dir in "$PROJECT_DIR" "${INSTINCTS_DIR}/global"; do
|
|
61
|
-
if [[ -d "$dir" ]]; then
|
|
62
|
-
count="$(find "$dir" -maxdepth 1 -name '*.yaml' 2>/dev/null | wc -l)"
|
|
63
|
-
INSTINCT_COUNT=$((INSTINCT_COUNT + count))
|
|
64
|
-
fi
|
|
65
|
-
done
|
|
66
|
-
|
|
67
|
-
# Determine level
|
|
68
|
-
LEVEL="CAPTURE"
|
|
69
|
-
if (( OBS_COUNT >= 20 )) || (( INSTINCT_COUNT > 0 )); then
|
|
70
|
-
LEVEL="ANALYZE"
|
|
71
|
-
fi
|
|
72
|
-
|
|
73
|
-
# Check for high-confidence instincts
|
|
74
|
-
if (( INSTINCT_COUNT > 0 )); then
|
|
75
|
-
for dir in "$PROJECT_DIR" "${INSTINCTS_DIR}/global"; do
|
|
76
|
-
if [[ -d "$dir" ]]; then
|
|
77
|
-
for f in "$dir"/*.yaml; do
|
|
78
|
-
[[ -f "$f" ]] || continue
|
|
79
|
-
conf="$(grep '^confidence:' "$f" 2>/dev/null | head -1 | sed 's/confidence: *//')"
|
|
80
|
-
if [[ -n "$conf" ]]; then
|
|
81
|
-
# Compare as integer (multiply by 100) using awk for portability
|
|
82
|
-
int_conf="$(printf '%s' "$conf" | awk '{printf "%.0f", $1 * 100}')"
|
|
83
|
-
if [[ -n "$int_conf" ]] && (( int_conf >= 70 )); then
|
|
84
|
-
LEVEL="AUTO-APPLY"
|
|
85
|
-
break 2
|
|
86
|
-
elif (( int_conf >= 50 )); then
|
|
87
|
-
LEVEL="SUGGEST"
|
|
88
|
-
fi
|
|
89
|
-
fi
|
|
90
|
-
done
|
|
91
|
-
fi
|
|
92
|
-
done
|
|
93
|
-
fi
|
|
94
|
-
|
|
95
|
-
# Write status to stderr (visible in hook output, not blocking)
|
|
96
|
-
echo "[continuous-improvement] Level: ${LEVEL} | Observations: ${OBS_COUNT} | Instincts: ${INSTINCT_COUNT}" >&2
|
|
97
|
-
fi
|
|
98
|
-
|
|
99
|
-
# ---------------------------------------------------------------------------
|
|
100
|
-
# SessionEnd: remind to reflect
|
|
101
|
-
# ---------------------------------------------------------------------------
|
|
102
|
-
if [[ "$EVENT_TYPE" == "SessionEnd" ]]; then
|
|
103
|
-
echo "[continuous-improvement] Session ending. Run /continuous-improvement to reflect and capture learnings." >&2
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
exit 0
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# session.sh — SessionStart/SessionEnd hook for continuous-improvement
|
|
3
|
+
# SessionStart: loads instincts and prints status
|
|
4
|
+
# SessionEnd: prompts reflection
|
|
5
|
+
# Always exits 0 — never blocks the session
|
|
6
|
+
trap 'exit 0' EXIT ERR INT TERM
|
|
7
|
+
|
|
8
|
+
INSTINCTS_DIR="${HOME}/.claude/instincts"
|
|
9
|
+
|
|
10
|
+
# Read stdin
|
|
11
|
+
INPUT="$(cat)"
|
|
12
|
+
[[ -z "$INPUT" ]] && exit 0
|
|
13
|
+
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# Detect event type from hook context
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
# SessionStart hooks receive no tool_name, SessionEnd hooks may vary.
|
|
18
|
+
# We detect based on the hook_type field or the calling context.
|
|
19
|
+
EVENT_TYPE=""
|
|
20
|
+
if command -v jq &>/dev/null; then
|
|
21
|
+
EVENT_TYPE="$(printf '%s' "$INPUT" | jq -r '.hook_type // .event_type // "unknown"' 2>/dev/null)"
|
|
22
|
+
else
|
|
23
|
+
if printf '%s' "$INPUT" | grep -q '"SessionStart"'; then
|
|
24
|
+
EVENT_TYPE="SessionStart"
|
|
25
|
+
elif printf '%s' "$INPUT" | grep -q '"SessionEnd"'; then
|
|
26
|
+
EVENT_TYPE="SessionEnd"
|
|
27
|
+
fi
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
# Project detection (same as observe.sh)
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
PROJECT_ROOT=""
|
|
34
|
+
if [[ -n "${CLAUDE_PROJECT_DIR:-}" && -d "${CLAUDE_PROJECT_DIR}" ]]; then
|
|
35
|
+
PROJECT_ROOT="${CLAUDE_PROJECT_DIR}"
|
|
36
|
+
fi
|
|
37
|
+
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
38
|
+
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
39
|
+
fi
|
|
40
|
+
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
41
|
+
PROJECT_ROOT="global"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | sha256sum | cut -c1-12)"
|
|
45
|
+
PROJECT_DIR="${INSTINCTS_DIR}/${PROJECT_HASH}"
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# SessionStart: count observations and instincts, print brief status
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
if [[ "$EVENT_TYPE" == "SessionStart" || "$EVENT_TYPE" == "unknown" ]]; then
|
|
51
|
+
OBS_COUNT=0
|
|
52
|
+
INSTINCT_COUNT=0
|
|
53
|
+
|
|
54
|
+
OBS_FILE="${PROJECT_DIR}/observations.jsonl"
|
|
55
|
+
if [[ -f "$OBS_FILE" ]]; then
|
|
56
|
+
OBS_COUNT="$(wc -l < "$OBS_FILE" 2>/dev/null || echo 0)"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Count yaml files in project + global
|
|
60
|
+
for dir in "$PROJECT_DIR" "${INSTINCTS_DIR}/global"; do
|
|
61
|
+
if [[ -d "$dir" ]]; then
|
|
62
|
+
count="$(find "$dir" -maxdepth 1 -name '*.yaml' 2>/dev/null | wc -l)"
|
|
63
|
+
INSTINCT_COUNT=$((INSTINCT_COUNT + count))
|
|
64
|
+
fi
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
# Determine level
|
|
68
|
+
LEVEL="CAPTURE"
|
|
69
|
+
if (( OBS_COUNT >= 20 )) || (( INSTINCT_COUNT > 0 )); then
|
|
70
|
+
LEVEL="ANALYZE"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Check for high-confidence instincts
|
|
74
|
+
if (( INSTINCT_COUNT > 0 )); then
|
|
75
|
+
for dir in "$PROJECT_DIR" "${INSTINCTS_DIR}/global"; do
|
|
76
|
+
if [[ -d "$dir" ]]; then
|
|
77
|
+
for f in "$dir"/*.yaml; do
|
|
78
|
+
[[ -f "$f" ]] || continue
|
|
79
|
+
conf="$(grep '^confidence:' "$f" 2>/dev/null | head -1 | sed 's/confidence: *//')"
|
|
80
|
+
if [[ -n "$conf" ]]; then
|
|
81
|
+
# Compare as integer (multiply by 100) using awk for portability
|
|
82
|
+
int_conf="$(printf '%s' "$conf" | awk '{printf "%.0f", $1 * 100}')"
|
|
83
|
+
if [[ -n "$int_conf" ]] && (( int_conf >= 70 )); then
|
|
84
|
+
LEVEL="AUTO-APPLY"
|
|
85
|
+
break 2
|
|
86
|
+
elif (( int_conf >= 50 )); then
|
|
87
|
+
LEVEL="SUGGEST"
|
|
88
|
+
fi
|
|
89
|
+
fi
|
|
90
|
+
done
|
|
91
|
+
fi
|
|
92
|
+
done
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Write status to stderr (visible in hook output, not blocking)
|
|
96
|
+
echo "[continuous-improvement] Level: ${LEVEL} | Observations: ${OBS_COUNT} | Instincts: ${INSTINCT_COUNT}" >&2
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# ---------------------------------------------------------------------------
|
|
100
|
+
# SessionEnd: remind to reflect
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
if [[ "$EVENT_TYPE" == "SessionEnd" ]]; then
|
|
103
|
+
echo "[continuous-improvement] Session ending. Run /continuous-improvement to reflect and capture learnings." >&2
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
exit 0
|