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,231 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* /companion-preference status — read & aggregate hook telemetry.
|
|
4
|
+
*
|
|
5
|
+
* Reads ~/.claude/instincts/<project-hash>/companion-preference.jsonl
|
|
6
|
+
* (or an explicit path via --path), groups events by ci_skill within the
|
|
7
|
+
* configured window (default 7 days), and prints a summary report with
|
|
8
|
+
* per-skill totals, action breakdown, and companion_installed%.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node bin/companion-preference-status.mjs # last 7 days, human
|
|
12
|
+
* node bin/companion-preference-status.mjs --days 30 # 30-day window
|
|
13
|
+
* node bin/companion-preference-status.mjs --all # whole file, no window
|
|
14
|
+
* node bin/companion-preference-status.mjs --json # machine-readable JSON
|
|
15
|
+
* node bin/companion-preference-status.mjs --path <p> # override JSONL path
|
|
16
|
+
*
|
|
17
|
+
* Exit codes:
|
|
18
|
+
* 0 — report rendered (including the "no telemetry recorded yet" case)
|
|
19
|
+
* 1 — argument parse error or unexpected runtime failure
|
|
20
|
+
*/
|
|
21
|
+
import { execFileSync } from "node:child_process";
|
|
22
|
+
import { createHash } from "node:crypto";
|
|
23
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
24
|
+
import { homedir } from "node:os";
|
|
25
|
+
import { join } from "node:path";
|
|
26
|
+
import { argv, exit, stdout } from "node:process";
|
|
27
|
+
const ACTIONS = [
|
|
28
|
+
"observation",
|
|
29
|
+
"advisory",
|
|
30
|
+
"block",
|
|
31
|
+
"block-not-installed",
|
|
32
|
+
];
|
|
33
|
+
function parseArgs(args) {
|
|
34
|
+
const out = { days: 7, all: false, json: false, path: null };
|
|
35
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
36
|
+
const a = args[i];
|
|
37
|
+
if (a === "--days") {
|
|
38
|
+
const v = Number(args[++i]);
|
|
39
|
+
if (!Number.isFinite(v) || v <= 0) {
|
|
40
|
+
process.stderr.write(`--days requires a positive integer (got ${args[i]})\n`);
|
|
41
|
+
exit(1);
|
|
42
|
+
}
|
|
43
|
+
out.days = v;
|
|
44
|
+
}
|
|
45
|
+
else if (a === "--all") {
|
|
46
|
+
out.all = true;
|
|
47
|
+
out.days = null;
|
|
48
|
+
}
|
|
49
|
+
else if (a === "--json") {
|
|
50
|
+
out.json = true;
|
|
51
|
+
}
|
|
52
|
+
else if (a === "--path") {
|
|
53
|
+
out.path = args[++i] ?? null;
|
|
54
|
+
if (!out.path) {
|
|
55
|
+
process.stderr.write(`--path requires a value\n`);
|
|
56
|
+
exit(1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if (a === "--help" || a === "-h") {
|
|
60
|
+
printHelp();
|
|
61
|
+
exit(0);
|
|
62
|
+
}
|
|
63
|
+
else if (a !== undefined) {
|
|
64
|
+
process.stderr.write(`unknown argument: ${a}\n`);
|
|
65
|
+
exit(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
function printHelp() {
|
|
71
|
+
stdout.write([
|
|
72
|
+
"Usage: companion-preference-status [options]",
|
|
73
|
+
"",
|
|
74
|
+
"Options:",
|
|
75
|
+
" --days N Only count events from the last N days (default 7)",
|
|
76
|
+
" --all Ignore the window; count every row in the file",
|
|
77
|
+
" --json Emit a machine-readable JSON report",
|
|
78
|
+
" --path <file> Override the default JSONL path (testing)",
|
|
79
|
+
" -h, --help Print this help",
|
|
80
|
+
"",
|
|
81
|
+
].join("\n"));
|
|
82
|
+
}
|
|
83
|
+
function resolveProjectRoot() {
|
|
84
|
+
const fromEnv = process.env.CLAUDE_PROJECT_DIR;
|
|
85
|
+
if (fromEnv)
|
|
86
|
+
return fromEnv;
|
|
87
|
+
try {
|
|
88
|
+
const root = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
89
|
+
encoding: "utf8",
|
|
90
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
91
|
+
}).trim();
|
|
92
|
+
if (root)
|
|
93
|
+
return root;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// not in a git repo
|
|
97
|
+
}
|
|
98
|
+
return "global";
|
|
99
|
+
}
|
|
100
|
+
function defaultJsonlPath() {
|
|
101
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? homedir();
|
|
102
|
+
const hash = createHash("sha256")
|
|
103
|
+
.update(resolveProjectRoot())
|
|
104
|
+
.digest("hex")
|
|
105
|
+
.slice(0, 12);
|
|
106
|
+
return join(home, ".claude", "instincts", hash, "companion-preference.jsonl");
|
|
107
|
+
}
|
|
108
|
+
function parseJsonl(raw) {
|
|
109
|
+
const rows = [];
|
|
110
|
+
let parseErrors = 0;
|
|
111
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
112
|
+
if (line.trim().length === 0)
|
|
113
|
+
continue;
|
|
114
|
+
try {
|
|
115
|
+
rows.push(JSON.parse(line));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
parseErrors += 1;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { rows, parseErrors };
|
|
122
|
+
}
|
|
123
|
+
function aggregate(rows) {
|
|
124
|
+
const bySkill = {};
|
|
125
|
+
const byMode = {};
|
|
126
|
+
const installedYes = {};
|
|
127
|
+
for (const row of rows) {
|
|
128
|
+
const stats = (bySkill[row.ci_skill] ??= {
|
|
129
|
+
total: 0,
|
|
130
|
+
actions: {},
|
|
131
|
+
installed_pct: null,
|
|
132
|
+
});
|
|
133
|
+
stats.total += 1;
|
|
134
|
+
stats.actions[row.action] = (stats.actions[row.action] ?? 0) + 1;
|
|
135
|
+
if (row.companion_installed) {
|
|
136
|
+
installedYes[row.ci_skill] = (installedYes[row.ci_skill] ?? 0) + 1;
|
|
137
|
+
}
|
|
138
|
+
byMode[row.mode] = (byMode[row.mode] ?? 0) + 1;
|
|
139
|
+
}
|
|
140
|
+
for (const [skill, stats] of Object.entries(bySkill)) {
|
|
141
|
+
stats.installed_pct =
|
|
142
|
+
stats.total > 0
|
|
143
|
+
? Math.round(((installedYes[skill] ?? 0) * 100) / stats.total)
|
|
144
|
+
: null;
|
|
145
|
+
}
|
|
146
|
+
return { bySkill, byMode };
|
|
147
|
+
}
|
|
148
|
+
function pad(s, width) {
|
|
149
|
+
return s.length >= width ? s : s + " ".repeat(width - s.length);
|
|
150
|
+
}
|
|
151
|
+
function rpad(n, width) {
|
|
152
|
+
const s = String(n);
|
|
153
|
+
return s.length >= width ? s : " ".repeat(width - s.length) + s;
|
|
154
|
+
}
|
|
155
|
+
function formatHuman(report) {
|
|
156
|
+
const lines = [];
|
|
157
|
+
const windowLabel = report.window_days === null ? "all-time" : `last ${report.window_days} days`;
|
|
158
|
+
lines.push(`Companion-preference telemetry — ${windowLabel}`);
|
|
159
|
+
lines.push(`File: ${report.file}`);
|
|
160
|
+
if (report.since)
|
|
161
|
+
lines.push(`Window: ${report.since} to ${new Date().toISOString()}`);
|
|
162
|
+
lines.push("");
|
|
163
|
+
if (report.total_events === 0) {
|
|
164
|
+
lines.push("No events in window.");
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const skillWidth = Math.max(8, ...Object.keys(report.by_skill).map((k) => k.length));
|
|
168
|
+
const header = pad("ci_skill", skillWidth) +
|
|
169
|
+
" " +
|
|
170
|
+
["total", "observation", "advisory", "block", "block-not-installed", "installed%"]
|
|
171
|
+
.map((h) => rpad(h, h.length))
|
|
172
|
+
.join(" ");
|
|
173
|
+
lines.push(header);
|
|
174
|
+
for (const [skill, stats] of Object.entries(report.by_skill).sort((a, b) => b[1].total - a[1].total)) {
|
|
175
|
+
const cells = [
|
|
176
|
+
rpad(stats.total, "total".length),
|
|
177
|
+
rpad(stats.actions.observation ?? 0, "observation".length),
|
|
178
|
+
rpad(stats.actions.advisory ?? 0, "advisory".length),
|
|
179
|
+
rpad(stats.actions.block ?? 0, "block".length),
|
|
180
|
+
rpad(stats.actions["block-not-installed"] ?? 0, "block-not-installed".length),
|
|
181
|
+
rpad(stats.installed_pct === null ? "—" : `${stats.installed_pct}`, "installed%".length),
|
|
182
|
+
].join(" ");
|
|
183
|
+
lines.push(pad(skill, skillWidth) + " " + cells);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
lines.push("");
|
|
187
|
+
const modeEntries = Object.entries(report.by_mode);
|
|
188
|
+
if (modeEntries.length > 0) {
|
|
189
|
+
lines.push(`Mode totals: ${modeEntries.map(([k, v]) => `${k} ${v}`).join(", ")}`);
|
|
190
|
+
}
|
|
191
|
+
lines.push(`Total events: ${report.total_events}`);
|
|
192
|
+
if (report.parse_errors > 0)
|
|
193
|
+
lines.push(`Parse errors (skipped): ${report.parse_errors}`);
|
|
194
|
+
return lines.join("\n") + "\n";
|
|
195
|
+
}
|
|
196
|
+
function main() {
|
|
197
|
+
const args = parseArgs(argv.slice(2));
|
|
198
|
+
const filePath = args.path ?? defaultJsonlPath();
|
|
199
|
+
if (!existsSync(filePath)) {
|
|
200
|
+
stdout.write(`Companion-preference telemetry: no telemetry recorded yet at ${filePath}\n`);
|
|
201
|
+
exit(0);
|
|
202
|
+
}
|
|
203
|
+
const raw = readFileSync(filePath, "utf8");
|
|
204
|
+
const { rows, parseErrors } = parseJsonl(raw);
|
|
205
|
+
const cutoff = args.all || args.days === null
|
|
206
|
+
? null
|
|
207
|
+
: new Date(Date.now() - args.days * 24 * 3600 * 1000).toISOString();
|
|
208
|
+
const filtered = cutoff === null ? rows : rows.filter((r) => r.ts >= cutoff);
|
|
209
|
+
const { bySkill, byMode } = aggregate(filtered);
|
|
210
|
+
const report = {
|
|
211
|
+
file: filePath,
|
|
212
|
+
window_days: args.all ? null : args.days,
|
|
213
|
+
since: cutoff,
|
|
214
|
+
total_events: filtered.length,
|
|
215
|
+
parse_errors: parseErrors,
|
|
216
|
+
by_skill: bySkill,
|
|
217
|
+
by_mode: byMode,
|
|
218
|
+
};
|
|
219
|
+
if (args.json) {
|
|
220
|
+
stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
stdout.write(formatHuman(report));
|
|
224
|
+
}
|
|
225
|
+
exit(0);
|
|
226
|
+
}
|
|
227
|
+
const invokedDirectly = argv[1]?.endsWith("companion-preference-status.mjs");
|
|
228
|
+
if (invokedDirectly) {
|
|
229
|
+
main();
|
|
230
|
+
}
|
|
231
|
+
export { ACTIONS, aggregate, parseArgs, parseJsonl, };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* gateguard-clear — record GateGuard clearance for files from the Bash route.
|
|
4
|
+
*
|
|
5
|
+
* The GateGuard PreToolUse hook blocks the first Edit/Write per file and prints
|
|
6
|
+
* the session-state path in its block reason. After presenting the required
|
|
7
|
+
* facts, run this to clear the gate so the retry is allowed. Bash is not gated
|
|
8
|
+
* (unless the command is destructive), so this surface always works — including
|
|
9
|
+
* where the ci_gateguard_clear MCP tool is not connected.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* node bin/gateguard-clear.mjs <file_path> [<file_path>...] [--state <path>]
|
|
13
|
+
*
|
|
14
|
+
* Default resolves the session dir canonically, the same way the hook does.
|
|
15
|
+
* --state <path> writes that exact gateguard-session.json — the path the block
|
|
16
|
+
* reason prints — bypassing resolution for any residual env mismatch.
|
|
17
|
+
*/
|
|
18
|
+
import { dirname, join } from "node:path";
|
|
19
|
+
import { MAX_CLEARED_FILES, clearFiles, resolveSessionDir, } from "../lib/gateguard-state.mjs";
|
|
20
|
+
function main() {
|
|
21
|
+
const argv = process.argv.slice(2);
|
|
22
|
+
const files = [];
|
|
23
|
+
let stateFile = "";
|
|
24
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
25
|
+
const arg = argv[i];
|
|
26
|
+
if (arg === "--state") {
|
|
27
|
+
stateFile = argv[i + 1] ?? "";
|
|
28
|
+
i += 1;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
files.push(arg);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (argv.includes("--state") && stateFile === "") {
|
|
35
|
+
process.stderr.write("--state requires a <gateguard-session.json> path argument\n");
|
|
36
|
+
process.exit(2);
|
|
37
|
+
}
|
|
38
|
+
if (files.length === 0) {
|
|
39
|
+
process.stderr.write("usage: gateguard-clear <file_path> [<file_path>...] [--state <gateguard-session.json>]\n");
|
|
40
|
+
process.exit(2);
|
|
41
|
+
}
|
|
42
|
+
// clearFiles writes <sessionDir>/gateguard-session.json. With --state the
|
|
43
|
+
// caller hands us the full state-file path the block reason printed, so the
|
|
44
|
+
// session dir is its parent.
|
|
45
|
+
const sessionDir = stateFile ? dirname(stateFile) : resolveSessionDir();
|
|
46
|
+
const { cleared, skippedForCap } = clearFiles(sessionDir, files);
|
|
47
|
+
process.stdout.write(`Cleared ${cleared.length}: ${cleared.length > 0 ? cleared.join(", ") : "(none — already cleared)"}\n`);
|
|
48
|
+
if (skippedForCap.length > 0) {
|
|
49
|
+
process.stdout.write(`Skipped — session cap of ${MAX_CLEARED_FILES} reached: ${skippedForCap.join(", ")}\n`);
|
|
50
|
+
}
|
|
51
|
+
process.stdout.write(`State: ${join(sessionDir, "gateguard-session.json")}\n`);
|
|
52
|
+
}
|
|
53
|
+
main();
|
|
@@ -35,7 +35,7 @@ async function writeBundledSkills() {
|
|
|
35
35
|
const sourceSkillsDir = join(REPO_ROOT, "skills");
|
|
36
36
|
const targetSkillsDir = join(PLUGIN_BUNDLE_DIR, "skills");
|
|
37
37
|
const companionSkills = (await readdir(sourceSkillsDir))
|
|
38
|
-
.filter((file) =>
|
|
38
|
+
.filter((file) => file.endsWith(".md") && file !== "README.md")
|
|
39
39
|
.sort();
|
|
40
40
|
await mkdir(targetSkillsDir, { recursive: true });
|
|
41
41
|
await copyFileTo(join(REPO_ROOT, "SKILL.md"), join(targetSkillsDir, PACKAGE_NAME, "SKILL.md"));
|
|
@@ -145,9 +145,16 @@ async function writePluginBundle() {
|
|
|
145
145
|
copyFileTo(join(REPO_ROOT, "bin", "mcp-server.mjs"), join(PLUGIN_BUNDLE_DIR, "bin", "mcp-server.mjs")),
|
|
146
146
|
copyFileTo(join(REPO_ROOT, "bin", "observe.mjs"), join(PLUGIN_BUNDLE_DIR, "bin", "observe.mjs")),
|
|
147
147
|
copyFileTo(join(REPO_ROOT, "bin", "backfill.mjs"), join(PLUGIN_BUNDLE_DIR, "bin", "backfill.mjs")),
|
|
148
|
+
copyFileTo(join(REPO_ROOT, "bin", "gateguard-clear.mjs"), join(PLUGIN_BUNDLE_DIR, "bin", "gateguard-clear.mjs")),
|
|
149
|
+
copyFileTo(join(REPO_ROOT, "lib", "gateguard-state.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "gateguard-state.mjs")),
|
|
148
150
|
copyFileTo(join(REPO_ROOT, "lib", "plugin-metadata.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "plugin-metadata.mjs")),
|
|
149
151
|
copyFileTo(join(REPO_ROOT, "lib", "resolve-home-dir.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "resolve-home-dir.mjs")),
|
|
150
152
|
copyFileTo(join(REPO_ROOT, "lib", "observe-event.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "observe-event.mjs")),
|
|
153
|
+
copyFileTo(join(REPO_ROOT, "lib", "goal-state.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "goal-state.mjs")),
|
|
154
|
+
copyFileTo(join(REPO_ROOT, "lib", "goal-drift-gate.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "goal-drift-gate.mjs")),
|
|
155
|
+
copyFileTo(join(REPO_ROOT, "lib", "recall-index.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "recall-index.mjs")),
|
|
156
|
+
copyFileTo(join(REPO_ROOT, "lib", "recall-briefing.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "recall-briefing.mjs")),
|
|
157
|
+
copyFileTo(join(REPO_ROOT, "lib", "skill-distill.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "skill-distill.mjs")),
|
|
151
158
|
copyFileTo(join(REPO_ROOT, "LICENSE"), join(PLUGIN_BUNDLE_DIR, "LICENSE")),
|
|
152
159
|
writePluginBundleReadme(),
|
|
153
160
|
]);
|
package/bin/harvest-friction.mjs
CHANGED
|
@@ -248,7 +248,7 @@ function main() {
|
|
|
248
248
|
console.log(" the Node observer is not on PATH — never tool_complete with output_summary,");
|
|
249
249
|
console.log(" which is what the classifier needs.");
|
|
250
250
|
console.log(" Install jq (winget install jqlang.jq | brew install jq | apt install jq)");
|
|
251
|
-
console.log(" OR ensure
|
|
251
|
+
console.log(" OR ensure instincts/bin/observe.mjs is reachable from the hook script.");
|
|
252
252
|
}
|
|
253
253
|
else if (result.thinSchemaRows > 0 && result.classifiedRows === 0) {
|
|
254
254
|
console.log("");
|
package/bin/hook-stats.mjs
CHANGED
|
@@ -46,27 +46,27 @@ import { platform } from "node:os";
|
|
|
46
46
|
import { join } from "node:path";
|
|
47
47
|
import { argv, cwd, exit, stderr, stdout } from "node:process";
|
|
48
48
|
import { resolveHomeDir } from "../lib/resolve-home-dir.mjs";
|
|
49
|
-
const USAGE = `Usage: node bin/hook-stats.mjs [options]
|
|
50
|
-
|
|
51
|
-
Reads JSONL telemetry from <HOME>/.claude/hook-telemetry/*.jsonl and
|
|
52
|
-
prints per-hook aggregate counts over a recent time window.
|
|
53
|
-
|
|
54
|
-
Options:
|
|
55
|
-
--hours=<n> Time window in hours (default: 24)
|
|
56
|
-
--hash=<hash> Only read this single <hash>.jsonl file
|
|
57
|
-
(default: sha256 of the current working directory,
|
|
58
|
-
normalized to forward slashes and lowercased on
|
|
59
|
-
Windows, then first 12 hex chars)
|
|
60
|
-
--telemetry-dir=<path> Override telemetry dir
|
|
61
|
-
(default: <HOME>/.claude/hook-telemetry)
|
|
62
|
-
--help Show this help and exit 0
|
|
63
|
-
|
|
64
|
-
Output:
|
|
65
|
-
One line per hook: "<hook> last <hours>h: pass=<n> block=<n>
|
|
66
|
-
skip-short=<n> total=<n> avg-duration=<X>ms".
|
|
67
|
-
If there are no records in the window: "no records in last <hours>h".
|
|
68
|
-
|
|
69
|
-
The reader is parse-tolerant: malformed JSONL lines are skipped silently.
|
|
49
|
+
const USAGE = `Usage: node bin/hook-stats.mjs [options]
|
|
50
|
+
|
|
51
|
+
Reads JSONL telemetry from <HOME>/.claude/hook-telemetry/*.jsonl and
|
|
52
|
+
prints per-hook aggregate counts over a recent time window.
|
|
53
|
+
|
|
54
|
+
Options:
|
|
55
|
+
--hours=<n> Time window in hours (default: 24)
|
|
56
|
+
--hash=<hash> Only read this single <hash>.jsonl file
|
|
57
|
+
(default: sha256 of the current working directory,
|
|
58
|
+
normalized to forward slashes and lowercased on
|
|
59
|
+
Windows, then first 12 hex chars)
|
|
60
|
+
--telemetry-dir=<path> Override telemetry dir
|
|
61
|
+
(default: <HOME>/.claude/hook-telemetry)
|
|
62
|
+
--help Show this help and exit 0
|
|
63
|
+
|
|
64
|
+
Output:
|
|
65
|
+
One line per hook: "<hook> last <hours>h: pass=<n> block=<n>
|
|
66
|
+
skip-short=<n> total=<n> avg-duration=<X>ms".
|
|
67
|
+
If there are no records in the window: "no records in last <hours>h".
|
|
68
|
+
|
|
69
|
+
The reader is parse-tolerant: malformed JSONL lines are skipped silently.
|
|
70
70
|
`;
|
|
71
71
|
function parseArgs(rawArgs) {
|
|
72
72
|
const opts = {
|