@dadado/agent-kit-cli 5.15.1 → 5.16.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.
Files changed (71) hide show
  1. package/dashboard/dashboard-data.mjs +69 -65
  2. package/dashboard/lib/guards.d.mts +5 -0
  3. package/dashboard/lib/guards.mjs +31 -0
  4. package/dashboard/lib/identity-probe.mjs +56 -0
  5. package/dashboard/lib/pipeline-cache.mjs +58 -0
  6. package/dashboard/lib/processes.mjs +71 -0
  7. package/dashboard/serve.mjs +43 -1
  8. package/dashboard/start-broadcast.mjs +2 -12
  9. package/dashboard/start.mjs +2 -13
  10. package/dist/add-7UMSGVWC.js +150 -0
  11. package/dist/chunk-2IPXQFJE.js +253 -0
  12. package/dist/chunk-2YU2H7I6.js +42 -0
  13. package/dist/chunk-4IWG5CVE.js +214 -0
  14. package/dist/chunk-5OXPNVCF.js +106 -0
  15. package/dist/chunk-5VCOWTTP.js +6 -0
  16. package/dist/chunk-6QV2BFGA.js +341 -0
  17. package/dist/chunk-77V75A7O.js +39 -0
  18. package/dist/chunk-7HDQEK6T.js +26 -0
  19. package/dist/chunk-CBCW5R5J.js +484 -0
  20. package/dist/chunk-CGTE7DHN.js +410 -0
  21. package/dist/chunk-DE3LQFSJ.js +18 -0
  22. package/dist/chunk-F6C3GFKV.js +57 -0
  23. package/dist/chunk-HFUH3HVS.js +282 -0
  24. package/dist/chunk-HS7LVVLO.js +74 -0
  25. package/dist/chunk-IHROBTNM.js +135 -0
  26. package/dist/chunk-KD2MYBB6.js +213 -0
  27. package/dist/chunk-KI6ZHBPV.js +332 -0
  28. package/dist/chunk-MAPOQEA2.js +43 -0
  29. package/dist/chunk-NQ7IQ5XT.js +26 -0
  30. package/dist/chunk-OUQZC744.js +1315 -0
  31. package/dist/chunk-OZ4QV6LM.js +1078 -0
  32. package/dist/chunk-PCCQUWE5.js +817 -0
  33. package/dist/chunk-PNFF6OU3.js +273 -0
  34. package/dist/chunk-QTON2GQX.js +203 -0
  35. package/dist/chunk-TFZ2JUXH.js +1081 -0
  36. package/dist/chunk-VGZBARQC.js +318 -0
  37. package/dist/chunk-VS2JD2XC.js +1453 -0
  38. package/dist/chunk-VY7MTPJ2.js +205 -0
  39. package/dist/chunk-WW3YZKHW.js +165 -0
  40. package/dist/chunk-XWPO3VYQ.js +53 -0
  41. package/dist/chunk-XZZAVHH4.js +503 -0
  42. package/dist/chunk-YGBBHKBE.js +82 -0
  43. package/dist/chunk-ZB43YMHW.js +20 -0
  44. package/dist/chunk-ZCTSUQRR.js +874 -0
  45. package/dist/chunk-ZXKZBTXE.js +17 -0
  46. package/dist/contribute-YKK6YCSI.js +367 -0
  47. package/dist/cursor-awareness-KTL2RGKD.js +77 -0
  48. package/dist/dashboard-YSNUGBFY.js +21 -0
  49. package/dist/dashboard-broadcast-M4CMW7RX.js +119 -0
  50. package/dist/diff-YTR7VOAN.js +74 -0
  51. package/dist/doctor-TA2FWREU.js +497 -0
  52. package/dist/dogfood-KKFVRWT6.js +366 -0
  53. package/dist/guard-EHXF76ID.js +530 -0
  54. package/dist/handoff-3UI6VKVG.js +302 -0
  55. package/dist/hook-MUV6Y7UW.js +1074 -0
  56. package/dist/index.js +62 -14068
  57. package/dist/init-TTTKGC4C.js +127 -0
  58. package/dist/install-ZMFJBPOI.js +34 -0
  59. package/dist/mission-control-LJACEVVN.js +89 -0
  60. package/dist/monitors-QV2IS3MP.js +176 -0
  61. package/dist/plan-index-JMC7Z4DW.js +44 -0
  62. package/dist/public-inbound-radar-WP3XF7GS.js +68 -0
  63. package/dist/remote-issues-SZ4HDQL5.js +44 -0
  64. package/dist/run-I3BFGULT.js +243 -0
  65. package/dist/run-plan-FO7CL4M3.js +118 -0
  66. package/dist/scan-NI2SWJ2E.js +33 -0
  67. package/dist/setup-global-JUVMJXJ5.js +340 -0
  68. package/dist/status-MVCUNCWX.js +138 -0
  69. package/dist/update-Q4EBIRUB.js +260 -0
  70. package/dist/validate-V2CW7J4B.js +201 -0
  71. package/package.json +1 -1
@@ -0,0 +1,410 @@
1
+ import {
2
+ INTERACTIVE_DENY_RULES
3
+ } from "./chunk-MAPOQEA2.js";
4
+ import {
5
+ assertRealContained,
6
+ assertRealParentContained,
7
+ isRealWriteTargetContained,
8
+ resolveContained
9
+ } from "./chunk-VS2JD2XC.js";
10
+ import {
11
+ ensureDir
12
+ } from "./chunk-77V75A7O.js";
13
+
14
+ // src/generator/claude-session-start-hook.ts
15
+ import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
16
+ import path2 from "path";
17
+
18
+ // src/generator/claude-settings-ledger.ts
19
+ import { lstat, mkdir, readFile, writeFile } from "fs/promises";
20
+ import path from "path";
21
+ var CLAUDE_SETTINGS_LEDGER_REL = ".cursor/agent-kit.claude-settings.json";
22
+ var ClaudeSettingsLedgerSymlinkError = class extends Error {
23
+ constructor(path3, detail) {
24
+ super(`Refusing to use Claude settings ledger ${path3}: ${detail}`);
25
+ this.path = path3;
26
+ this.name = "ClaudeSettingsLedgerSymlinkError";
27
+ }
28
+ path;
29
+ };
30
+ var ClaudeSettingsLedgerInvalidError = class extends Error {
31
+ constructor(path3) {
32
+ super(
33
+ `Claude settings ledger ${path3} is malformed or has an unknown schemaVersion; not overwriting without authorization.`
34
+ );
35
+ this.path = path3;
36
+ this.name = "ClaudeSettingsLedgerInvalidError";
37
+ }
38
+ path;
39
+ };
40
+ function emptyLedger() {
41
+ return { schemaVersion: 1, denyRowsWritten: [], hookEntriesWritten: [] };
42
+ }
43
+ function hookKey(r) {
44
+ return `${r.event}\0${r.marker}`;
45
+ }
46
+ function normalize(denyRows, hooks) {
47
+ const seen = /* @__PURE__ */ new Map();
48
+ for (const h of hooks) seen.set(hookKey(h), { event: h.event, marker: h.marker });
49
+ return {
50
+ schemaVersion: 1,
51
+ denyRowsWritten: [...new Set(denyRows)].sort(),
52
+ hookEntriesWritten: [...seen.values()].sort(
53
+ (a, b) => a.event.localeCompare(b.event) || a.marker.localeCompare(b.marker)
54
+ )
55
+ };
56
+ }
57
+ function parseLedger(raw) {
58
+ let data;
59
+ try {
60
+ data = JSON.parse(raw);
61
+ } catch {
62
+ return null;
63
+ }
64
+ if (typeof data !== "object" || data === null || Array.isArray(data)) return null;
65
+ const o = data;
66
+ if (o.schemaVersion !== 1) return null;
67
+ if (!Array.isArray(o.denyRowsWritten) || !o.denyRowsWritten.every((r) => typeof r === "string")) {
68
+ return null;
69
+ }
70
+ if (!Array.isArray(o.hookEntriesWritten)) return null;
71
+ const hooks = [];
72
+ for (const h of o.hookEntriesWritten) {
73
+ if (typeof h !== "object" || h === null || typeof h.event !== "string" || typeof h.marker !== "string") {
74
+ return null;
75
+ }
76
+ hooks.push({
77
+ event: h.event,
78
+ marker: h.marker
79
+ });
80
+ }
81
+ return normalize(o.denyRowsWritten, hooks);
82
+ }
83
+ async function readState(root) {
84
+ const abs = resolveContained(root, CLAUDE_SETTINGS_LEDGER_REL);
85
+ let exists = true;
86
+ try {
87
+ await lstat(abs);
88
+ } catch {
89
+ exists = false;
90
+ }
91
+ try {
92
+ if (exists) await assertRealContained(root, abs);
93
+ else await assertRealParentContained(root, abs);
94
+ } catch (err) {
95
+ throw new ClaudeSettingsLedgerSymlinkError(
96
+ abs,
97
+ err instanceof Error ? err.message : String(err)
98
+ );
99
+ }
100
+ if (!exists) return { abs, state: { kind: "missing" } };
101
+ const ledger = parseLedger(await readFile(abs, "utf8"));
102
+ return { abs, state: ledger ? { kind: "ok", ledger } : { kind: "invalid" } };
103
+ }
104
+ async function loadClaudeSettingsLedger(root) {
105
+ const { state } = await readState(root);
106
+ return state.kind === "ok" ? state.ledger : null;
107
+ }
108
+ async function saveClaudeSettingsLedger(root, additions, opts = {}) {
109
+ const { abs, state } = await readState(root);
110
+ if (state.kind === "invalid" && !opts.overwriteInvalid) {
111
+ throw new ClaudeSettingsLedgerInvalidError(abs);
112
+ }
113
+ const base = state.kind === "ok" ? state.ledger : emptyLedger();
114
+ const merged = normalize(
115
+ [...base.denyRowsWritten, ...additions.denyRowsWritten ?? []],
116
+ [...base.hookEntriesWritten, ...additions.hookEntriesWritten ?? []]
117
+ );
118
+ await mkdir(path.dirname(abs), { recursive: true });
119
+ await writeFile(abs, `${JSON.stringify(merged, null, 2)}
120
+ `, "utf8");
121
+ return merged;
122
+ }
123
+
124
+ // src/generator/claude-session-start-hook.ts
125
+ var CLAUDE_SETTINGS_REL = ".claude/settings.json";
126
+ var RESOLVE_AGENT_KIT_REL = ".cursor/hooks/agent/resolve-agent-kit.sh";
127
+ var SESSION_START_HOOK_MARKER = "hook session-start --format claude";
128
+ var SESSION_START_DEGRADED_TEXT = "Agent Kit hooks are running in degraded fail-open mode: the agent-kit CLI could not be resolved (checked AGENT_KIT_HOOK_BIN, node_modules/.bin/agent-kit, PATH), or it resolved to a node script and node is not on PATH. Slash command adapters still work; session-context injection is inactive. Fix: install the CLI (npm i -D @dadado/agent-kit-cli), put node on PATH, or set AGENT_KIT_HOOK_BIN.";
129
+ function buildSessionStartHookCommand() {
130
+ const run = `{ if command -v run_agent_kit >/dev/null 2>&1; then run_agent_kit ${SESSION_START_HOOK_MARKER}; else exec $AGENT_KIT_RESOLVED ${SESSION_START_HOOK_MARKER}; fi; }`;
131
+ return `_AGENT_KIT_HOOK_ROOT="\${CLAUDE_PROJECT_DIR}"; . "\${CLAUDE_PROJECT_DIR}/${RESOLVE_AGENT_KIT_REL}" 2>/dev/null && resolve_agent_kit && ${run}; printf '%s' ${shellSingleQuote(SESSION_START_DEGRADED_TEXT)}`;
132
+ }
133
+ var GUARD_SHELL_HOOK_MARKER = "guard shell --format claude";
134
+ function buildGuardShellHookCommand() {
135
+ const run = `{ if command -v run_agent_kit >/dev/null 2>&1; then run_agent_kit ${GUARD_SHELL_HOOK_MARKER}; else exec $AGENT_KIT_RESOLVED ${GUARD_SHELL_HOOK_MARKER}; fi; }`;
136
+ return `_AGENT_KIT_HOOK_ROOT="\${CLAUDE_PROJECT_DIR}"; . "\${CLAUDE_PROJECT_DIR}/${RESOLVE_AGENT_KIT_REL}" 2>/dev/null && resolve_agent_kit && ${run}; :`;
137
+ }
138
+ function buildGuardShellHookEntry() {
139
+ return { type: "command", command: buildGuardShellHookCommand(), timeout: 10 };
140
+ }
141
+ function shellSingleQuote(text) {
142
+ return `'${text.replace(/'/g, "'\\''")}'`;
143
+ }
144
+ function buildSessionStartHookEntry() {
145
+ return {
146
+ type: "command",
147
+ command: buildSessionStartHookCommand(),
148
+ timeout: 15,
149
+ statusMessage: "Loading Agent Kit session context"
150
+ };
151
+ }
152
+ function isPlainObject(value) {
153
+ return typeof value === "object" && value !== null && !Array.isArray(value);
154
+ }
155
+ function groupHasMarker(group, marker) {
156
+ if (!isPlainObject(group) || !Array.isArray(group.hooks)) return false;
157
+ return group.hooks.some(
158
+ (h) => isPlainObject(h) && typeof h.command === "string" && h.command.includes(marker)
159
+ );
160
+ }
161
+ function upsertMarkedGroup(arr, group, marker) {
162
+ const existingIndex = arr.findIndex((g) => groupHasMarker(g, marker));
163
+ if (existingIndex === -1) {
164
+ arr.push(group);
165
+ return "applied";
166
+ }
167
+ if (JSON.stringify(arr[existingIndex]) === JSON.stringify(group)) return "unchanged";
168
+ arr[existingIndex] = group;
169
+ return "refreshed";
170
+ }
171
+ var SESSION_START_EVENT = "SessionStart";
172
+ var PRE_TOOL_USE_EVENT = "PreToolUse";
173
+ function mergeSessionStartHookIntoSettings(existingRaw, opts = {}) {
174
+ const ledger = opts.ledger ?? null;
175
+ const authorized = opts.authorized ?? true;
176
+ const entry = buildSessionStartHookEntry();
177
+ const newGroup = { hooks: [entry] };
178
+ let root = {};
179
+ if (existingRaw !== null && existingRaw.trim() !== "") {
180
+ try {
181
+ const parsed = JSON.parse(existingRaw);
182
+ if (!isPlainObject(parsed)) throw new Error("root is not an object");
183
+ root = parsed;
184
+ } catch {
185
+ return {
186
+ content: null,
187
+ status: "unavailable",
188
+ instructions: instructionsBlock(entry)
189
+ };
190
+ }
191
+ }
192
+ const pending = { denyRows: [], hookEntries: [] };
193
+ const additions = { denyRowsWritten: [], hookEntriesWritten: [] };
194
+ const hooks = isPlainObject(root.hooks) ? { ...root.hooks } : {};
195
+ const sessionStart = Array.isArray(hooks.SessionStart) ? [...hooks.SessionStart] : [];
196
+ const preToolUse = Array.isArray(hooks.PreToolUse) ? [...hooks.PreToolUse] : [];
197
+ const upserts = [
198
+ upsertLedgerAwareGroup({
199
+ arr: sessionStart,
200
+ group: newGroup,
201
+ event: SESSION_START_EVENT,
202
+ marker: SESSION_START_HOOK_MARKER
203
+ }),
204
+ upsertLedgerAwareGroup({
205
+ arr: preToolUse,
206
+ group: { matcher: "Bash", hooks: [buildGuardShellHookEntry()] },
207
+ event: PRE_TOOL_USE_EVENT,
208
+ marker: GUARD_SHELL_HOOK_MARKER
209
+ })
210
+ ];
211
+ hooks.SessionStart = sessionStart;
212
+ hooks.PreToolUse = preToolUse;
213
+ root.hooks = hooks;
214
+ function upsertLedgerAwareGroup(g) {
215
+ const record = { event: g.event, marker: g.marker };
216
+ if (g.arr.some((x) => groupHasMarker(x, g.marker))) {
217
+ additions.hookEntriesWritten.push(record);
218
+ return upsertMarkedGroup(g.arr, g.group, g.marker);
219
+ }
220
+ if (ledger?.hookEntriesWritten.some((h) => h.event === g.event && h.marker === g.marker)) {
221
+ return "unchanged";
222
+ }
223
+ if (ledger === null && !authorized) {
224
+ pending.hookEntries.push(record);
225
+ return "unchanged";
226
+ }
227
+ additions.hookEntriesWritten.push(record);
228
+ return upsertMarkedGroup(g.arr, g.group, g.marker);
229
+ }
230
+ const status = upserts.reduce(
231
+ (acc, next, i) => i === 0 ? next : combineStatus(acc, next),
232
+ "unchanged"
233
+ );
234
+ const denyAdded = mergeKitDenyRules(root, { ledger, authorized }, pending, additions);
235
+ const finalStatus = denyAdded && status === "unchanged" ? "refreshed" : status;
236
+ return {
237
+ content: `${JSON.stringify(root, null, 2)}
238
+ `,
239
+ status: finalStatus,
240
+ pending,
241
+ ledgerAdditions: additions
242
+ };
243
+ }
244
+ function combineStatus(a, b) {
245
+ return a === "unchanged" && b !== "unchanged" ? "refreshed" : a;
246
+ }
247
+ function mergeKitDenyRules(root, ctx, pending, additions) {
248
+ if (root.permissions !== void 0 && !isPlainObject(root.permissions)) return false;
249
+ const permissions = isPlainObject(root.permissions) ? { ...root.permissions } : {};
250
+ if (permissions.deny !== void 0 && !Array.isArray(permissions.deny)) return false;
251
+ const deny = Array.isArray(permissions.deny) ? [...permissions.deny] : [];
252
+ const written = new Set(ctx.ledger?.denyRowsWritten ?? []);
253
+ for (const rule of INTERACTIVE_DENY_RULES) {
254
+ if (deny.includes(rule)) additions.denyRowsWritten.push(rule);
255
+ }
256
+ const missing = INTERACTIVE_DENY_RULES.filter(
257
+ (rule) => !deny.includes(rule) && !written.has(rule)
258
+ );
259
+ const toAdd = ctx.ledger === null && !ctx.authorized ? [] : missing;
260
+ if (ctx.ledger === null && !ctx.authorized) pending.denyRows.push(...missing);
261
+ if (toAdd.length === 0) return false;
262
+ additions.denyRowsWritten.push(...toAdd);
263
+ permissions.deny = [...deny, ...toAdd];
264
+ root.permissions = permissions;
265
+ return true;
266
+ }
267
+ function instructionsBlock(entry) {
268
+ return [
269
+ `Could not parse the existing ${CLAUDE_SETTINGS_REL} as JSON, so Agent Kit did not touch it.`,
270
+ "Add these hooks by hand (create the arrays if they do not exist).",
271
+ "Under hooks.SessionStart:",
272
+ "",
273
+ JSON.stringify(entry, null, 2),
274
+ "",
275
+ 'Under hooks.PreToolUse, in a group with "matcher": "Bash":',
276
+ "",
277
+ JSON.stringify(buildGuardShellHookEntry(), null, 2)
278
+ ].join("\n");
279
+ }
280
+ async function writeClaudeSessionStartHook(rootDir, opts = {}) {
281
+ const authorized = opts.authorized ?? true;
282
+ const abs = resolveContained(rootDir, CLAUDE_SETTINGS_REL);
283
+ if (!await isRealWriteTargetContained(rootDir, abs)) {
284
+ return { relativePath: CLAUDE_SETTINGS_REL, status: "skipped-symlink" };
285
+ }
286
+ let ledger;
287
+ try {
288
+ ledger = await loadClaudeSettingsLedger(rootDir);
289
+ } catch (err) {
290
+ if (err instanceof ClaudeSettingsLedgerSymlinkError) {
291
+ return { relativePath: CLAUDE_SETTINGS_REL, status: "skipped-symlink" };
292
+ }
293
+ throw err;
294
+ }
295
+ let existing = null;
296
+ try {
297
+ existing = await readFile2(abs, "utf8");
298
+ } catch {
299
+ existing = null;
300
+ }
301
+ const merged = mergeSessionStartHookIntoSettings(existing, { ledger, authorized });
302
+ if (merged.status === "unavailable" || merged.content === null) {
303
+ return {
304
+ relativePath: CLAUDE_SETTINGS_REL,
305
+ status: "unavailable",
306
+ instructions: merged.instructions
307
+ };
308
+ }
309
+ if (merged.status !== "unchanged") {
310
+ await ensureDir(path2.dirname(abs));
311
+ await writeFile2(abs, merged.content, "utf8");
312
+ }
313
+ const result = {
314
+ relativePath: CLAUDE_SETTINGS_REL,
315
+ status: merged.status
316
+ };
317
+ if (merged.pending && (merged.pending.denyRows.length || merged.pending.hookEntries.length)) {
318
+ result.pending = merged.pending;
319
+ }
320
+ if (authorized && merged.ledgerAdditions && ledgerGrows(ledger, merged.ledgerAdditions)) {
321
+ await saveClaudeSettingsLedger(rootDir, merged.ledgerAdditions, { overwriteInvalid: true });
322
+ result.ledgerPath = CLAUDE_SETTINGS_LEDGER_REL;
323
+ }
324
+ return result;
325
+ }
326
+ function ledgerGrows(ledger, add) {
327
+ if (ledger === null) return true;
328
+ const rows = new Set(ledger.denyRowsWritten);
329
+ const hooks = new Set(ledger.hookEntriesWritten.map((h) => `${h.event}\0${h.marker}`));
330
+ return add.denyRowsWritten.some((r) => !rows.has(r)) || add.hookEntriesWritten.some((h) => !hooks.has(`${h.event}\0${h.marker}`));
331
+ }
332
+ async function planClaudeSettingsDrift(rootDir) {
333
+ const abs = resolveContained(rootDir, CLAUDE_SETTINGS_REL);
334
+ if (!await isRealWriteTargetContained(rootDir, abs)) return null;
335
+ let raw;
336
+ try {
337
+ raw = await readFile2(abs, "utf8");
338
+ } catch {
339
+ return null;
340
+ }
341
+ let existing;
342
+ try {
343
+ const parsed = JSON.parse(raw);
344
+ if (!isPlainObject(parsed)) return null;
345
+ existing = parsed;
346
+ } catch {
347
+ return null;
348
+ }
349
+ const hooks = isPlainObject(existing.hooks) ? existing.hooks : {};
350
+ const groupsOf = (event) => Array.isArray(hooks[event]) ? hooks[event] : [];
351
+ const kitEntries = [
352
+ { event: SESSION_START_EVENT, marker: SESSION_START_HOOK_MARKER },
353
+ { event: PRE_TOOL_USE_EVENT, marker: GUARD_SHELL_HOOK_MARKER }
354
+ ];
355
+ const present = kitEntries.filter(
356
+ (e) => groupsOf(e.event).some((g) => groupHasMarker(g, e.marker))
357
+ );
358
+ if (present.length === 0) return null;
359
+ let ledger;
360
+ try {
361
+ ledger = await loadClaudeSettingsLedger(rootDir);
362
+ } catch (err) {
363
+ if (err instanceof ClaudeSettingsLedgerSymlinkError) return null;
364
+ throw err;
365
+ }
366
+ const merged = mergeSessionStartHookIntoSettings(raw, { ledger, authorized: false });
367
+ if (merged.content === null) return null;
368
+ const next = JSON.parse(merged.content);
369
+ const deny = (r) => isPlainObject(r.permissions) && Array.isArray(r.permissions.deny) ? r.permissions.deny.filter((x) => typeof x === "string") : [];
370
+ const had = new Set(deny(existing));
371
+ const denyRows = deny(next).filter((r) => !had.has(r));
372
+ const ambiguousDenyRows = merged.pending?.denyRows ?? [];
373
+ const missingEntries = kitEntries.filter((e) => !present.includes(e));
374
+ const ledgerHas = (e) => Boolean(ledger?.hookEntriesWritten.some((h) => h.event === e.event && h.marker === e.marker));
375
+ const hookEntries = missingEntries.filter((e) => !ledgerHas(e));
376
+ if (denyRows.length === 0 && ambiguousDenyRows.length === 0 && hookEntries.length === 0) {
377
+ return null;
378
+ }
379
+ return { denyRows, ambiguousDenyRows, hookEntries };
380
+ }
381
+ function formatClaudeSettingsDrift(report, opts) {
382
+ const rows = [...report.denyRows, ...report.ambiguousDenyRows];
383
+ const lines = [
384
+ `Claude settings drift in ${CLAUDE_SETTINGS_REL}${opts.protectedPath ? " (protected (skipped))" : ""}: update did not write it.`
385
+ ];
386
+ if (rows.length > 0) {
387
+ lines.push("Add to permissions.deny:", JSON.stringify(rows, null, 2));
388
+ if (report.ambiguousDenyRows.length > 0) {
389
+ lines.push(
390
+ `(${report.ambiguousDenyRows.length} row(s) ambiguous: no ${CLAUDE_SETTINGS_LEDGER_REL} ledger, so a deliberate deletion cannot be told apart.)`
391
+ );
392
+ }
393
+ }
394
+ if (report.hookEntries.length > 0) {
395
+ lines.push("Missing hook entries (add by hand or use the command below):");
396
+ for (const e of report.hookEntries) lines.push(` ${e.event}: ${e.marker}`);
397
+ }
398
+ lines.push("Apply with: agent-kit update --claude");
399
+ return lines;
400
+ }
401
+
402
+ export {
403
+ CLAUDE_SETTINGS_REL,
404
+ RESOLVE_AGENT_KIT_REL,
405
+ SESSION_START_HOOK_MARKER,
406
+ GUARD_SHELL_HOOK_MARKER,
407
+ writeClaudeSessionStartHook,
408
+ planClaudeSettingsDrift,
409
+ formatClaudeSettingsDrift
410
+ };
@@ -0,0 +1,18 @@
1
+ // src/hooks/read-stdin-json.ts
2
+ async function readStdinJson() {
3
+ const chunks = [];
4
+ for await (const chunk of process.stdin) {
5
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
6
+ }
7
+ const raw = Buffer.concat(chunks).toString("utf8").trim();
8
+ if (!raw) return {};
9
+ try {
10
+ return JSON.parse(raw);
11
+ } catch {
12
+ return {};
13
+ }
14
+ }
15
+
16
+ export {
17
+ readStdinJson
18
+ };
@@ -0,0 +1,57 @@
1
+ // src/types.ts
2
+ var GIT_PLATFORM_META = {
3
+ github: {
4
+ cli: "gh",
5
+ prTerm: "Pull Request",
6
+ prCommand: "gh pr create",
7
+ ciDefault: "github-actions"
8
+ },
9
+ gitlab: {
10
+ cli: "glab",
11
+ prTerm: "Merge Request",
12
+ prCommand: "glab mr create",
13
+ ciDefault: "gitlab-ci"
14
+ },
15
+ bitbucket: {
16
+ cli: "bb",
17
+ prTerm: "Pull Request",
18
+ prCommand: "bb pr create",
19
+ ciDefault: "bitbucket-pipelines"
20
+ },
21
+ "azure-devops": {
22
+ cli: "az repos",
23
+ prTerm: "Pull Request",
24
+ prCommand: "az repos pr create",
25
+ ciDefault: "azure-pipelines"
26
+ },
27
+ gitea: { cli: "tea", prTerm: "Pull Request", prCommand: "tea pr create", ciDefault: "none" }
28
+ };
29
+ var CI_PLATFORM_FILES = {
30
+ "github-actions": ".github/workflows",
31
+ "gitlab-ci": ".gitlab-ci.yml",
32
+ "azure-pipelines": "azure-pipelines.yml",
33
+ "bitbucket-pipelines": "bitbucket-pipelines.yml",
34
+ jenkins: "Jenkinsfile",
35
+ circleci: ".circleci/config.yml",
36
+ travis: ".travis.yml"
37
+ };
38
+ var PM_TOOL_LABELS = {
39
+ clickup: "ClickUp",
40
+ jira: "Jira",
41
+ linear: "Linear",
42
+ asana: "Asana",
43
+ "github-issues": "GitHub Issues",
44
+ "github-projects": "GitHub Projects",
45
+ "azure-boards": "Azure Boards",
46
+ trello: "Trello",
47
+ shortcut: "Shortcut",
48
+ notion: "Notion",
49
+ youtrack: "YouTrack",
50
+ none: "None"
51
+ };
52
+
53
+ export {
54
+ GIT_PLATFORM_META,
55
+ CI_PLATFORM_FILES,
56
+ PM_TOOL_LABELS
57
+ };