@bunshin-cc/bunshin 0.3.3 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +192 -19
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -2674,6 +2674,17 @@ ${d.text.replace(/\n*$/, "\n")}`),
|
|
|
2674
2674
|
];
|
|
2675
2675
|
return parts.join("\n");
|
|
2676
2676
|
}
|
|
2677
|
+
function removeBlock(file) {
|
|
2678
|
+
const text2 = readText(file);
|
|
2679
|
+
if (text2 === null) return false;
|
|
2680
|
+
const start = text2.indexOf(BLOCK_BEGIN);
|
|
2681
|
+
const end = text2.indexOf(BLOCK_END);
|
|
2682
|
+
if (start < 0 || end < start) return false;
|
|
2683
|
+
const rest = (text2.slice(0, start).replace(/\s*$/, "") + "\n" + text2.slice(end + BLOCK_END.length).replace(/^\s*/, "")).trim();
|
|
2684
|
+
if (rest) writeTextAtomic(file, rest + "\n");
|
|
2685
|
+
else fs5.unlinkSync(file);
|
|
2686
|
+
return true;
|
|
2687
|
+
}
|
|
2677
2688
|
function writeBlock(file, block2) {
|
|
2678
2689
|
const text2 = readText(file) ?? "";
|
|
2679
2690
|
const start = text2.indexOf(BLOCK_BEGIN);
|
|
@@ -2984,9 +2995,9 @@ function deployLocked(v2, config, ctx, bundle, opts, p, harnesses, now) {
|
|
|
2984
2995
|
}
|
|
2985
2996
|
}
|
|
2986
2997
|
}
|
|
2987
|
-
const blockDocs = plan.instructions.map((s) => ({ id: s.id, version: s.version, text: next[s.id]?.pending ? readBlock(p.claudeMd)?.get(s.id) ?? s.body : s.body }));
|
|
2998
|
+
const blockDocs = config.instructionsFile ? plan.instructions.map((s) => ({ id: s.id, version: s.version, text: next[s.id]?.pending ? readBlock(p.claudeMd)?.get(s.id) ?? s.body : s.body })) : [];
|
|
2988
2999
|
if (harnesses.has("claude-code") && (blockDocs.length || readBlock(p.claudeMd))) {
|
|
2989
|
-
if (writeBlock(p.claudeMd, renderBlock(blockDocs, ""))) report.written++;
|
|
3000
|
+
if (blockDocs.length ? writeBlock(p.claudeMd, renderBlock(blockDocs, "")) : removeBlock(p.claudeMd)) report.written++;
|
|
2990
3001
|
}
|
|
2991
3002
|
if (harnesses.has("codex") && (blockDocs.length || plan.skills.length || readBlock(p.agentsMd))) {
|
|
2992
3003
|
if (writeBlock(p.agentsMd, renderBlock(blockDocs, skillIndex(plan.skills, p)))) report.written++;
|
|
@@ -7127,8 +7138,8 @@ async function cmdImport2(store, args, cwd, out, err) {
|
|
|
7127
7138
|
if (batches.length > 1) out(` batch ${i + 1}/${batches.length}: ${last.versions.length} versions${last.skipped.length ? `, ${last.skipped.length} already imported` : ""}
|
|
7128
7139
|
`);
|
|
7129
7140
|
}
|
|
7130
|
-
const
|
|
7131
|
-
out(`Imported into the library: ${written} document revisions${
|
|
7141
|
+
const lib2 = last?.versions.at(-1)?.version;
|
|
7142
|
+
out(`Imported into the library: ${written} document revisions${lib2 ? `, now lib@${lib2}` : ""}; ${last?.documents ?? 0} documents active in ${pack}.
|
|
7132
7143
|
`);
|
|
7133
7144
|
if (history) out("Old commit pins resolve with `bunshin library checkout --git <sha>`.\n");
|
|
7134
7145
|
const propose = args.flags["propose-rewrites"];
|
|
@@ -7316,8 +7327,8 @@ function sinceCutoff(since) {
|
|
|
7316
7327
|
}
|
|
7317
7328
|
function parsePin(text2) {
|
|
7318
7329
|
const t = text2.trim();
|
|
7319
|
-
const
|
|
7320
|
-
if (
|
|
7330
|
+
const lib2 = /lib@(\d+)/.exec(t) ?? /^(\d+)$/.exec(t);
|
|
7331
|
+
if (lib2) return { version: Number(lib2[1]) };
|
|
7321
7332
|
const sha2 = /\b([0-9a-f]{7,40})\b/i.exec(t);
|
|
7322
7333
|
return sha2 ? { git: sha2[1].toLowerCase() } : {};
|
|
7323
7334
|
}
|
|
@@ -7826,6 +7837,94 @@ init_v22();
|
|
|
7826
7837
|
init_transcript();
|
|
7827
7838
|
init_api();
|
|
7828
7839
|
init_deploy();
|
|
7840
|
+
|
|
7841
|
+
// src/v2/live.ts
|
|
7842
|
+
init_api();
|
|
7843
|
+
var LIVE_REFRESH_MS = 5 * 6e4;
|
|
7844
|
+
var MAX_DIFF_LINES = 80;
|
|
7845
|
+
var instructionDocs = (bundle) => (bundle?.sections ?? []).filter((s) => s.delivery === "always" && s.status === "active");
|
|
7846
|
+
var skillDocs = (bundle) => (bundle?.sections ?? []).filter((s) => !!s.skill && s.status === "active");
|
|
7847
|
+
function baselineOf(bundle) {
|
|
7848
|
+
return {
|
|
7849
|
+
...bundle?.libraryVersion !== void 0 ? { library: bundle.libraryVersion } : {},
|
|
7850
|
+
skills: Object.fromEntries(skillDocs(bundle).map((s) => [s.id, { version: s.version, name: s.skill.name }])),
|
|
7851
|
+
instructions: Object.fromEntries(instructionDocs(bundle).map((s) => [s.id, s.body]))
|
|
7852
|
+
};
|
|
7853
|
+
}
|
|
7854
|
+
var lib = (v) => v === void 0 ? "the library" : `lib@${v}`;
|
|
7855
|
+
function renderInstructions(bundle) {
|
|
7856
|
+
const docs = instructionDocs(bundle);
|
|
7857
|
+
if (!docs.length) return "";
|
|
7858
|
+
return [
|
|
7859
|
+
`## Standing instructions (your organization, from Bunshin ${lib(bundle?.libraryVersion)})`,
|
|
7860
|
+
"Follow these as you would CLAUDE.md. Bunshin re-delivers them after /clear and compaction, and tells you when they change.",
|
|
7861
|
+
"",
|
|
7862
|
+
...docs.map((d) => d.body.trim())
|
|
7863
|
+
].join("\n");
|
|
7864
|
+
}
|
|
7865
|
+
function lineDiff(before, after, max = MAX_DIFF_LINES) {
|
|
7866
|
+
const a = before.split("\n");
|
|
7867
|
+
const b = after.split("\n");
|
|
7868
|
+
if (a.length * b.length > 4e6) return [`(the text changed substantially; ${b.length} lines now)`];
|
|
7869
|
+
const dp = Array.from({ length: a.length + 1 }, () => new Uint32Array(b.length + 1));
|
|
7870
|
+
for (let i2 = a.length - 1; i2 >= 0; i2--) for (let j2 = b.length - 1; j2 >= 0; j2--) dp[i2][j2] = a[i2] === b[j2] ? dp[i2 + 1][j2 + 1] + 1 : Math.max(dp[i2 + 1][j2], dp[i2][j2 + 1]);
|
|
7871
|
+
const out = [];
|
|
7872
|
+
let i = 0;
|
|
7873
|
+
let j = 0;
|
|
7874
|
+
while (i < a.length || j < b.length) {
|
|
7875
|
+
if (i < a.length && j < b.length && a[i] === b[j]) {
|
|
7876
|
+
i++;
|
|
7877
|
+
j++;
|
|
7878
|
+
} else if (j < b.length && (i === a.length || dp[i][j + 1] >= dp[i + 1][j])) {
|
|
7879
|
+
if (b[j].trim()) out.push(`+ ${b[j]}`);
|
|
7880
|
+
j++;
|
|
7881
|
+
} else {
|
|
7882
|
+
if (a[i].trim()) out.push(`- ${a[i]}`);
|
|
7883
|
+
i++;
|
|
7884
|
+
}
|
|
7885
|
+
}
|
|
7886
|
+
return out.length > max ? [...out.slice(0, max), `\u2026 ${out.length - max} more changed lines`] : out;
|
|
7887
|
+
}
|
|
7888
|
+
function changesSince(base, bundle, skillPath) {
|
|
7889
|
+
const next = baselineOf(bundle);
|
|
7890
|
+
if (!bundle || next.library === base.library) return { text: "", next: base };
|
|
7891
|
+
const lines = [];
|
|
7892
|
+
const now = instructionDocs(bundle);
|
|
7893
|
+
for (const d of now) {
|
|
7894
|
+
const old = base.instructions[d.id];
|
|
7895
|
+
if (old === d.body) continue;
|
|
7896
|
+
if (old === void 0) {
|
|
7897
|
+
lines.push(`New standing instructions ("${d.title}"):`, d.body.trim(), "");
|
|
7898
|
+
continue;
|
|
7899
|
+
}
|
|
7900
|
+
const diff = lineDiff(old, d.body);
|
|
7901
|
+
if (diff.length) lines.push(`Standing instructions changed ("${d.title}"); follow the new text:`, ...diff, "");
|
|
7902
|
+
}
|
|
7903
|
+
for (const id of Object.keys(base.instructions)) if (!now.some((d) => d.id === id)) lines.push(`Standing instructions withdrawn (${id}): stop following them.`, "");
|
|
7904
|
+
const skillLines = [];
|
|
7905
|
+
for (const s of skillDocs(bundle)) {
|
|
7906
|
+
const old = base.skills[s.id];
|
|
7907
|
+
const where = skillPath(s.skill.name);
|
|
7908
|
+
const read = where ? `re-read \`${where}\` before using it` : `load it with \`bunshin load ${s.id}\` before using it`;
|
|
7909
|
+
if (!old) skillLines.push(`- new skill \`${s.skill.name}\`: ${s.skill.description.replace(/\s+/g, " ").trim()} (${where ? `\`${where}\`` : `\`bunshin load ${s.id}\``})`);
|
|
7910
|
+
else if (old.version !== s.version) skillLines.push(`- \`${s.skill.name}\` updated (v${old.version} \u2192 v${s.version}): ${read}`);
|
|
7911
|
+
}
|
|
7912
|
+
for (const [id, old] of Object.entries(base.skills)) if (!next.skills[id]) skillLines.push(`- \`${old.name}\` was retired: don't use it`);
|
|
7913
|
+
if (skillLines.length) lines.push("Skills:", ...skillLines);
|
|
7914
|
+
if (!lines.length) return { text: "", next };
|
|
7915
|
+
return { text: [`## Bunshin: the library changed during this session (${lib(base.library)} \u2192 ${lib(next.library)})`, ...lines].join("\n").trim(), next };
|
|
7916
|
+
}
|
|
7917
|
+
function refreshInBackground(v2, store, detach2, cwd, now = Date.now()) {
|
|
7918
|
+
if (!canCall(store.config())) return false;
|
|
7919
|
+
const state = v2.readSyncState();
|
|
7920
|
+
const last = Math.max(Date.parse(state.lastAttemptAt ?? "") || 0, Date.parse(state.lastSyncAt ?? "") || 0);
|
|
7921
|
+
if (now - last < LIVE_REFRESH_MS) return false;
|
|
7922
|
+
v2.writeSyncState({ ...state, lastAttemptAt: new Date(now).toISOString() });
|
|
7923
|
+
detach2(["--root", store.root, "sync", "--quiet"], { cwd });
|
|
7924
|
+
return true;
|
|
7925
|
+
}
|
|
7926
|
+
|
|
7927
|
+
// src/v2/hooks.ts
|
|
7829
7928
|
init_reflect2();
|
|
7830
7929
|
init_repo();
|
|
7831
7930
|
|
|
@@ -7938,7 +8037,7 @@ async function handleV2(event, ctx) {
|
|
|
7938
8037
|
case "session-start":
|
|
7939
8038
|
return onSessionStart(ctx);
|
|
7940
8039
|
case "user-prompt-submit":
|
|
7941
|
-
return onPrompt(ctx);
|
|
8040
|
+
return await onPrompt(ctx);
|
|
7942
8041
|
case "pre-tool-use":
|
|
7943
8042
|
return onPreToolUse(ctx);
|
|
7944
8043
|
case "stop":
|
|
@@ -7973,6 +8072,10 @@ async function onSessionStart(ctx) {
|
|
|
7973
8072
|
}
|
|
7974
8073
|
}
|
|
7975
8074
|
const bundle = v2.readBundle();
|
|
8075
|
+
v2.updateSession(id, ctx.cwd, (s) => {
|
|
8076
|
+
s.live = baselineOf(bundle);
|
|
8077
|
+
});
|
|
8078
|
+
const instructions = renderInstructions(bundle);
|
|
7976
8079
|
const lines = [];
|
|
7977
8080
|
for (const d of (bundle?.digest ?? []).slice(0, 5)) lines.push(`- ${d}`);
|
|
7978
8081
|
const proposed = v2.listSuggestions().filter((s) => s.status === "proposed").length;
|
|
@@ -7982,16 +8085,60 @@ async function onSessionStart(ctx) {
|
|
|
7982
8085
|
lines.push(`Open question${questions.length === 1 ? "" : "s"} for your team (ask the user when it fits; answer with \`bunshin questions answer <id> "<choice>"\`):`);
|
|
7983
8086
|
for (const q of questions) lines.push(`- [${q.id}] ${q.question}${q.options.length ? ` Options: ${q.options.join(" | ")}` : ""}`);
|
|
7984
8087
|
}
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
8088
|
+
const parts = [instructions, lines.length ? `## Bunshin
|
|
8089
|
+
${lines.join("\n")}` : ""].filter(Boolean);
|
|
8090
|
+
if (!parts.length) return {};
|
|
8091
|
+
return additional("SessionStart", parts.join("\n\n"));
|
|
8092
|
+
}
|
|
8093
|
+
function liveUpdate(v2, ctx, session) {
|
|
8094
|
+
try {
|
|
8095
|
+
refreshInBackground(v2, ctx.store, ctx.detach, ctx.cwd);
|
|
8096
|
+
const bundle = v2.readBundle();
|
|
8097
|
+
if (!session.live) {
|
|
8098
|
+
v2.updateSession(session.sessionId, ctx.cwd, (s) => {
|
|
8099
|
+
s.live = baselineOf(bundle);
|
|
8100
|
+
});
|
|
8101
|
+
return "";
|
|
8102
|
+
}
|
|
8103
|
+
const config = ctx.store.config();
|
|
8104
|
+
const deployed = deployEnabled(config, localView(v2, config, ctx.cwd).ctx);
|
|
8105
|
+
const paths = deployed ? deployPaths() : null;
|
|
8106
|
+
const root = paths ? config.harness === "codex" ? paths.codexSkills : paths.claudeSkills : null;
|
|
8107
|
+
const skillPath = (name) => root ? `${root}/${name}/SKILL.md` : null;
|
|
8108
|
+
const { text: text2, next } = changesSince(session.live, bundle, skillPath);
|
|
8109
|
+
if (next !== session.live) {
|
|
8110
|
+
v2.updateSession(session.sessionId, ctx.cwd, (s) => {
|
|
8111
|
+
s.live = next;
|
|
8112
|
+
});
|
|
8113
|
+
}
|
|
8114
|
+
if (text2) v2.log("v2-live-update", { session: session.sessionId, from: session.live.library ?? null, to: next.library ?? null });
|
|
8115
|
+
return text2;
|
|
8116
|
+
} catch {
|
|
8117
|
+
return "";
|
|
8118
|
+
}
|
|
8119
|
+
}
|
|
8120
|
+
function skillHint(sec, others) {
|
|
8121
|
+
const also = others.length ? ` Also possibly relevant: ${others.map((t) => `"${t}"`).join(", ")}.` : "";
|
|
8122
|
+
return `Bunshin: the \`${sec.skill.name}\` skill may apply: ${sec.skill.description.replace(/\s+/g, " ").trim()} If it does, invoke it (Skill tool, or \`/${sec.skill.name}\`) before doing this by hand.${also}`;
|
|
8123
|
+
}
|
|
8124
|
+
async function remoteAuto(ctx, prompt, exclude) {
|
|
8125
|
+
const config = ctx.store.config();
|
|
8126
|
+
if (!canCall(config) || !config.recall.useMothership) return null;
|
|
8127
|
+
const budget = Math.min(2500, ctx.deadline - Date.now() - 600);
|
|
8128
|
+
if (budget < 300) return null;
|
|
8129
|
+
try {
|
|
8130
|
+
const res = await v2api(config, "POST", "/recall/auto", { prompt: prompt.slice(0, 8e3), exclude }, { timeoutMs: budget });
|
|
8131
|
+
return res.available ? res : null;
|
|
8132
|
+
} catch {
|
|
8133
|
+
return null;
|
|
8134
|
+
}
|
|
7988
8135
|
}
|
|
7989
8136
|
function hintLine(titles, harness) {
|
|
7990
8137
|
const quoted = titles.map((t) => `"${t}"`).join(", ");
|
|
7991
8138
|
const how = harness === "claude-code" ? "If one could change your approach, call the bunshin_recall tool (describe the task abstractly) and load only what you need." : 'If one could change your approach, run `bunshin recall "<the task, abstractly>" --hypothetical "<the lesson you would want>"` and `bunshin load <id>`.';
|
|
7992
8139
|
return `Bunshin: possibly relevant library sections: ${quoted}. ${how}`;
|
|
7993
8140
|
}
|
|
7994
|
-
function onPrompt(ctx) {
|
|
8141
|
+
async function onPrompt(ctx) {
|
|
7995
8142
|
const prompt = ctx.input.prompt ?? "";
|
|
7996
8143
|
if (prompt.trimStart().startsWith(REFLECT_MARKER)) return {};
|
|
7997
8144
|
const v2 = new V2Store(ctx.store);
|
|
@@ -8001,11 +8148,30 @@ function onPrompt(ctx) {
|
|
|
8001
8148
|
s.lastPrompt = prompt.slice(0, 4e3);
|
|
8002
8149
|
s.lastActivityAt = now;
|
|
8003
8150
|
});
|
|
8004
|
-
|
|
8151
|
+
const live = liveUpdate(v2, ctx, session);
|
|
8152
|
+
const withLive = (out) => {
|
|
8153
|
+
if (!live) return out;
|
|
8154
|
+
const text2 = [live, out.hookSpecificOutput?.additionalContext ?? ""].filter(Boolean).join("\n\n");
|
|
8155
|
+
return additional("UserPromptSubmit", text2);
|
|
8156
|
+
};
|
|
8157
|
+
if (!prompt.trim()) return withLive({});
|
|
8005
8158
|
const config = ctx.store.config();
|
|
8006
8159
|
const view = localView(v2, config, ctx.cwd);
|
|
8007
8160
|
const injected = [...session.loaded, ...session.pushed];
|
|
8008
8161
|
const res = auto(view.sections, view.reader, prompt, { exclude: injected });
|
|
8162
|
+
const remote = await remoteAuto(ctx, prompt, injected);
|
|
8163
|
+
if (remote) {
|
|
8164
|
+
const local = (id) => view.sections.find((s) => s.id === id);
|
|
8165
|
+
if (remote.section) {
|
|
8166
|
+
res.section = local(remote.section.id) ?? remote.section;
|
|
8167
|
+
res.anchor = void 0;
|
|
8168
|
+
res.reason = `dense ${remote.reason ?? ""}`.trim();
|
|
8169
|
+
} else {
|
|
8170
|
+
res.section = void 0;
|
|
8171
|
+
res.hint = (remote.hint ?? []).map((h) => ({ id: h.id, title: local(h.id)?.title ?? h.title }));
|
|
8172
|
+
res.reason = `dense ${remote.reason ?? ""}`.trim();
|
|
8173
|
+
}
|
|
8174
|
+
}
|
|
8009
8175
|
if (res.section) {
|
|
8010
8176
|
const sec = res.section;
|
|
8011
8177
|
v2.updateSession(session.sessionId, ctx.cwd, (s) => {
|
|
@@ -8013,16 +8179,18 @@ function onPrompt(ctx) {
|
|
|
8013
8179
|
addUnique(s.loaded, sec.id);
|
|
8014
8180
|
});
|
|
8015
8181
|
v2.log("v2-auto", { session: session.sessionId, section: sec.id, reason: res.reason });
|
|
8016
|
-
return additional("UserPromptSubmit", renderSection(sec, "your prompt matches it", { ...res.anchor ? { anchor: res.anchor } : {}, deployed: !!sec.skill && deployEnabled(config, view.ctx) }));
|
|
8182
|
+
return withLive(additional("UserPromptSubmit", renderSection(sec, "your prompt matches it", { ...res.anchor ? { anchor: res.anchor } : {}, deployed: !!sec.skill && deployEnabled(config, view.ctx) })));
|
|
8017
8183
|
}
|
|
8018
8184
|
const fresh = res.hint.filter((h) => !session.hinted?.includes(h.id)).slice(0, 3);
|
|
8019
|
-
if (!fresh.length) return {};
|
|
8185
|
+
if (!fresh.length) return withLive({});
|
|
8020
8186
|
v2.updateSession(session.sessionId, ctx.cwd, (s) => {
|
|
8021
8187
|
s.hinted = s.hinted ?? [];
|
|
8022
8188
|
addUnique(s.hinted, ...fresh.map((h) => h.id));
|
|
8023
8189
|
addUnique(s.served, ...fresh.map((h) => h.id));
|
|
8024
8190
|
});
|
|
8025
|
-
|
|
8191
|
+
const topSkill = view.sections.find((s) => s.id === fresh[0].id && s.skill);
|
|
8192
|
+
if (topSkill && deployEnabled(config, view.ctx)) return withLive(additional("UserPromptSubmit", skillHint(topSkill, fresh.slice(1).map((h) => h.title))));
|
|
8193
|
+
return withLive(additional("UserPromptSubmit", hintLine(fresh.map((h) => h.title), config.harness)));
|
|
8026
8194
|
}
|
|
8027
8195
|
function toolPaths(input) {
|
|
8028
8196
|
if (!input || typeof input !== "object") return [];
|
|
@@ -8038,16 +8206,21 @@ function onPreToolUse(ctx) {
|
|
|
8038
8206
|
const session = touch(v2, ctx, (s) => {
|
|
8039
8207
|
s.lastActivityAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8040
8208
|
});
|
|
8209
|
+
const live = liveUpdate(v2, ctx, session);
|
|
8210
|
+
const withLive = (out) => {
|
|
8211
|
+
if (!live) return out;
|
|
8212
|
+
return additional("PreToolUse", [live, out.hookSpecificOutput?.additionalContext ?? ""].filter(Boolean).join("\n\n"));
|
|
8213
|
+
};
|
|
8041
8214
|
const raw = toolPaths(ctx.input.tool_input);
|
|
8042
|
-
if (!raw.length) return {};
|
|
8215
|
+
if (!raw.length) return withLive({});
|
|
8043
8216
|
const config = ctx.store.config();
|
|
8044
8217
|
const view = localView(v2, config, ctx.cwd);
|
|
8045
8218
|
const paths = raw.map((p) => relativeToRoot(view.root, p, ctx.cwd)).filter((p) => !!p);
|
|
8046
8219
|
const text2 = [session.task, session.lastPrompt].filter(Boolean).join("\n");
|
|
8047
|
-
if (!paths.length && !text2) return {};
|
|
8220
|
+
if (!paths.length && !text2) return withLive({});
|
|
8048
8221
|
const seen = /* @__PURE__ */ new Set([...session.pushed, ...session.loaded]);
|
|
8049
8222
|
const hits = push(view.sections, view.reader, { paths, text: text2 }).filter((h) => !seen.has(h.section.id)).slice(0, MAX_PUSH);
|
|
8050
|
-
if (!hits.length) return {};
|
|
8223
|
+
if (!hits.length) return withLive({});
|
|
8051
8224
|
const ids = hits.map((h) => h.section.id);
|
|
8052
8225
|
v2.updateSession(session.sessionId, ctx.cwd, (s) => {
|
|
8053
8226
|
addUnique(s.pushed, ...ids);
|
|
@@ -8056,7 +8229,7 @@ function onPreToolUse(ctx) {
|
|
|
8056
8229
|
});
|
|
8057
8230
|
v2.log("v2-push", { session: session.sessionId, tool: ctx.input.tool_name, hits: hits.map((h) => `${h.section.id} ${h.trigger}`) });
|
|
8058
8231
|
const deployed = deployEnabled(config, view.ctx);
|
|
8059
|
-
return additional("PreToolUse", hits.map((h) => renderSection(h.section, h.trigger, { ...h.anchor ? { anchor: h.anchor } : {}, deployed: deployed && !!h.section.skill })).join("\n\n"));
|
|
8232
|
+
return withLive(additional("PreToolUse", hits.map((h) => renderSection(h.section, h.trigger, { ...h.anchor ? { anchor: h.anchor } : {}, deployed: deployed && !!h.section.skill })).join("\n\n")));
|
|
8060
8233
|
}
|
|
8061
8234
|
function onStop(ctx) {
|
|
8062
8235
|
const v2 = new V2Store(ctx.store);
|