token-goat 2.9.26 → 2.9.29

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 (78) hide show
  1. package/README.md +30 -88
  2. package/SECURITY.md +14 -0
  3. package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-2AWQ2R5X.mjs} +2 -2
  4. package/dist/{token-goat-chunk-BH4ZVRB2.mjs → token-goat-chunk-2NNUA2LR.mjs} +4 -4
  5. package/dist/token-goat-chunk-2WOUYWLM.mjs +955 -0
  6. package/dist/{token-goat-chunk-IKZLSRII.mjs → token-goat-chunk-435UQTKD.mjs} +5 -3
  7. package/dist/{token-goat-chunk-62IHOU6L.mjs → token-goat-chunk-44BM7DDQ.mjs} +5 -3
  8. package/dist/token-goat-chunk-52NSDWYY.mjs +96 -0
  9. package/dist/{token-goat-chunk-CXBOFPF4.mjs → token-goat-chunk-67BNIKKO.mjs} +32 -18
  10. package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-6AK46ZT7.mjs} +2 -3
  11. package/dist/{token-goat-chunk-7SXPJOSZ.mjs → token-goat-chunk-7CPMDFGB.mjs} +166 -40
  12. package/dist/token-goat-chunk-ASLWOQ3I.mjs +14 -0
  13. package/dist/{token-goat-chunk-MWID3YOY.mjs → token-goat-chunk-BGYOZ6DO.mjs} +6 -4
  14. package/dist/{token-goat-chunk-PAV6NNY7.mjs → token-goat-chunk-C5YPNZKQ.mjs} +22 -8
  15. package/dist/{token-goat-chunk-D2X7XN5M.mjs → token-goat-chunk-CIQ2FTY3.mjs} +23 -242
  16. package/dist/token-goat-chunk-D4ETHJD6.mjs +246 -0
  17. package/dist/{token-goat-chunk-7Y6GWTII.mjs → token-goat-chunk-DNRPXHYH.mjs} +25 -17
  18. package/dist/{token-goat-chunk-L43RKNHA.mjs → token-goat-chunk-DNSPXQXQ.mjs} +2 -2
  19. package/dist/token-goat-chunk-DPNLUJWB.mjs +220 -0
  20. package/dist/token-goat-chunk-E4ZOJIZK.mjs +1382 -0
  21. package/dist/token-goat-chunk-E5TK5DNO.mjs +718 -0
  22. package/dist/{token-goat-chunk-VVROQBQJ.mjs → token-goat-chunk-EUSDXRXU.mjs} +62 -12
  23. package/dist/{token-goat-chunk-POOI26O6.mjs → token-goat-chunk-FTP4U4QA.mjs} +12 -8
  24. package/dist/token-goat-chunk-G23DWHV4.mjs +142 -0
  25. package/dist/{token-goat-chunk-MDV5VWF4.mjs → token-goat-chunk-G7IWXCFF.mjs} +223 -15
  26. package/dist/{token-goat-chunk-C2PG4K5D.mjs → token-goat-chunk-GLXRTTLE.mjs} +7 -5
  27. package/dist/{token-goat-chunk-M6CVNHTW.mjs → token-goat-chunk-H5J3C56Q.mjs} +95 -573
  28. package/dist/{token-goat-chunk-BAWKGODL.mjs → token-goat-chunk-HNFZZHFW.mjs} +2 -2
  29. package/dist/{token-goat-chunk-TG5ZPD6B.mjs → token-goat-chunk-HUYUHODZ.mjs} +1036 -759
  30. package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
  31. package/dist/{token-goat-chunk-ZZT6PVB3.mjs → token-goat-chunk-IVWI2OCK.mjs} +72 -45
  32. package/dist/{token-goat-chunk-GMOUBOX4.mjs → token-goat-chunk-JTKCQMQA.mjs} +37 -5
  33. package/dist/{token-goat-chunk-H2CPLEMP.mjs → token-goat-chunk-KOPIR3KZ.mjs} +46 -23
  34. package/dist/token-goat-chunk-L7H3U27L.mjs +35 -0
  35. package/dist/{token-goat-chunk-FLEYOCAS.mjs → token-goat-chunk-LZNBQTDK.mjs} +6 -4
  36. package/dist/token-goat-chunk-MELOKFDJ.mjs +199 -0
  37. package/dist/{token-goat-chunk-RH27ZSPF.mjs → token-goat-chunk-NMBWLRHW.mjs} +164 -50
  38. package/dist/{token-goat-chunk-43JFN26X.mjs → token-goat-chunk-O6I2XU4P.mjs} +27 -967
  39. package/dist/{token-goat-chunk-G6EYO5CD.mjs → token-goat-chunk-ONXH6NZ5.mjs} +2 -87
  40. package/dist/token-goat-chunk-ORNFMIER.mjs +295 -0
  41. package/dist/{token-goat-chunk-LHUP4DXZ.mjs → token-goat-chunk-PGTH2U4C.mjs} +1 -1
  42. package/dist/{token-goat-chunk-5BQ7W7D7.mjs → token-goat-chunk-PKRWMHVP.mjs} +76 -59
  43. package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-PQ53BSCF.mjs} +1 -1
  44. package/dist/{token-goat-chunk-STYRLQIW.mjs → token-goat-chunk-PYSUADX4.mjs} +2 -2
  45. package/dist/{token-goat-chunk-JALB3KWJ.mjs → token-goat-chunk-QO3LXVVR.mjs} +4247 -5005
  46. package/dist/{token-goat-chunk-L45IWWMC.mjs → token-goat-chunk-RLP6J7WR.mjs} +6 -6
  47. package/dist/token-goat-chunk-RQGGMPCR.mjs +205 -0
  48. package/dist/{token-goat-chunk-MBDJR6HU.mjs → token-goat-chunk-RTMVLHWX.mjs} +3708 -4003
  49. package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-S4VSXURL.mjs} +8 -6
  50. package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-SE6E4BKJ.mjs} +1 -1
  51. package/dist/token-goat-chunk-TCQANXYC.mjs +351 -0
  52. package/dist/token-goat-chunk-TDUT2CL6.mjs +564 -0
  53. package/dist/{token-goat-chunk-LRIZ7K3F.mjs → token-goat-chunk-TGOXNAHW.mjs} +54 -111
  54. package/dist/{token-goat-chunk-WNBSCSAI.mjs → token-goat-chunk-UA5BKWWQ.mjs} +1 -1
  55. package/dist/{token-goat-chunk-RIB6XY2V.mjs → token-goat-chunk-UXSXQQIY.mjs} +1 -1
  56. package/dist/{token-goat-chunk-7EPYB34H.mjs → token-goat-chunk-VMFWNHGR.mjs} +84 -73
  57. package/dist/token-goat-chunk-VQ6F6T7X.mjs +36 -0
  58. package/dist/{token-goat-chunk-5M3NRJD2.mjs → token-goat-chunk-VZQEWRVH.mjs} +6 -4
  59. package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
  60. package/dist/{token-goat-chunk-6E2IDLHF.mjs → token-goat-chunk-XYWPOSCN.mjs} +57 -615
  61. package/dist/{token-goat-chunk-CQHY4SL7.mjs → token-goat-chunk-YAGLESS3.mjs} +8 -5
  62. package/dist/token-goat-chunk-YKSRAWUU.mjs +33 -0
  63. package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-YOOVFPTP.mjs} +2 -2
  64. package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
  65. package/dist/token-goat-chunk-Z6KBMOBI.mjs +53 -0
  66. package/dist/{token-goat-chunk-4GEDH2WU.mjs → token-goat-chunk-ZER6EAXZ.mjs} +81 -70
  67. package/dist/token-goat-hook-client.cjs +475 -0
  68. package/dist/token-goat-hook-client.mjs +26 -0
  69. package/dist/token-goat-hook.mjs +31 -21
  70. package/dist/token-goat.core.mjs +9 -39
  71. package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
  72. package/docs/cli.md +35 -23
  73. package/docs/install.md +18 -14
  74. package/package.json +1 -1
  75. package/dist/token-goat-chunk-ADMR3QVF.mjs +0 -41
  76. package/dist/token-goat-chunk-E6B2UFDF.mjs +0 -30
  77. package/dist/token-goat-chunk-GKZ2US5B.mjs +0 -187
  78. package/dist/token-goat-chunk-MZTO4FXH.mjs +0 -26
@@ -2,10 +2,10 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  estimateTokensFromLength
5
- } from "./token-goat-chunk-G6EYO5CD.mjs";
5
+ } from "./token-goat-chunk-52NSDWYY.mjs";
6
6
  import {
7
7
  loadConfig
8
- } from "./token-goat-chunk-LRIZ7K3F.mjs";
8
+ } from "./token-goat-chunk-TGOXNAHW.mjs";
9
9
  import {
10
10
  atomicWriteText,
11
11
  backupFile,
@@ -21,7 +21,7 @@ import {
21
21
  upsertDelimitedBlock,
22
22
  withInstallScope,
23
23
  writeIfDifferent
24
- } from "./token-goat-chunk-6E2IDLHF.mjs";
24
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
25
25
  import {
26
26
  init_define_import_meta_env
27
27
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -51,6 +51,7 @@ function buildGuidanceBody(fallbackToolClause, opts = {}) {
51
51
  '- not knowing which command answers a question you can already state in words \u2192 `answer "<question>"`, which resolves the subject in the index, runs the right command, prints `via: <command>`, and refuses rather than guess',
52
52
  '- a shell text search with context flags to find a function body \u2192 `read "file::symbol"`',
53
53
  '- paging one function with view/view_range \u2192 `read "file::symbol"`',
54
+ "- a read refused by a `[tg]` deny, retried with a shifted range or a different read tool \u2192 the command the deny names",
54
55
  '- reading a symbol plus chasing its callers and containing doc section as separate reads \u2192 `brief "file::symbol"`',
55
56
  '- reading one heading of a large doc \u2192 `section "file::Heading"`',
56
57
  "- searching for a symbol's callers \u2192 `refs file::symbol --callers`",
@@ -369,6 +370,30 @@ function foldToolName(name) {
369
370
  return typeof name === "string" ? name.toLowerCase().replace(/[_-]/g, "") : "";
370
371
  }
371
372
 
373
+ // src/bridges/shim_try_server.ts
374
+ init_define_import_meta_env();
375
+ var SHIM_TRY_SERVER = `// Attempts the resident hook server (src/hook_server.ts): the sibling hook client sends this
376
+ // call to an already-running token-goat process, so neither Node's module loading nor the hook
377
+ // graph is paid for again. The CommonJS client comes first: this shim is CommonJS, and loading
378
+ // the ES module one starts Node's ESM loader, about 5ms of a call the server answers. The ES
379
+ // module one is for an install built before the CommonJS file existed. It returns undefined
380
+ // whenever nothing was dispatched -- no server yet (it starts one in the background), all busy,
381
+ // replaced by a newer build, turned off, or an install predating the client -- and the caller
382
+ // then runs the call itself.
383
+ async function tryServer(entryPath, eventName, input, harnessWaitMs) {
384
+ if (!entryPath) return undefined
385
+ try {
386
+ const fs = require('node:fs')
387
+ const cjsPath = path.join(path.dirname(entryPath), 'token-goat-hook-client.cjs')
388
+ const mjsPath = path.join(path.dirname(entryPath), 'token-goat-hook-client.mjs')
389
+ const client = fs.existsSync(cjsPath) ? require(cjsPath) : fs.existsSync(mjsPath) ? await import(pathToFileURL(mjsPath).href) : undefined
390
+ if (client === undefined) return undefined
391
+ return await client.relayViaServer(eventName, input, harnessWaitMs)
392
+ } catch {
393
+ return undefined
394
+ }
395
+ }`;
396
+
372
397
  // src/bridges/shrink_block.ts
373
398
  init_define_import_meta_env();
374
399
  var MATERIALIZE_SHRUNK_IMAGE_JS = `// Best-effort sweep of previously materialized shrunk copies in the OS temp dir. The temp file only needs to outlive the single tool call whose path argument was rewritten to it, so anything older than an hour is finished with; the "token-goat-shrink-" prefix check confines the sweep to this mechanism's own files (same defense-in-depth rule as pruneShrinkCache in src/image_shrink.ts). Throttled per process; runs only when a shrink payload actually arrives, so the common no-image path never pays for it.
@@ -665,7 +690,9 @@ function remapToolInput(copilotToolName, input) {
665
690
  return out
666
691
  }
667
692
 
668
- // Attempts the in-process hook call: import()s dist/token-goat-hook.mjs (a sibling of
693
+ ${SHIM_TRY_SERVER}
694
+
695
+ // Attempts the resident server (tryServer above), then the in-process hook call: import()s dist/token-goat-hook.mjs (a sibling of
669
696
  // the baked token-goat entry path, built with zero load-time side effects -- unlike
670
697
  // the CLI entry, which runs the full argv-parsing CLI as a side effect of being
671
698
  // loaded) and calls its exported relayInProcess() directly, avoiding a second node
@@ -675,14 +702,17 @@ function remapToolInput(copilotToolName, input) {
675
702
  async function tryInProcess(entryPath, tgEvent, canonical, harness) {
676
703
  if (!entryPath) return undefined
677
704
  try {
678
- const hookLibPath = path.join(path.dirname(entryPath), 'token-goat-hook.mjs')
679
- if (!require('node:fs').existsSync(hookLibPath)) return undefined
680
- const mod = await import(pathToFileURL(hookLibPath).href)
705
+ // Set before either path: the resident server runs the call under this process's environment.
681
706
  process.env.TOKEN_GOAT_HARNESS_OVERRIDE = harness
682
707
  // Which hooks directory VS Code loaded this shim from is the only thing separating a
683
708
  // user-scope copy from a project-scope one -- the two files are byte-identical and so are
684
709
  // their payloads. vscode_duplicate.ts needs it to stand the redundant copy down.
685
710
  if (harness === 'vscode') process.env.TOKEN_GOAT_VSCODE_HOOKS_DIR = __dirname
711
+ const served = await tryServer(entryPath, tgEvent, canonical)
712
+ if (served !== undefined) return served
713
+ const hookLibPath = path.join(path.dirname(entryPath), 'token-goat-hook.mjs')
714
+ if (!require('node:fs').existsSync(hookLibPath)) return undefined
715
+ const mod = await import(pathToFileURL(hookLibPath).href)
686
716
  return await mod.relayInProcess(tgEvent, canonical)
687
717
  } catch {
688
718
  return undefined
@@ -1173,13 +1203,26 @@ function buildConfig(scriptPath) {
1173
1203
  return { version: 1, hooks };
1174
1204
  }
1175
1205
  var HOOKS_CONFIG_FILE = "token-goat.json";
1176
- var HOOKS_SCRIPT_FILE = "token-goat-shim.js";
1206
+ var HOOKS_SCRIPT_FILE = "token-goat-shim.cjs";
1207
+ var LEGACY_HOOKS_SCRIPT_FILE = "token-goat-shim.js";
1177
1208
  var HOOKS_OWNERS_FILE = "token-goat.owners";
1209
+ var HOOKS_SCRIPT_FORWARDER = `#!/usr/bin/env node
1210
+ // Forwarder for compatibility with cached hook definitions in running Copilot CLI sessions.
1211
+ import('./token-goat-shim.cjs').catch(() => {
1212
+ try { process.stdout.write('{}') } catch {}
1213
+ process.exitCode = 0
1214
+ });
1215
+ `;
1178
1216
  function copilotHooksOwnersPath(hooksDir) {
1179
1217
  return path3.join(hooksDir, HOOKS_OWNERS_FILE);
1180
1218
  }
1181
1219
  function copilotHooksFilePaths(hooksDir) {
1182
- return [path3.join(hooksDir, HOOKS_CONFIG_FILE), path3.join(hooksDir, HOOKS_SCRIPT_FILE), copilotHooksOwnersPath(hooksDir)];
1220
+ return [
1221
+ path3.join(hooksDir, HOOKS_CONFIG_FILE),
1222
+ path3.join(hooksDir, HOOKS_SCRIPT_FILE),
1223
+ path3.join(hooksDir, LEGACY_HOOKS_SCRIPT_FILE),
1224
+ copilotHooksOwnersPath(hooksDir)
1225
+ ];
1183
1226
  }
1184
1227
  function readCopilotHooksOwners(hooksDir) {
1185
1228
  const owners = /* @__PURE__ */ new Set();
@@ -1199,14 +1242,16 @@ function readCopilotHooksOwners(hooksDir) {
1199
1242
  function installCopilotHooksFile(hooksDir, owner) {
1200
1243
  const configPath = path3.join(hooksDir, HOOKS_CONFIG_FILE);
1201
1244
  const scriptPath = path3.join(hooksDir, HOOKS_SCRIPT_FILE);
1245
+ const legacyScriptPath = path3.join(hooksDir, LEGACY_HOOKS_SCRIPT_FILE);
1202
1246
  const owners = readCopilotHooksOwners(hooksDir);
1203
1247
  const scriptChanged = writeIfDifferent(scriptPath, COPILOT_CLI_HOOK_SCRIPT);
1248
+ const legacyScriptChanged = writeIfDifferent(legacyScriptPath, HOOKS_SCRIPT_FORWARDER);
1204
1249
  const desiredText = JSON.stringify(buildConfig(scriptPath), null, 2) + "\n";
1205
1250
  const configChanged = writeIfDifferent(configPath, desiredText, true);
1206
1251
  recordCreatedConfig(configPath);
1207
1252
  owners.add(owner);
1208
1253
  const ownersChanged = writeIfDifferent(copilotHooksOwnersPath(hooksDir), [...owners].sort().join("\n") + "\n");
1209
- return { configPath, scriptPath, changed: scriptChanged || configChanged || ownersChanged };
1254
+ return { configPath, scriptPath, changed: scriptChanged || legacyScriptChanged || configChanged || ownersChanged };
1210
1255
  }
1211
1256
  function releaseCopilotHooksFile(hooksDir, owner, keepBackups = false) {
1212
1257
  const ownersPath = copilotHooksOwnersPath(hooksDir);
@@ -1222,8 +1267,9 @@ function releaseCopilotHooksFile(hooksDir, owner, keepBackups = false) {
1222
1267
  if (!keepBackups) removeCreatedBackups(path3.join(hooksDir, HOOKS_CONFIG_FILE));
1223
1268
  takeCreatedConfig(path3.join(hooksDir, HOOKS_CONFIG_FILE));
1224
1269
  const scriptRemoved = removeFileInScope(path3.join(hooksDir, HOOKS_SCRIPT_FILE));
1270
+ const legacyScriptRemoved = removeFileInScope(path3.join(hooksDir, LEGACY_HOOKS_SCRIPT_FILE));
1225
1271
  const ownersRemoved = removeFileInScope(ownersPath);
1226
- return configRemoved || scriptRemoved || ownersRemoved;
1272
+ return configRemoved || scriptRemoved || legacyScriptRemoved || ownersRemoved;
1227
1273
  }
1228
1274
  function installCopilotCli(opts = {}) {
1229
1275
  return withInstallScope(projectScopeRoot(opts), () => installCopilotCliScoped(opts));
@@ -1258,7 +1304,8 @@ function uninstallCopilotCli(opts = {}) {
1258
1304
  return userRemoved || localRemoved;
1259
1305
  }
1260
1306
  function isCopilotCliInstalled(opts = {}) {
1261
- if (!fs3.existsSync(copilotCliConfigPath(opts)) || !fs3.existsSync(copilotCliScriptPath(opts))) {
1307
+ const scriptPresent = fs3.existsSync(copilotCliScriptPath(opts)) || fs3.existsSync(path3.join(copilotCliHooksDir(opts), LEGACY_HOOKS_SCRIPT_FILE));
1308
+ if (!fs3.existsSync(copilotCliConfigPath(opts)) || !scriptPresent) {
1262
1309
  return false;
1263
1310
  }
1264
1311
  if (!readCopilotHooksOwners(copilotCliHooksDir(opts)).has("copilot")) return false;
@@ -1338,7 +1385,9 @@ function readCopilotMcpTools(dir = copilotCliMcpToolsDir()) {
1338
1385
  export {
1339
1386
  foldToolName,
1340
1387
  COPILOT_CLI_TOOL_NAME_MAP,
1388
+ SHIM_TRY_SERVER,
1341
1389
  MATERIALIZE_SHRUNK_IMAGE_JS,
1390
+ COPILOT_CLI_HOOK_SCRIPT,
1342
1391
  buildGuidanceBody,
1343
1392
  skillDescriptionLine,
1344
1393
  buildGuidanceBlock,
@@ -1368,6 +1417,7 @@ export {
1368
1417
  copilotCliConfigPath,
1369
1418
  copilotCliScriptPath,
1370
1419
  HOOKS_SCRIPT_FILE,
1420
+ LEGACY_HOOKS_SCRIPT_FILE,
1371
1421
  copilotHooksFilePaths,
1372
1422
  readCopilotHooksOwners,
1373
1423
  installCopilotHooksFile,
@@ -20,19 +20,23 @@ import {
20
20
  setOcrTimeoutForTesting,
21
21
  setTesseractEntryForTesting,
22
22
  verifyOcrLangCache
23
- } from "./token-goat-chunk-5M3NRJD2.mjs";
24
- import "./token-goat-chunk-D2X7XN5M.mjs";
25
- import "./token-goat-chunk-7SXPJOSZ.mjs";
23
+ } from "./token-goat-chunk-VZQEWRVH.mjs";
24
+ import "./token-goat-chunk-D4ETHJD6.mjs";
25
+ import "./token-goat-chunk-CIQ2FTY3.mjs";
26
+ import "./token-goat-chunk-7CPMDFGB.mjs";
26
27
  import {
27
28
  DEFAULT_OCR_LANG,
28
29
  isSupportedOcrLang,
29
30
  resolveOcrLangs
30
- } from "./token-goat-chunk-LRIZ7K3F.mjs";
31
- import "./token-goat-chunk-EEIDFMEM.mjs";
32
- import "./token-goat-chunk-OSUFN2FV.mjs";
33
- import "./token-goat-chunk-6E2IDLHF.mjs";
31
+ } from "./token-goat-chunk-TGOXNAHW.mjs";
32
+ import "./token-goat-chunk-XB5KKOCG.mjs";
33
+ import "./token-goat-chunk-YZAAZU2S.mjs";
34
+ import "./token-goat-chunk-IVE6U7KV.mjs";
35
+ import "./token-goat-chunk-XYWPOSCN.mjs";
36
+ import "./token-goat-chunk-TCQANXYC.mjs";
34
37
  import "./token-goat-chunk-NMTKNYGF.mjs";
35
- import "./token-goat-chunk-GMOUBOX4.mjs";
38
+ import "./token-goat-chunk-MELOKFDJ.mjs";
39
+ import "./token-goat-chunk-JTKCQMQA.mjs";
36
40
  import "./token-goat-chunk-A37V4PBF.mjs";
37
41
  export {
38
42
  DEFAULT_OCR_LANG,
@@ -0,0 +1,142 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ CONTENT_DELIVERED_REASON,
5
+ classifyToolError,
6
+ errorPrefix
7
+ } from "./token-goat-chunk-E4ZOJIZK.mjs";
8
+ import "./token-goat-chunk-E5TK5DNO.mjs";
9
+ import "./token-goat-chunk-ZER6EAXZ.mjs";
10
+ import "./token-goat-chunk-EUSDXRXU.mjs";
11
+ import "./token-goat-chunk-TDUT2CL6.mjs";
12
+ import "./token-goat-chunk-52NSDWYY.mjs";
13
+ import "./token-goat-chunk-2WOUYWLM.mjs";
14
+ import "./token-goat-chunk-CIQ2FTY3.mjs";
15
+ import "./token-goat-chunk-7CPMDFGB.mjs";
16
+ import "./token-goat-chunk-TGOXNAHW.mjs";
17
+ import "./token-goat-chunk-XB5KKOCG.mjs";
18
+ import "./token-goat-chunk-YZAAZU2S.mjs";
19
+ import "./token-goat-chunk-IVE6U7KV.mjs";
20
+ import "./token-goat-chunk-XYWPOSCN.mjs";
21
+ import "./token-goat-chunk-TCQANXYC.mjs";
22
+ import {
23
+ displaySafeText
24
+ } from "./token-goat-chunk-NMTKNYGF.mjs";
25
+ import "./token-goat-chunk-MELOKFDJ.mjs";
26
+ import "./token-goat-chunk-JTKCQMQA.mjs";
27
+ import {
28
+ init_define_import_meta_env
29
+ } from "./token-goat-chunk-A37V4PBF.mjs";
30
+
31
+ // src/tool_error_census.ts
32
+ init_define_import_meta_env();
33
+ var UNKNOWN_PREFIX_LIMIT = 20;
34
+ var REASONS_PER_ROW = 4;
35
+ var UNKNOWN_MODEL = "(unknown)";
36
+ function tally(map, name) {
37
+ let row = map.get(name);
38
+ if (row === void 0) {
39
+ row = { name, calls: 0, errors: 0, unknown: 0, delivered: 0, expected: {} };
40
+ map.set(name, row);
41
+ }
42
+ return row;
43
+ }
44
+ function byCodeUnit(a, b) {
45
+ return a < b ? -1 : a > b ? 1 : 0;
46
+ }
47
+ function sortTallies(map) {
48
+ return [...map.values()].sort((a, b) => b.errors - a.errors || b.calls - a.calls || byCodeUnit(a.name, b.name));
49
+ }
50
+ function newToolErrorAccumulator() {
51
+ const tools = /* @__PURE__ */ new Map();
52
+ const models = /* @__PURE__ */ new Map();
53
+ const unknownPrefixes = /* @__PURE__ */ new Map();
54
+ return {
55
+ countCall(tool, model) {
56
+ tally(tools, tool).calls += 1;
57
+ tally(models, model ?? UNKNOWN_MODEL).calls += 1;
58
+ },
59
+ countError(tool, model, errorText, flags) {
60
+ const verdict = classifyToolError(tool, errorText, flags);
61
+ const rows = [tally(tools, tool), tally(models, model ?? UNKNOWN_MODEL)];
62
+ if (verdict.reason === CONTENT_DELIVERED_REASON) {
63
+ for (const row of rows) row.delivered += 1;
64
+ return;
65
+ }
66
+ for (const row of rows) {
67
+ row.errors += 1;
68
+ if (verdict.kind === "unknown") row.unknown += 1;
69
+ else row.expected[verdict.reason] = (row.expected[verdict.reason] ?? 0) + 1;
70
+ }
71
+ if (verdict.kind !== "unknown") return;
72
+ const prefix = errorPrefix(errorText);
73
+ const key = `${tool}\0${prefix}`;
74
+ const hit = unknownPrefixes.get(key);
75
+ if (hit === void 0) unknownPrefixes.set(key, { tool, prefix, count: 1 });
76
+ else hit.count += 1;
77
+ },
78
+ finish() {
79
+ const topUnknown = [...unknownPrefixes.values()].sort((a, b) => b.count - a.count || byCodeUnit(a.tool, b.tool) || byCodeUnit(a.prefix, b.prefix)).slice(0, UNKNOWN_PREFIX_LIMIT);
80
+ return { byTool: sortTallies(tools), byModel: sortTallies(models), unknownPrefixes: topUnknown };
81
+ }
82
+ };
83
+ }
84
+ function fmt(n) {
85
+ return n.toLocaleString("en-US");
86
+ }
87
+ function rate(errors, calls) {
88
+ return calls === 0 ? "-" : `${(errors / calls * 100).toFixed(1)}%`;
89
+ }
90
+ function reasonsCell(expected) {
91
+ const ranked = Object.entries(expected).sort((a, b) => b[1] - a[1] || byCodeUnit(a[0], b[0]));
92
+ const shown = ranked.slice(0, REASONS_PER_ROW).map(([reason, n]) => `${reason} ${fmt(n)}`);
93
+ const rest = ranked.slice(REASONS_PER_ROW).reduce((sum, [, n]) => sum + n, 0);
94
+ if (rest > 0) shown.push(`+${fmt(rest)} more`);
95
+ return shown.join(", ");
96
+ }
97
+ function columnWidth(names, header) {
98
+ return names.reduce((w, n) => Math.max(w, n.length), header.length);
99
+ }
100
+ function tableLines(rows) {
101
+ const failing = rows.filter((r) => r.errors > 0);
102
+ const names = failing.map((r) => displaySafeText(r.name));
103
+ const width = columnWidth(names, "name");
104
+ const out = [`${"name".padEnd(width)} ${"calls".padStart(9)} ${"errors".padStart(7)} ${"rate".padStart(6)} ${"unknown".padStart(7)} expected, by reason`];
105
+ failing.forEach((r, i) => out.push(`${names[i].padEnd(width)} ${fmt(r.calls).padStart(9)} ${fmt(r.errors).padStart(7)} ${rate(r.errors, r.calls).padStart(6)} ${fmt(r.unknown).padStart(7)} ${reasonsCell(r.expected)}`.trimEnd()));
106
+ if (failing.length < rows.length) out.push(`(${fmt(rows.length - failing.length)} more ran without an error)`);
107
+ return out;
108
+ }
109
+ function deliveredLines(rows) {
110
+ const delivering = rows.filter((r) => r.delivered > 0).sort((a, b) => b.delivered - a.delivered || byCodeUnit(a.name, b.name));
111
+ if (delivering.length === 0) return [];
112
+ const total = delivering.reduce((sum, r) => sum + r.delivered, 0);
113
+ return [`Content delivered by a token-goat deny, not counted as errors: ${fmt(total)} (${delivering.map((r) => `${displaySafeText(r.name)} ${fmt(r.delivered)}`).join(", ")}).`];
114
+ }
115
+ function formatToolErrorCensus(census, scope) {
116
+ const calls = census.byTool.reduce((sum, r) => sum + r.calls, 0);
117
+ const errors = census.byTool.reduce((sum, r) => sum + r.errors, 0);
118
+ const unknown = census.byTool.reduce((sum, r) => sum + r.unknown, 0);
119
+ const toolWidth = columnWidth(census.unknownPrefixes.map((p) => displaySafeText(p.tool)), "");
120
+ const window = scope.windowDays === 0 ? "all time" : `transcripts modified in the last ${fmt(scope.windowDays)} days`;
121
+ const lines = [
122
+ `# Tool errors (${fmt(scope.filesScanned)} transcripts, ${window})`,
123
+ `Calls ${fmt(calls)}, errors ${fmt(errors)} (${rate(errors, calls)}), unknown ${fmt(unknown)}. Expected means a named failure shape in tool_error_class.ts; unknown is everything else.`,
124
+ ...deliveredLines(census.byTool),
125
+ "",
126
+ "## By tool",
127
+ ...tableLines(census.byTool),
128
+ "",
129
+ "## By model",
130
+ ...tableLines(census.byModel),
131
+ "",
132
+ "## Top unknown error prefixes (paths, quoted text and digits masked)",
133
+ ...census.unknownPrefixes.map((p) => `${fmt(p.count).padStart(7)} ${displaySafeText(p.tool).padEnd(toolWidth)} ${displaySafeText(p.prefix)}`)
134
+ ];
135
+ if (census.unknownPrefixes.length === 0) lines.push("(none)");
136
+ return lines.join("\n");
137
+ }
138
+ export {
139
+ UNKNOWN_PREFIX_LIMIT,
140
+ formatToolErrorCensus,
141
+ newToolErrorAccumulator
142
+ };
@@ -1,33 +1,47 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
- WEB_FETCH_KEY_SEP,
5
4
  computeAdaptiveBudget,
6
5
  getContextPressure,
7
- getSessionBashOutputs,
8
- getSessionBashReruns,
9
- getSessionFiles,
10
- getSessionWebFetches,
11
6
  isNoisePath,
12
7
  listSiblingSessionStates,
13
8
  loadSessionCache
14
- } from "./token-goat-chunk-M6CVNHTW.mjs";
9
+ } from "./token-goat-chunk-H5J3C56Q.mjs";
10
+ import {
11
+ WEB_FETCH_KEY_SEP,
12
+ getSessionBashOutputs,
13
+ getSessionBashReruns,
14
+ getSessionFiles,
15
+ getSessionWebFetches
16
+ } from "./token-goat-chunk-TDUT2CL6.mjs";
15
17
  import {
16
18
  getBashOutput
17
- } from "./token-goat-chunk-43JFN26X.mjs";
19
+ } from "./token-goat-chunk-O6I2XU4P.mjs";
18
20
  import {
21
+ findProject,
19
22
  loadConfig
20
- } from "./token-goat-chunk-LRIZ7K3F.mjs";
23
+ } from "./token-goat-chunk-TGOXNAHW.mjs";
21
24
  import {
22
- foldPath,
25
+ LOCK_WAIT_MS_HARDENED,
26
+ atomicWriteText,
27
+ ensureDirSync,
23
28
  runGit,
24
- toKB
25
- } from "./token-goat-chunk-6E2IDLHF.mjs";
29
+ toKB,
30
+ withFileLock,
31
+ withRetryOnLock
32
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
33
+ import {
34
+ foldPath,
35
+ sleepSync
36
+ } from "./token-goat-chunk-TCQANXYC.mjs";
26
37
  import {
27
38
  displaySafePath,
28
39
  displaySafeText,
29
40
  neutralizeSpokenMarkers
30
41
  } from "./token-goat-chunk-NMTKNYGF.mjs";
42
+ import {
43
+ dataDir
44
+ } from "./token-goat-chunk-MELOKFDJ.mjs";
31
45
  import {
32
46
  init_define_import_meta_env
33
47
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -35,6 +49,193 @@ import {
35
49
  // src/manifest.ts
36
50
  init_define_import_meta_env();
37
51
  import { spawnSync } from "node:child_process";
52
+
53
+ // src/project_memory.ts
54
+ init_define_import_meta_env();
55
+ import * as fs from "node:fs";
56
+ import * as path from "node:path";
57
+ var MAX_ENTRIES = 30;
58
+ var MAX_VALUE_LEN = 300;
59
+ var MAX_TOTAL_CHARS = 4e3;
60
+ var KEY_RE = /^[A-Za-z0-9_-]{1,80}$/;
61
+ function ordinal(a, b) {
62
+ return a < b ? -1 : a > b ? 1 : 0;
63
+ }
64
+ function memoryPath(projectHash) {
65
+ return path.join(dataDir(), "projects", `${projectHash}_memory.toml`);
66
+ }
67
+ function validateKey(key) {
68
+ if (!KEY_RE.test(key)) {
69
+ throw new Error(
70
+ `Invalid memory key ${JSON.stringify(key)}: use only letters, digits, hyphens, underscores (max 80 chars)`
71
+ );
72
+ }
73
+ }
74
+ function parseTOML(content, unparsed = []) {
75
+ const result = {};
76
+ for (const [i, line] of content.split("\n").entries()) {
77
+ const trimmed = line.trim();
78
+ if (!trimmed || trimmed.startsWith("#")) {
79
+ continue;
80
+ }
81
+ const match = trimmed.match(/^([A-Za-z0-9_-]+)\s*=\s*"(.*)"\s*$/);
82
+ if (match) {
83
+ const [, key, value] = match;
84
+ if (key && value !== void 0) {
85
+ const unescaped = value.replace(/\\([\\nrt"])/g, (_, c) => {
86
+ switch (c) {
87
+ case "\\":
88
+ return "\\";
89
+ case "n":
90
+ return "\n";
91
+ case "r":
92
+ return "\r";
93
+ case '"':
94
+ return '"';
95
+ default:
96
+ return _;
97
+ }
98
+ });
99
+ result[key] = unescaped;
100
+ }
101
+ } else {
102
+ unparsed.push(i + 1);
103
+ }
104
+ }
105
+ return result;
106
+ }
107
+ function loadRaw(filePath, forUpdate = false) {
108
+ let content = "";
109
+ try {
110
+ withRetryOnLock(() => {
111
+ content = fs.readFileSync(filePath, "utf-8");
112
+ });
113
+ } catch (err) {
114
+ if (err.code === "ENOENT") return {};
115
+ throw err;
116
+ }
117
+ const unparsed = [];
118
+ const entries = parseTOML(content, unparsed);
119
+ if (forUpdate && unparsed.length > 0) {
120
+ const one = unparsed.length === 1;
121
+ throw new Error(`Not updating ${filePath}: ${one ? "line" : "lines"} ${unparsed.join(", ")} ${one ? "is" : "are"} not in the key = "value" form, and saving would drop ${one ? "it" : "them"}. Fix or remove ${one ? "it" : "them"}, then try again.`);
122
+ }
123
+ return entries;
124
+ }
125
+ function save(filePath, entries) {
126
+ const lines = [];
127
+ const sorted = Object.entries(entries).sort(([a], [b]) => ordinal(a, b));
128
+ for (const [k, v] of sorted) {
129
+ const escaped = v.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\r/g, "\\r").replace(/\n/g, "\\n");
130
+ lines.push(`${k} = "${escaped}"`);
131
+ }
132
+ const content = lines.length > 0 ? lines.join("\n") + "\n" : "";
133
+ const dir = path.dirname(filePath);
134
+ ensureDirSync(dir);
135
+ atomicWriteText(filePath, content);
136
+ }
137
+ function loadEntries(projectHash) {
138
+ return loadRaw(memoryPath(projectHash));
139
+ }
140
+ function setEntry(projectHash, key, value) {
141
+ validateKey(key);
142
+ const p = memoryPath(projectHash);
143
+ const dir = path.dirname(p);
144
+ ensureDirSync(dir);
145
+ const doSet = () => {
146
+ const entries = loadRaw(p, true);
147
+ const isNewKey = !(key in entries);
148
+ if (isNewKey && Object.keys(entries).length >= MAX_ENTRIES) {
149
+ const keysToKeep = MAX_ENTRIES - 1;
150
+ const allKeys = Object.keys(entries).sort((a, b) => ordinal(a, b));
151
+ for (const k of allKeys.slice(keysToKeep)) {
152
+ delete entries[k];
153
+ }
154
+ }
155
+ entries[key] = value;
156
+ save(p, entries);
157
+ return true;
158
+ };
159
+ underNotesLock(p, doSet);
160
+ }
161
+ function underNotesLock(p, update) {
162
+ const lockPath = `${p}.lock`;
163
+ ensureDirSync(path.dirname(p));
164
+ for (let attempt = 1; attempt <= 3; attempt++) {
165
+ if (withFileLock(lockPath, update, { waitMs: LOCK_WAIT_MS_HARDENED }) !== void 0) return;
166
+ if (fs.existsSync(lockPath)) break;
167
+ if (attempt < 3) sleepSync(50 * attempt);
168
+ }
169
+ throw new Error(`Could not lock ${p} for writing; no note was changed. Another token-goat process may be writing notes: try again.`);
170
+ }
171
+ function unsetEntry(projectHash, key) {
172
+ validateKey(key);
173
+ const p = memoryPath(projectHash);
174
+ const doUnset = () => {
175
+ const entries = loadRaw(p, true);
176
+ if (key in entries) {
177
+ delete entries[key];
178
+ save(p, entries);
179
+ }
180
+ return true;
181
+ };
182
+ underNotesLock(p, doUnset);
183
+ }
184
+ function clearAll(projectHash) {
185
+ const p = memoryPath(projectHash);
186
+ const doClear = () => {
187
+ if (fs.existsSync(p)) {
188
+ save(p, {});
189
+ }
190
+ return true;
191
+ };
192
+ underNotesLock(p, doClear);
193
+ }
194
+ function buildInjection(projectHash) {
195
+ try {
196
+ const entries = loadEntries(projectHash);
197
+ if (Object.keys(entries).length === 0) {
198
+ return null;
199
+ }
200
+ const header = '### Project notes (`token-goat note set <key> "<finding>"`)';
201
+ const lines = [header];
202
+ let total = header.length;
203
+ let skipped = 0;
204
+ const entries_list = Object.entries(entries).sort(([a], [b]) => ordinal(a, b)).slice(0, MAX_ENTRIES);
205
+ for (const [key, val] of entries_list) {
206
+ const display = val.length <= MAX_VALUE_LEN ? val : val.slice(0, MAX_VALUE_LEN) + "\u2026";
207
+ const line = `- **${key}**: ${display}`;
208
+ if (total + line.length + 1 > MAX_TOTAL_CHARS) {
209
+ skipped++;
210
+ continue;
211
+ }
212
+ lines.push(line);
213
+ total += line.length + 1;
214
+ }
215
+ if (skipped > 0) {
216
+ while (lines.length > 1 && total + `- (+${skipped} more memory entries omitted -- total size limit reached)`.length + 1 > MAX_TOTAL_CHARS) {
217
+ const popped = lines.pop();
218
+ total -= popped.length + 1;
219
+ skipped++;
220
+ }
221
+ lines.push(`- (+${skipped} more memory entries omitted -- total size limit reached)`);
222
+ }
223
+ return lines.join("\n");
224
+ } catch {
225
+ return null;
226
+ }
227
+ }
228
+ function projectNotesFor(cwd) {
229
+ if (cwd === void 0) return null;
230
+ try {
231
+ const project = findProject(cwd);
232
+ return project === null ? null : buildInjection(project.hash);
233
+ } catch {
234
+ return null;
235
+ }
236
+ }
237
+
238
+ // src/manifest.ts
38
239
  var MEM_EPOCH_TIMEOUT_MS = 800;
39
240
  var MAX_ROWS = 40;
40
241
  function appendCappedSection(lines, header, rows, cap) {
@@ -115,6 +316,8 @@ function buildManifestParts(sessionId, cwd, transcriptPath) {
115
316
  for (let i = 0; i < Math.min(rows.length, MAX_ROWS); i++) fileRows.push({ path: displaySafePath(entries[i].path), row: rows[i] });
116
317
  };
117
318
  appendFileSection("### Edited files", editedFiles, (entry) => `- ${displaySafePath(entry.path)}`);
319
+ const notes = projectNotesFor(cwd);
320
+ if (notes !== null) lines.push("", notes);
118
321
  appendFileSection("### Surgically read files (symbol/section reads, never read whole)", symbolOnlyFiles, renderSymbolReadRow);
119
322
  appendFileSection("### Read files", readFiles, renderReadRow);
120
323
  appendCappedSection(lines, "### Web URLs fetched", webFetches.map(([key, cacheId]) => renderWebFetchRow(key, cacheId)), MAX_ROWS);
@@ -123,10 +326,10 @@ function buildManifestParts(sessionId, cwd, transcriptPath) {
123
326
  const text = capManifestChars(lines.join("\n"), sessionId, cwd, transcriptPath);
124
327
  const seen = /* @__PURE__ */ new Set();
125
328
  const printed = [];
126
- for (const { path, row } of fileRows) {
127
- if (seen.has(path) || !(text.includes(row + "\n") || text.endsWith(row))) continue;
128
- seen.add(path);
129
- printed.push(path);
329
+ for (const { path: path2, row } of fileRows) {
330
+ if (seen.has(path2) || !(text.includes(row + "\n") || text.endsWith(row))) continue;
331
+ seen.add(path2);
332
+ printed.push(path2);
130
333
  }
131
334
  return { text, printed };
132
335
  }
@@ -238,6 +441,11 @@ function summaryBudgetDirective(budgetChars) {
238
441
  }
239
442
 
240
443
  export {
444
+ loadEntries,
445
+ setEntry,
446
+ unsetEntry,
447
+ clearAll,
448
+ projectNotesFor,
241
449
  renderWebFetchRow,
242
450
  manifestPrintedPaths,
243
451
  buildManifest,
@@ -10,16 +10,18 @@ import {
10
10
  querySheet,
11
11
  rangeSheet,
12
12
  xlsxColumns
13
- } from "./token-goat-chunk-STYRLQIW.mjs";
14
- import "./token-goat-chunk-L43RKNHA.mjs";
13
+ } from "./token-goat-chunk-PYSUADX4.mjs";
14
+ import "./token-goat-chunk-DNSPXQXQ.mjs";
15
15
  import "./token-goat-chunk-3BTK54F3.mjs";
16
- import "./token-goat-chunk-RIB6XY2V.mjs";
16
+ import "./token-goat-chunk-UXSXQQIY.mjs";
17
17
  import "./token-goat-chunk-XTQAOTSO.mjs";
18
18
  import "./token-goat-chunk-AH6QILZM.mjs";
19
- import "./token-goat-chunk-6E2IDLHF.mjs";
19
+ import "./token-goat-chunk-XYWPOSCN.mjs";
20
+ import "./token-goat-chunk-TCQANXYC.mjs";
20
21
  import "./token-goat-chunk-NMTKNYGF.mjs";
22
+ import "./token-goat-chunk-MELOKFDJ.mjs";
21
23
  import "./token-goat-chunk-Y4AFKTHK.mjs";
22
- import "./token-goat-chunk-GMOUBOX4.mjs";
24
+ import "./token-goat-chunk-JTKCQMQA.mjs";
23
25
  import "./token-goat-chunk-A37V4PBF.mjs";
24
26
  export {
25
27
  XlsxScanTooLargeError,