@bglocation/tune-context 1.0.1 → 2.0.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 +2 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +252 -0
- package/README.md +129 -16
- package/bin/tune-context +11 -0
- package/bin/tune-context.mjs +110 -16
- package/cli/detect.mjs +92 -16
- package/cli/generate.mjs +48 -0
- package/cli/sync-doctrine.mjs +11 -2
- package/cli/verify.mjs +119 -3
- package/eval/adoption-report.mjs +211 -33
- package/hooks/adoption-log.mjs +2 -2
- package/hooks/config-dir.mjs +12 -0
- package/hooks/context-reminder.mjs +212 -0
- package/hooks/hooks.json +11 -0
- package/hooks/pre-compact-snapshot.mjs +69 -7
- package/package.json +4 -2
- package/skills/token-efficiency/SKILL.md +3 -1
- package/skills/tune-context/SKILL.md +94 -19
- package/skills/tune-context/templates/settings.json.tmpl +15 -14
|
@@ -9,10 +9,16 @@
|
|
|
9
9
|
// capture what the filesystem/git already know (branch, dirty files, recent
|
|
10
10
|
// commits) — not decisions or open threads from the conversation. It is a
|
|
11
11
|
// safety net against losing that mechanical state, not a summary.
|
|
12
|
+
//
|
|
13
|
+
// Claude Code also has a PostCompact event. Staying on PreCompact +
|
|
14
|
+
// SessionStart(compact) is deliberate, not an oversight (TASK-078): this pair
|
|
15
|
+
// is what TASK-056/061 proved out with a smoke-tested round trip, and nothing
|
|
16
|
+
// since has needed PostCompact's different timing.
|
|
12
17
|
import { execFileSync } from 'node:child_process';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
18
|
+
import { createHash } from 'node:crypto';
|
|
19
|
+
import { mkdirSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
15
20
|
import { join } from 'node:path';
|
|
21
|
+
import { claudeBaseDir } from './config-dir.mjs';
|
|
16
22
|
|
|
17
23
|
function readStdin() {
|
|
18
24
|
try {
|
|
@@ -34,9 +40,50 @@ function git(cwd, args) {
|
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
42
|
|
|
43
|
+
// Hash suffix makes this injective. The slug alone collapses distinct paths
|
|
44
|
+
// that normalize the same way (/home/a/b and /home/a-b both slug to
|
|
45
|
+
// "home-a-b"), which let two projects share one file — and SessionStart
|
|
46
|
+
// (compact) would reinject one project's git state into an unrelated
|
|
47
|
+
// session's compaction (TASK-076). Slug stays first for human readability;
|
|
48
|
+
// the hash is what actually prevents the collision. Renaming the file shape
|
|
49
|
+
// orphans pre-existing snapshots — acceptable, they're one-compaction-lived —
|
|
50
|
+
// noted in CHANGELOG per the task.
|
|
37
51
|
export function stateFilePath(cwd) {
|
|
38
52
|
const safe = cwd.replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
39
|
-
|
|
53
|
+
const hash = createHash('sha256').update(cwd).digest('hex').slice(0, 8);
|
|
54
|
+
return join(claudeBaseDir(), 'tune-context', 'state', `${safe}-${hash}.md`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// PO decision 2026-07-25 (TASK-076): age-based, 30 days. One file per distinct
|
|
58
|
+
// cwd (stateFilePath above) means every worktree or temp checkout a user ever
|
|
59
|
+
// compacted in gets a permanent file, not just abandoned projects — and this
|
|
60
|
+
// file is rewritten on every compaction of a still-active project, so mtime
|
|
61
|
+
// age is an exact recency signal, not a proxy.
|
|
62
|
+
const MAX_SNAPSHOT_AGE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
63
|
+
|
|
64
|
+
// Self-contained like git() above: never throws, so a missing/unreadable
|
|
65
|
+
// state/ directory or an unremovable file can't take the write down with it.
|
|
66
|
+
// `keep` is excluded from consideration outright, not just by age, so the
|
|
67
|
+
// snapshot this run just wrote can never be pruned regardless of mtime/clock
|
|
68
|
+
// edge cases (no reliance on "the fresh write's mtime beats the cutoff").
|
|
69
|
+
export function pruneStateDir(dir, keep) {
|
|
70
|
+
let entries;
|
|
71
|
+
try {
|
|
72
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
73
|
+
} catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const cutoff = Date.now() - MAX_SNAPSHOT_AGE_MS;
|
|
77
|
+
for (const entry of entries) {
|
|
78
|
+
if (!entry.isFile()) continue;
|
|
79
|
+
const path = join(dir, entry.name);
|
|
80
|
+
if (path === keep) continue;
|
|
81
|
+
try {
|
|
82
|
+
if (statSync(path).mtimeMs < cutoff) unlinkSync(path);
|
|
83
|
+
} catch {
|
|
84
|
+
// gone already, or unremovable — not this hook's problem
|
|
85
|
+
}
|
|
86
|
+
}
|
|
40
87
|
}
|
|
41
88
|
|
|
42
89
|
export function buildSnapshot(input) {
|
|
@@ -61,11 +108,26 @@ export function buildSnapshot(input) {
|
|
|
61
108
|
return lines.join('\n') + '\n';
|
|
62
109
|
}
|
|
63
110
|
|
|
111
|
+
// Never fails the host tool call: this snapshot is a safety net for a
|
|
112
|
+
// compaction, not a critical feature, so its own failure can't be louder than
|
|
113
|
+
// the context loss it guards against. An unwritable state dir (container,
|
|
114
|
+
// read-only volume, misdirected CLAUDE_CONFIG_DIR) must not surface as a
|
|
115
|
+
// nonzero exit at the exact moment the session is under context pressure.
|
|
116
|
+
// Deliberately no console.error — hooks don't write to stdout/stderr
|
|
117
|
+
// (transcript noise) — a silent safety-net failure is cheaper than a loud
|
|
118
|
+
// one. Mirrors hooks/adoption-log.mjs's main(), which this file previously
|
|
119
|
+
// lacked parity with (TASK-076).
|
|
64
120
|
function main() {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
121
|
+
try {
|
|
122
|
+
const input = readStdin();
|
|
123
|
+
const cwd = input.cwd || process.cwd();
|
|
124
|
+
const path = stateFilePath(cwd);
|
|
125
|
+
mkdirSync(join(path, '..'), { recursive: true });
|
|
126
|
+
writeFileSync(path, buildSnapshot(input));
|
|
127
|
+
pruneStateDir(join(path, '..'), path);
|
|
128
|
+
} catch {
|
|
129
|
+
// non-fatal by design — never block a compaction over a snapshot write
|
|
130
|
+
}
|
|
69
131
|
}
|
|
70
132
|
|
|
71
133
|
if (process.argv[1] && process.argv[1].endsWith('pre-compact-snapshot.mjs')) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bglocation/tune-context",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Context-efficiency configurator for Claude Code — token-saving doctrine packaged as skills, plus a tune-context configurator that scaffolds a lean CLAUDE.md, doctrine skills, subagents, settings, hooks and MCP wiring.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,13 +32,15 @@
|
|
|
32
32
|
"hooks",
|
|
33
33
|
"eval",
|
|
34
34
|
"README.md",
|
|
35
|
+
"CHANGELOG.md",
|
|
35
36
|
"LICENSE"
|
|
36
37
|
],
|
|
37
38
|
"scripts": {
|
|
39
|
+
"test": "node --test",
|
|
38
40
|
"verify:pack": "node scripts/verify-pack.mjs",
|
|
39
41
|
"verify:plugin": "node scripts/verify-plugin.mjs",
|
|
40
42
|
"smoke:init": "node scripts/smoke-init.mjs",
|
|
41
|
-
"prepublishOnly": "npm run verify:pack && npm run verify:plugin && npm run smoke:init"
|
|
43
|
+
"prepublishOnly": "npm test && npm run verify:pack && npm run verify:plugin && npm run smoke:init"
|
|
42
44
|
},
|
|
43
45
|
"publishConfig": {
|
|
44
46
|
"access": "public"
|
|
@@ -45,7 +45,9 @@ comments in the domain vocabulary someone would *search* with — better contrac
|
|
|
45
45
|
## 6. Measure, don't believe
|
|
46
46
|
If the tool logs usage (`.rag/usage.jsonl` → `rag-usage`), review it
|
|
47
47
|
periodically: is semantic search actually replacing grep? Promote or drop levers
|
|
48
|
-
on data, not faith.
|
|
48
|
+
on data, not faith. If `tune-context` is set up, `node eval/adoption-report.mjs`
|
|
49
|
+
covers the rest of this doctrine the same way — search lever, skills, subagents,
|
|
50
|
+
re-read churn — as a behavioral proxy (tool calls), not token cost.
|
|
49
51
|
|
|
50
52
|
## In a new project
|
|
51
53
|
Set up semantic search proactively — `npx -p @bglocation/code-search-mcp
|
|
@@ -43,10 +43,32 @@ not guesses); monorepo vs single project (workspaces, `packages/`, `apps/`).
|
|
|
43
43
|
| project | `./.mcp.json` |
|
|
44
44
|
| user | `~/.claude.json` → top-level `mcpServers` |
|
|
45
45
|
| local | `~/.claude.json` → `["<abs project path>"].mcpServers` |
|
|
46
|
-
|
|
|
46
|
+
| rejected | any `settings.json`: `disabledMcpjsonServers` (project `.mcp.json` servers only) |
|
|
47
47
|
|
|
48
48
|
If `CLAUDE_CONFIG_DIR` is set, `.claude.json` lives there instead of `~`.
|
|
49
49
|
|
|
50
|
+
**A rejected server is not a lever.** A project `.mcp.json` server named in
|
|
51
|
+
`disabledMcpjsonServers` (in *any* settings file) is rejected — `claude mcp get`
|
|
52
|
+
shows it as `✘ Rejected`. Skip it: no `mcp__<server>__*` permission rule, no
|
|
53
|
+
CLAUDE.md line promising a capability this session does not have. Say which
|
|
54
|
+
servers you skipped and why.
|
|
55
|
+
|
|
56
|
+
Read the neighbouring keys carefully rather than by name — the three below look
|
|
57
|
+
like the same mechanism and are not:
|
|
58
|
+
- `enabledMcpjsonServers` — an *approval* list. A `.mcp.json` server that is
|
|
59
|
+
absent from it is **⏸ pending approval**, not disabled; the user is prompted
|
|
60
|
+
and may approve it. Do not treat absence as rejection.
|
|
61
|
+
- `allowedMcpServers` / `deniedMcpServers` — arrays of **objects**
|
|
62
|
+
(`{serverName}` | `{serverUrl}` | `{serverCommand}`). They may sit in any
|
|
63
|
+
settings file and merge from every source, but they are organization policy,
|
|
64
|
+
not a per-project toggle: enforcement rests on a managed tier
|
|
65
|
+
(`managed-settings.json`, server-managed settings, MDM/registry), and matching
|
|
66
|
+
uses URL wildcards, `${VAR}` expansion and denylist-over-allowlist precedence.
|
|
67
|
+
The docs warn a `serverName` entry "is not a security control".
|
|
68
|
+
- `disabledMcpServers` / `enabledMcpServers` (note: no `json`) — a *different*
|
|
69
|
+
pair, living per-project in `~/.claude.json`, covering user-configured,
|
|
70
|
+
plugin and claude.ai servers. Disjoint from the `…Mcpjson…` keys above.
|
|
71
|
+
|
|
50
72
|
**Classify each server** — this is what turns "a server exists" into a rule:
|
|
51
73
|
|
|
52
74
|
| Type | Rule to write into the project CLAUDE.md |
|
|
@@ -65,8 +87,9 @@ If `CLAUDE_CONFIG_DIR` is set, `.claude.json` lives there instead of `~`.
|
|
|
65
87
|
**Existing config.** Note whether `./CLAUDE.md`, `.claude/settings.json`,
|
|
66
88
|
`.mcp.json`, `rag.config.json` already exist — you will merge, never clobber.
|
|
67
89
|
For `settings.json` also check `hooks.PreCompact` / `hooks.SessionStart` /
|
|
68
|
-
`hooks.PostToolUse` / `hooks.SubagentStart` for an
|
|
69
|
-
`pre-compact-snapshot.mjs` / `session-start-reinject.mjs` /
|
|
90
|
+
`hooks.PostToolUse` / `hooks.SubagentStart` / `hooks.UserPromptSubmit` for an
|
|
91
|
+
entry already calling `pre-compact-snapshot.mjs` / `session-start-reinject.mjs` /
|
|
92
|
+
`adoption-log.mjs` / `context-reminder.mjs`
|
|
70
93
|
(idempotency: skip if present — `adoption-log.mjs` is registered under both
|
|
71
94
|
`PostToolUse` and `SubagentStart`) and `permissions.allow` for entries already
|
|
72
95
|
covering the detected build/test/lint commands.
|
|
@@ -86,33 +109,69 @@ covering the detected build/test/lint commands.
|
|
|
86
109
|
`phase-workflow` are present in `~/.claude/skills/` (they ship with this tool).
|
|
87
110
|
4. **`.mcp.json`** — **merge**. Add a semantic-search server only if none was
|
|
88
111
|
detected in any scope. Preserve every existing server and key.
|
|
112
|
+
*(Skill path only — the `tune-context` CLI reads `.mcp.json` but never writes
|
|
113
|
+
it: picking which server to add is a judgment call, and the CLI runs with no
|
|
114
|
+
model in the loop.)*
|
|
89
115
|
5. **Hooks** — ensure `~/.claude/hooks/pre-compact-snapshot.mjs`,
|
|
90
116
|
`~/.claude/hooks/session-start-reinject.mjs` and `~/.claude/hooks/adoption-log.mjs`
|
|
91
117
|
exist (they ship with this tool, installed once user-level — same as the
|
|
92
|
-
doctrine skills in step 3)
|
|
118
|
+
doctrine skills in step 3), **plus `~/.claude/hooks/config-dir.mjs`** — the
|
|
119
|
+
snapshot and adoption-log scripts import it for their state paths, so
|
|
120
|
+
installing them without it means `Cannot find module` on every event.
|
|
121
|
+
Install the hooks directory as a set, never single files. Merge into `settings.json` from
|
|
93
122
|
`${CLAUDE_SKILL_DIR}/templates/settings.json.tmpl`: append the `PreCompact`
|
|
94
123
|
(matcher `"*"`, docs: omit or `*` = every trigger), `SessionStart`
|
|
95
|
-
(matcher `"compact"`), `PostToolUse` (matcher `"*"`)
|
|
96
|
-
(matcher `"*"`) entries **only if an
|
|
97
|
-
there** — treat each hook array as a
|
|
98
|
-
overwrite.
|
|
124
|
+
(matcher `"compact"`), `PostToolUse` (matcher `"*"`), `SubagentStart`
|
|
125
|
+
(matcher `"*"`) and `UserPromptSubmit` (matcher `"*"`) entries **only if an
|
|
126
|
+
entry calling that script isn't already there** — treat each hook array as a
|
|
127
|
+
set keyed by `command`, not a value to overwrite.
|
|
128
|
+
- The template's `{{HOOKS_DIR}}` slot decides where those commands point.
|
|
129
|
+
**Default: `$HOME/.claude/hooks`** — keep the literal `$HOME` (expanded when
|
|
130
|
+
the hook fires, so `settings.json` stays portable between machines).
|
|
131
|
+
**Under `CLAUDE_CONFIG_DIR`: the literal `<override>/hooks`** — that is where
|
|
132
|
+
the scripts are actually installed (the config dir moves, so must the path).
|
|
133
|
+
A hardcoded `$HOME/.claude/hooks` under an override points at a dir the
|
|
134
|
+
scripts were never copied to, and the hooks silently never fire. Verify with
|
|
135
|
+
the path cross-check in §3, not just "the command mentions the script".
|
|
99
136
|
- `PreCompact` writes a mechanical git/branch/status snapshot per-project to
|
|
100
|
-
`~/.claude/tune-context/state
|
|
101
|
-
`additionalContext`. Filesystem/git facts only — not decisions/open
|
|
102
|
-
(a hook has no model access).
|
|
137
|
+
`~/.claude/tune-context/state/` by default; `SessionStart(compact)` reads it
|
|
138
|
+
back via `additionalContext`. Filesystem/git facts only — not decisions/open
|
|
139
|
+
threads (a hook has no model access).
|
|
103
140
|
- `adoption-log.mjs` is registered under **both** `PostToolUse` (every tool
|
|
104
141
|
call) and `SubagentStart` (subagent spawns — these are NOT PostToolUse tools,
|
|
105
142
|
they fire their own event carrying `agent_type`). It appends one line per
|
|
106
|
-
event to `~/.claude/tune-context/adoption.jsonl` — which lever the
|
|
107
|
-
reached for (RAG vs grep, Skill, subagent, re-reads). Read it with
|
|
143
|
+
event to `~/.claude/tune-context/adoption.jsonl` by default — which lever the
|
|
144
|
+
model reached for (RAG vs grep, Skill, subagent, re-reads). Read it with
|
|
108
145
|
`eval/adoption-report.mjs` (the `rag-usage` analog). Behavioral proxy only:
|
|
109
146
|
no token cost (needs OTEL `claude_code.cost.usage` + a collector) and no
|
|
110
|
-
caveman (an output style, not a tool call).
|
|
147
|
+
caveman (an output style, not a tool call). Doctrine-as-method (narrow reads,
|
|
148
|
+
contracts-first edits) is likewise not `Skill`-call-visible — the verdict
|
|
149
|
+
reports zero `Skill` calls as a neutral note, not "unused", and points at the
|
|
150
|
+
edit:read ratio as a partial proxy.
|
|
151
|
+
- `context-reminder.mjs` is registered under `UserPromptSubmit` (matcher `"*"`).
|
|
152
|
+
It reads the **tail** of the session transcript (`transcript_path`, present on
|
|
153
|
+
every hook payload), sums `input_tokens + cache_read + cache_creation` — the
|
|
154
|
+
context actually re-sent — and once that crosses a PO-frozen threshold
|
|
155
|
+
(120k, override `TUNE_CONTEXT_REMIND_TOKENS`) injects one short reminder to
|
|
156
|
+
consider `/compact`. Fires **once per crossing**, re-arming only after a
|
|
157
|
+
compaction-sized drop: the reminder costs tokens on the prompt it appears in,
|
|
158
|
+
so nagging every turn would spend exactly what the tool saves. It reminds on
|
|
159
|
+
SIZE, not on "phase boundary" — size is measurable from the transcript, a
|
|
160
|
+
phase boundary is a judgment a hook (no model access) cannot make, so the
|
|
161
|
+
reminder hands that timing call to the model and `phase-workflow`.
|
|
162
|
+
- All three state paths resolve through `hooks/config-dir.mjs`'s
|
|
163
|
+
`claudeBaseDir()` — same `CLAUDE_CONFIG_DIR || ~/.claude` rule as the
|
|
164
|
+
registration paths above, so an override isolates state too, not just script
|
|
165
|
+
locations.
|
|
111
166
|
6. **`settings.json` permissions** — merge `permissions.allow`: the project's
|
|
112
167
|
safe, frequent commands (build/test/lint, `git status`/`diff`/`log`) and
|
|
113
|
-
`mcp__<server>__<tool>` for detected servers
|
|
168
|
+
`mcp__<server>__<tool>` for detected servers — **excluding servers rejected
|
|
169
|
+
via `disabledMcpjsonServers`** (see §1). Union with the existing array
|
|
114
170
|
(dedupe, never remove entries). Never add blanket `Bash(*)` or bypass modes.
|
|
115
171
|
7. **Wiki** — wire the lever chosen in detection (segment / MCP note / pointer).
|
|
172
|
+
*(Skill path only — the CLI neither detects the wiki location nor wires this
|
|
173
|
+
lever; choosing between a RAG segment, a dedicated MCP and a plain pointer
|
|
174
|
+
needs judgment.)*
|
|
116
175
|
|
|
117
176
|
Keep the generated CLAUDE.md **thin**: headings and pointers only. Depth belongs
|
|
118
177
|
in skills — that is the whole point of this setup.
|
|
@@ -132,14 +191,30 @@ in skills — that is the whole point of this setup.
|
|
|
132
191
|
should exit 0 without throwing; same for `adoption-log.mjs`).
|
|
133
192
|
- **The merge actually landed — don't just trust step 5 ran.** Re-read the
|
|
134
193
|
target `settings.json` (the same file you merged into) and parse it: confirm
|
|
135
|
-
`hooks.PreCompact`, `hooks.SessionStart`, `hooks.PostToolUse
|
|
136
|
-
`hooks.SubagentStart` each contain an entry whose
|
|
137
|
-
expected script (`pre-compact-snapshot.mjs` /
|
|
138
|
-
`adoption-log.mjs` twice, for `PostToolUse` and
|
|
194
|
+
`hooks.PreCompact`, `hooks.SessionStart`, `hooks.PostToolUse`,
|
|
195
|
+
`hooks.SubagentStart` and `hooks.UserPromptSubmit` each contain an entry whose
|
|
196
|
+
`command` references the expected script (`pre-compact-snapshot.mjs` /
|
|
197
|
+
`session-start-reinject.mjs` / `adoption-log.mjs` twice, for `PostToolUse` and
|
|
198
|
+
`SubagentStart` / `context-reminder.mjs`). Copying the
|
|
139
199
|
hook scripts to `~/.claude/hooks/` is not sufficient — a real prior incident
|
|
140
200
|
had the scripts present and executable while `settings.json` had **no**
|
|
141
201
|
`hooks` key at all, so the hooks silently never fired. Scripts-exist and
|
|
142
202
|
entries-are-registered are two different, both-required checks.
|
|
203
|
+
- **Cross-check the path, don't just match the name.** For each registered hook,
|
|
204
|
+
the path in its `command` must resolve to **the same file** you installed —
|
|
205
|
+
not merely contain the script's name. Expand `$HOME`/`${HOME}` (to
|
|
206
|
+
`CLAUDE_CONFIG_DIR`-aware `~/.claude`, the same base you install into),
|
|
207
|
+
`resolve` both sides, and compare. Under `CLAUDE_CONFIG_DIR` the script lands
|
|
208
|
+
in `$CLAUDE_CONFIG_DIR/hooks/` while a hardcoded `$HOME/.claude/hooks/` command
|
|
209
|
+
points elsewhere — both the "name is present" and "file exists" checks pass
|
|
210
|
+
independently while the wiring is broken. If a command can't be parsed for a
|
|
211
|
+
path, say so out loud; a silent OK is worse than a false alarm.
|
|
212
|
+
Check **every** command that names the script, not the first match: the merge
|
|
213
|
+
is a set keyed by command, so a path change leaves the old entry next to the
|
|
214
|
+
new one, and Claude Code runs both. At least one must resolve to the installed
|
|
215
|
+
file; any other that resolves to a **missing** file is a dead wire erroring on
|
|
216
|
+
every event — report it (with which file to remove), don't pass over it. A
|
|
217
|
+
duplicate resolving to a file that exists runs twice but works — note it.
|
|
143
218
|
- **Idempotency:** a second run would produce no changes.
|
|
144
219
|
|
|
145
220
|
Report what you created, what you merged, and anything you deliberately skipped.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
|
-
"command": "node \"
|
|
9
|
+
"command": "node \"{{HOOKS_DIR}}/pre-compact-snapshot.mjs\""
|
|
10
10
|
}
|
|
11
11
|
]
|
|
12
12
|
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"hooks": [
|
|
18
18
|
{
|
|
19
19
|
"type": "command",
|
|
20
|
-
"command": "node \"
|
|
20
|
+
"command": "node \"{{HOOKS_DIR}}/session-start-reinject.mjs\""
|
|
21
21
|
}
|
|
22
22
|
]
|
|
23
23
|
}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"hooks": [
|
|
29
29
|
{
|
|
30
30
|
"type": "command",
|
|
31
|
-
"command": "node \"
|
|
31
|
+
"command": "node \"{{HOOKS_DIR}}/adoption-log.mjs\""
|
|
32
32
|
}
|
|
33
33
|
]
|
|
34
34
|
}
|
|
@@ -39,20 +39,21 @@
|
|
|
39
39
|
"hooks": [
|
|
40
40
|
{
|
|
41
41
|
"type": "command",
|
|
42
|
-
"command": "node \"
|
|
42
|
+
"command": "node \"{{HOOKS_DIR}}/adoption-log.mjs\""
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"UserPromptSubmit": [
|
|
48
|
+
{
|
|
49
|
+
"matcher": "*",
|
|
50
|
+
"hooks": [
|
|
51
|
+
{
|
|
52
|
+
"type": "command",
|
|
53
|
+
"command": "node \"{{HOOKS_DIR}}/context-reminder.mjs\""
|
|
43
54
|
}
|
|
44
55
|
]
|
|
45
56
|
}
|
|
46
|
-
]
|
|
47
|
-
},
|
|
48
|
-
"permissions": {
|
|
49
|
-
"allow": [
|
|
50
|
-
"Bash({{BUILD_CMD}}:*)",
|
|
51
|
-
"Bash({{TEST_CMD}}:*)",
|
|
52
|
-
"Bash({{LINT_CMD}}:*)",
|
|
53
|
-
"Bash(git status:*)",
|
|
54
|
-
"Bash(git diff:*)",
|
|
55
|
-
"Bash(git log:*)"
|
|
56
57
|
]
|
|
57
58
|
}
|
|
58
59
|
}
|