token-goat 2.9.28 → 2.9.30

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 (134) hide show
  1. package/README.md +36 -40
  2. package/SECURITY.md +28 -10
  3. package/THIRD_PARTY_NOTICES.md +40 -3
  4. package/dist/native/linux-arm64/tg-hook +0 -0
  5. package/dist/native/linux-x64/tg-hook +0 -0
  6. package/dist/ort-wasm-simd-threaded.mjs +59 -0
  7. package/dist/token-goat-chunk-3CHUNJ2O.mjs +53 -0
  8. package/dist/token-goat-chunk-3Z5S4KGM.mjs +918 -0
  9. package/dist/token-goat-chunk-4FVIAHSI.mjs +211 -0
  10. package/dist/{token-goat-chunk-66LODAUT.mjs → token-goat-chunk-4JJS54TR.mjs} +4 -3
  11. package/dist/token-goat-chunk-4LCCNRTG.mjs +313 -0
  12. package/dist/token-goat-chunk-54K3EUV3.mjs +35 -0
  13. package/dist/token-goat-chunk-56EIMS3E.mjs +159 -0
  14. package/dist/token-goat-chunk-5BCIJXMO.mjs +609 -0
  15. package/dist/token-goat-chunk-5KDMCMF2.mjs +362 -0
  16. package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
  17. package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
  18. package/dist/{token-goat-chunk-NILVK7XM.mjs → token-goat-chunk-64FBPDTK.mjs} +12 -6
  19. package/dist/{token-goat-chunk-LEG3JNJ6.mjs → token-goat-chunk-664RTTUV.mjs} +31 -15
  20. package/dist/token-goat-chunk-67TQJ76B.mjs +57 -0
  21. package/dist/token-goat-chunk-6QMAS7AB.mjs +42 -0
  22. package/dist/token-goat-chunk-7BXSNBY5.mjs +253 -0
  23. package/dist/{token-goat-chunk-F7QZRIWM.mjs → token-goat-chunk-7F2UBPD3.mjs} +42 -35
  24. package/dist/{token-goat-chunk-CC2PYJM7.mjs → token-goat-chunk-7IN2MKDS.mjs} +718 -595
  25. package/dist/token-goat-chunk-7NADEDKJ.mjs +124 -0
  26. package/dist/{token-goat-chunk-6SGLIPQB.mjs → token-goat-chunk-A3CK6N5Z.mjs} +621 -72
  27. package/dist/{token-goat-chunk-HXNAC4ZF.mjs → token-goat-chunk-AFLYLHDH.mjs} +48 -33
  28. package/dist/token-goat-chunk-AM5V6GSX.mjs +367 -0
  29. package/dist/{token-goat-chunk-I7CB3X4K.mjs → token-goat-chunk-APGZXSPS.mjs} +44 -148
  30. package/dist/{token-goat-chunk-BJBRGPBX.mjs → token-goat-chunk-ARDNEC2U.mjs} +11 -7
  31. package/dist/token-goat-chunk-ATCPY7EQ.mjs +134 -0
  32. package/dist/token-goat-chunk-B2RZZCSS.mjs +354 -0
  33. package/dist/{token-goat-chunk-QM76S6YS.mjs → token-goat-chunk-B45VMIIH.mjs} +6 -5
  34. package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
  35. package/dist/{token-goat-chunk-GGLEE35R.mjs → token-goat-chunk-C63JQV5K.mjs} +49 -10
  36. package/dist/{token-goat-chunk-RJH64KQH.mjs → token-goat-chunk-COBQGL5S.mjs} +2661 -2440
  37. package/dist/token-goat-chunk-COTXZHTS.mjs +39 -0
  38. package/dist/token-goat-chunk-CYCEYAEO.mjs +265 -0
  39. package/dist/token-goat-chunk-CZ3LUXYZ.mjs +4115 -0
  40. package/dist/token-goat-chunk-DZX2YDPT.mjs +15 -0
  41. package/dist/token-goat-chunk-E3OQX2XT.mjs +824 -0
  42. package/dist/token-goat-chunk-EFHMMIGP.mjs +68 -0
  43. package/dist/token-goat-chunk-ETBHVDB6.mjs +328 -0
  44. package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
  45. package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
  46. package/dist/{token-goat-chunk-6Z5ULNE5.mjs → token-goat-chunk-FBNQNSJK.mjs} +2490 -4957
  47. package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
  48. package/dist/{token-goat-chunk-XI2VFAV6.mjs → token-goat-chunk-FZ3NEW5O.mjs} +33 -19
  49. package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
  50. package/dist/{token-goat-chunk-VE27HPIF.mjs → token-goat-chunk-GFBSN7BD.mjs} +30 -398
  51. package/dist/{token-goat-chunk-L45ZQRT7.mjs → token-goat-chunk-GOLEOXZP.mjs} +780 -786
  52. package/dist/token-goat-chunk-H2K3QP6H.mjs +24 -0
  53. package/dist/token-goat-chunk-H2PHHGM5.mjs +188 -0
  54. package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
  55. package/dist/token-goat-chunk-HG45AF2B.mjs +2228 -0
  56. package/dist/{token-goat-chunk-CBMY2FGI.mjs → token-goat-chunk-HOJLCGDP.mjs} +17113 -15554
  57. package/dist/{token-goat-chunk-HUDC5GS5.mjs → token-goat-chunk-HYBFA5X3.mjs} +120 -19
  58. package/dist/token-goat-chunk-IVALLT3S.mjs +48 -0
  59. package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
  60. package/dist/{token-goat-chunk-UBUKHVYW.mjs → token-goat-chunk-IVKIZWAB.mjs} +3 -3
  61. package/dist/{token-goat-chunk-4JMWPWCS.mjs → token-goat-chunk-JB6QN6VF.mjs} +6 -4
  62. package/dist/{token-goat-chunk-Q4S3UQGO.mjs → token-goat-chunk-JDHE26RP.mjs} +10 -3
  63. package/dist/{token-goat-chunk-7R2XYKC5.mjs → token-goat-chunk-JDU3EXSU.mjs} +14 -10
  64. package/dist/token-goat-chunk-JDWCRD6M.mjs +253 -0
  65. package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-JN4XMLSD.mjs} +7 -4
  66. package/dist/token-goat-chunk-JTQQGXZH.mjs +733 -0
  67. package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
  68. package/dist/token-goat-chunk-KQNZDCBD.mjs +47 -0
  69. package/dist/{token-goat-chunk-4RN64ZND.mjs → token-goat-chunk-KWPNJBDH.mjs} +28 -3
  70. package/dist/token-goat-chunk-LOBGHXPB.mjs +242 -0
  71. package/dist/token-goat-chunk-MKPF4CL5.mjs +37 -0
  72. package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
  73. package/dist/{token-goat-chunk-YWSP6IU7.mjs → token-goat-chunk-N2NMER56.mjs} +25 -15
  74. package/dist/token-goat-chunk-NYKZLXMK.mjs +218 -0
  75. package/dist/token-goat-chunk-OJBNYTJP.mjs +3087 -0
  76. package/dist/token-goat-chunk-P4QMM4WK.mjs +295 -0
  77. package/dist/token-goat-chunk-PD5VKH46.mjs +184 -0
  78. package/dist/token-goat-chunk-PEPTHRFF.mjs +129 -0
  79. package/dist/{token-goat-chunk-VWZKZPSR.mjs → token-goat-chunk-PU7V3FD6.mjs} +8752 -11098
  80. package/dist/token-goat-chunk-PY533T7F.mjs +46 -0
  81. package/dist/token-goat-chunk-Q5VTGRH7.mjs +761 -0
  82. package/dist/{token-goat-chunk-IHKZ3QNA.mjs → token-goat-chunk-QCLDAQTS.mjs} +33 -19
  83. package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-QSBRTGM2.mjs} +9 -2
  84. package/dist/{token-goat-chunk-4STDIGYC.mjs → token-goat-chunk-RC35RBUL.mjs} +7 -5
  85. package/dist/{token-goat-chunk-D5ICEPSB.mjs → token-goat-chunk-RHXKCZX3.mjs} +887 -507
  86. package/dist/{token-goat-chunk-RSS3TLXU.mjs → token-goat-chunk-RZRTDST7.mjs} +17 -7
  87. package/dist/{token-goat-chunk-MAMQPC43.mjs → token-goat-chunk-SJHWVNDQ.mjs} +15 -21
  88. package/dist/token-goat-chunk-SMVRN2HU.mjs +188 -0
  89. package/dist/{token-goat-chunk-EL7M26WP.mjs → token-goat-chunk-SQSSNQPE.mjs} +2100 -1442
  90. package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-T4FK7VOV.mjs} +3 -3
  91. package/dist/token-goat-chunk-U4N3BN2W.mjs +92 -0
  92. package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
  93. package/dist/{token-goat-chunk-XKY4VKJ4.mjs → token-goat-chunk-UQ5UK2T7.mjs} +15 -4
  94. package/dist/token-goat-chunk-USILZ3T3.mjs +53 -0
  95. package/dist/token-goat-chunk-VES7EL7O.mjs +205 -0
  96. package/dist/{token-goat-chunk-M56BWPBN.mjs → token-goat-chunk-VL3YIFHZ.mjs} +550 -49
  97. package/dist/{token-goat-chunk-IZXKVT4A.mjs → token-goat-chunk-VPBBTSJR.mjs} +362 -128
  98. package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-W3QCJS6G.mjs} +10 -2
  99. package/dist/{token-goat-chunk-FSTWAOW6.mjs → token-goat-chunk-WY3L4DVT.mjs} +11 -5
  100. package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
  101. package/dist/token-goat-chunk-XKI4SEMX.mjs +66 -0
  102. package/dist/token-goat-chunk-XU4P6Z24.mjs +133 -0
  103. package/dist/{token-goat-chunk-6CCQDAYY.mjs → token-goat-chunk-Y776AENC.mjs} +138 -33
  104. package/dist/token-goat-chunk-YARZFCZS.mjs +359 -0
  105. package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
  106. package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-Z44YO3QZ.mjs} +12 -6
  107. package/dist/token-goat-chunk-Z57YODA2.mjs +35 -0
  108. package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-ZCDTCVIS.mjs} +49 -30
  109. package/dist/token-goat-chunk-ZEJVMUQH.mjs +48 -0
  110. package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
  111. package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
  112. package/dist/{token-goat-chunk-SJEKA7Y2.mjs → token-goat-chunk-ZQSJMO2R.mjs} +381 -201
  113. package/dist/token-goat-hook-client.cjs +539 -0
  114. package/dist/token-goat-hook-client.mjs +26 -0
  115. package/dist/token-goat-hook.mjs +48 -28
  116. package/dist/token-goat.core.mjs +10 -45
  117. package/docs/C4_RUNTIME_ARCHITECTURE.md +3 -3
  118. package/docs/cli.md +82 -47
  119. package/docs/install.md +58 -23
  120. package/docs/security.md +7 -7
  121. package/package.json +17 -7
  122. package/scripts/verify-native-dist.mjs +386 -0
  123. package/dist/token-goat-chunk-4JJBFT7V.mjs +0 -20
  124. package/dist/token-goat-chunk-5NNYIUGV.mjs +0 -143
  125. package/dist/token-goat-chunk-6DQNNFJ6.mjs +0 -294
  126. package/dist/token-goat-chunk-7MAFDRVR.mjs +0 -47
  127. package/dist/token-goat-chunk-BCN2YQC6.mjs +0 -32
  128. package/dist/token-goat-chunk-D7GHQKQD.mjs +0 -30
  129. package/dist/token-goat-chunk-GMOUBOX4.mjs +0 -386
  130. package/dist/token-goat-chunk-IFORDBGC.mjs +0 -192
  131. package/dist/token-goat-chunk-JXK2HQXS.mjs +0 -318
  132. package/dist/token-goat-chunk-L7SDVGBT.mjs +0 -430
  133. package/dist/token-goat-chunk-MMLMALWK.mjs +0 -1381
  134. package/dist/token-goat-chunk-MVSWBNMD.mjs +0 -1985
@@ -0,0 +1,68 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ NATIVE_FALLBACK_ENV,
5
+ RELAY_QUEUE_WAIT_MS,
6
+ buildEvent,
7
+ nativeFallbackDetail,
8
+ relay,
9
+ relayInProcess
10
+ } from "./token-goat-chunk-SQSSNQPE.mjs";
11
+ import "./token-goat-chunk-ZEJVMUQH.mjs";
12
+ import "./token-goat-chunk-GFBSN7BD.mjs";
13
+ import "./token-goat-chunk-5RG5SBL6.mjs";
14
+ import "./token-goat-chunk-KKUFXAPD.mjs";
15
+ import "./token-goat-chunk-7F2UBPD3.mjs";
16
+ import "./token-goat-chunk-54K3EUV3.mjs";
17
+ import "./token-goat-chunk-7BXSNBY5.mjs";
18
+ import "./token-goat-chunk-G5PJ7AGM.mjs";
19
+ import "./token-goat-chunk-YARZFCZS.mjs";
20
+ import "./token-goat-chunk-FBNQNSJK.mjs";
21
+ import "./token-goat-chunk-PEPTHRFF.mjs";
22
+ import "./token-goat-chunk-MNWKPRAL.mjs";
23
+ import "./token-goat-chunk-JTQQGXZH.mjs";
24
+ import "./token-goat-chunk-67TQJ76B.mjs";
25
+ import "./token-goat-chunk-H2PHHGM5.mjs";
26
+ import "./token-goat-chunk-P4QMM4WK.mjs";
27
+ import "./token-goat-chunk-5KDMCMF2.mjs";
28
+ import "./token-goat-chunk-APGZXSPS.mjs";
29
+ import "./token-goat-chunk-COBQGL5S.mjs";
30
+ import "./token-goat-chunk-ATCPY7EQ.mjs";
31
+ import "./token-goat-chunk-VPBBTSJR.mjs";
32
+ import "./token-goat-chunk-Q5VTGRH7.mjs";
33
+ import "./token-goat-chunk-Y776AENC.mjs";
34
+ import "./token-goat-chunk-SJHWVNDQ.mjs";
35
+ import "./token-goat-chunk-AFLYLHDH.mjs";
36
+ import "./token-goat-chunk-BPGCUMR7.mjs";
37
+ import "./token-goat-chunk-C63JQV5K.mjs";
38
+ import "./token-goat-chunk-JB6QN6VF.mjs";
39
+ import "./token-goat-chunk-RHXKCZX3.mjs";
40
+ import "./token-goat-chunk-EVMZJ27Z.mjs";
41
+ import "./token-goat-chunk-HYBFA5X3.mjs";
42
+ import "./token-goat-chunk-5Y6ZYL6U.mjs";
43
+ import "./token-goat-chunk-ARDNEC2U.mjs";
44
+ import "./token-goat-chunk-3Z5S4KGM.mjs";
45
+ import "./token-goat-chunk-VL3YIFHZ.mjs";
46
+ import "./token-goat-chunk-XB5KKOCG.mjs";
47
+ import "./token-goat-chunk-3BTK54F3.mjs";
48
+ import "./token-goat-chunk-4FVIAHSI.mjs";
49
+ import "./token-goat-chunk-7IN2MKDS.mjs";
50
+ import "./token-goat-chunk-U4N3BN2W.mjs";
51
+ import "./token-goat-chunk-YZAAZU2S.mjs";
52
+ import "./token-goat-chunk-IVE6U7KV.mjs";
53
+ import "./token-goat-chunk-Y4AFKTHK.mjs";
54
+ import "./token-goat-chunk-GOLEOXZP.mjs";
55
+ import "./token-goat-chunk-AM5V6GSX.mjs";
56
+ import "./token-goat-chunk-FNFBKLRD.mjs";
57
+ import "./token-goat-chunk-VES7EL7O.mjs";
58
+ import "./token-goat-chunk-KWPNJBDH.mjs";
59
+ import "./token-goat-chunk-HAVAOB3S.mjs";
60
+ import "./token-goat-chunk-A37V4PBF.mjs";
61
+ export {
62
+ NATIVE_FALLBACK_ENV,
63
+ RELAY_QUEUE_WAIT_MS,
64
+ buildEvent,
65
+ nativeFallbackDetail,
66
+ relay,
67
+ relayInProcess
68
+ };
@@ -0,0 +1,328 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ HOOK_EVENTS
5
+ } from "./token-goat-chunk-KKUFXAPD.mjs";
6
+ import {
7
+ init_define_import_meta_env
8
+ } from "./token-goat-chunk-A37V4PBF.mjs";
9
+
10
+ // src/bridges_status.ts
11
+ init_define_import_meta_env();
12
+ var NO_SERVER_HANDLER_REASON = "token-goat has no registered server-side handler for this event (zero registerHook('notification'|'stop', ...) call sites in src/) -- wiring it client-side would currently be a no-op";
13
+ var NO_POST_COMPACT_EVENT_REASON = "post_compact is a Claude Code event (hook_event_name PostCompact, carrying compact_summary); no equivalent has been confirmed for this harness, so it is left unwired rather than guessed at";
14
+ var NO_SEPARATE_FAILURE_EVENT_REASON = "post_tool_use_failure exists because Copilot CLI (postToolUseFailure) and Claude Code (PostToolUseFailure) route a failed tool result to a separate event instead of their post-tool one. No separate failure event is wired for this harness, so a failed tool call either arrives on post_tool_use like any other result or is not seen; which of the two has not been checked here";
15
+ var COPILOT_NO_POST_COMPACT_REASON = "Copilot CLI has no post-compaction hook: its HookType enum (schemas/api.schema.json, 1.0.79 and 1.0.80) declares preCompact and no postCompact, and both preCompact call sites in app.js await the hook and never assign its result. Whether the summary is reachable another way is open. app.js does emit session.compaction_complete carrying summaryContent, and the session event writer subscribes to '*' -- but emit() vs emitEphemeral() does NOT gate that writer: dispatchEventHandlers runs outside the ephemeral branch in emitInternal, on('*') early-returns past every filter, and the writer's callback applies no filter of its own before handing the JSON to native recordEventJson. The durable-vs-ephemeral decision is in Rust (api_session_event_writer.rs) and was not readable. Nor is the event uniformly summary-bearing: two of the four emit sites are the branches taken when no summary exists, summaryContent is optional in the schema, and the relay session class emits the same event via emitEphemeral. A manual /compact on 1.0.88 (tg-captures C7 and C7d) fired preCompact, and a marker returned from it reached neither the wire requests nor the model. token-goat therefore queues the session manifest at preCompact and delivers it as the next userPromptSubmitted's additionalContext, which reached the model in 5 of 5 runs on 1.0.88 (tg-captures C3)";
16
+ var NO_SUBAGENT_START_REASON = "subagent_start is wired only where the harness's subagent-start hook was shown to deliver additionalContext into the subagent itself (Copilot CLI 1.0.88, VS Code 1.137); here the spawn briefing still rides the spawn tool's prompt through pre_tool_use";
17
+ var VERIFICATION_RANK = {
18
+ dogfooded: 0,
19
+ sourced: 1,
20
+ documented: 2
21
+ };
22
+ var VERIFICATION_BLURB = {
23
+ dogfooded: "driven against the real harness binary",
24
+ sourced: "wire format read from the harness's own source or declarations, never driven against it",
25
+ documented: "wired from the harness's documentation only, never driven against it"
26
+ };
27
+ var BRIDGE_CAPABILITY_MATRIX = [
28
+ {
29
+ harness: "claudecode",
30
+ label: "Claude Code",
31
+ sourceFile: "src/install.ts (HOOK_EVENT_MAP)",
32
+ verification: "dogfooded",
33
+ verificationNote: "The harness this repo is developed and released under; CLAUDE.md requires every CLI/hook change be run against the built binary here before it ships.",
34
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "post_tool_use_failure", "pre_compact", "post_compact", "user_prompt_submit", "subagent_stop", "session_start"]),
35
+ reasons: [
36
+ { events: ["notification", "stop"], reason: NO_SERVER_HANDLER_REASON },
37
+ { events: ["subagent_start"], reason: NO_SUBAGENT_START_REASON }
38
+ ]
39
+ },
40
+ {
41
+ harness: "codex",
42
+ label: "Codex CLI",
43
+ sourceFile: "src/bridges/codex_install.ts (CODEX_HOOK_EVENTS, CODEX_GLOBAL_HOOK_EVENTS)",
44
+ verification: "dogfooded",
45
+ verificationNote: `codex-cli 0.155.0, 2026-09-22: observed running the installed config.toml hooks and delivering real payloads to the shim -- PreToolUse/PostToolUse with tool_name "Bash" and tool_input.command, and PreCompact with trigger "auto" from a forced auto-compaction. A pre-tool deny was honored (the model dropped Get-Content and ran token-goat outline instead) and post-tool additionalContext reached the model; the pre-compact response did not, which is why codex is in PRE_COMPACT_CONTEXT_DROPPED. Two conditions gate the tool events and both fail silently. config.toml must carry the matching [hooks.state] trusted_hash the installer writes, and the matcher must name the tool as it appears on the hook wire -- "Bash" for shell execution, since Codex normalizes its own exec tool into Claude Code's vocabulary before matching, while apply_patch stays native. A matcher naming the internal spelling produced a run with eight pre_compact rows and no pre_tool_use or post_tool_use row at all, and that also stranded every queued compaction manifest. Verified end to end after the fix: a forced auto-compaction run recorded eight compactions and twelve manifest deliveries in its own rollout transcript.`,
46
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "user_prompt_submit", "subagent_stop"]),
47
+ reasons: [
48
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
49
+ { events: ["notification", "stop"], reason: NO_SERVER_HANDLER_REASON },
50
+ { events: ["subagent_start"], reason: NO_SUBAGENT_START_REASON },
51
+ {
52
+ events: ["post_compact", "session_start"],
53
+ reason: "Codex CLI 0.155.0 does declare PostCompact and SessionStart -- both appear in the hook-event enum next to PreToolUse and PreCompact, so the earlier claim that it had no session-start equivalent and no post-compact event was wrong. They stay unwired for the reason the rest of this table applies: neither channel has been measured. The post-compact input has no summary field anywhere in the binary's payload key list (session_id, turn_id, agent_id, agent_type, transcript_path, hook_event_name, model, permission_mode, trigger, tool_name, tool_input, tool_use_id), so postCompactHandler would have nothing to count, and whether SessionStart forwards additionalContext has not been run"
54
+ }
55
+ ]
56
+ },
57
+ {
58
+ harness: "grok",
59
+ label: "Grok CLI",
60
+ sourceFile: "src/bridges/grok_install.ts (GROK_HOOK_EVENTS)",
61
+ verification: "dogfooded",
62
+ verificationNote: "grok 0.2.93, 2026-07-09: observed executing the global settings.json hooks config unmodified and setting GROK_SESSION_ID on every hook subprocess (src/bridges/registry.ts, src/hooks_cli.ts).",
63
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "user_prompt_submit", "subagent_stop"]),
64
+ reasons: [
65
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
66
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
67
+ { events: ["notification", "stop"], reason: NO_SERVER_HANDLER_REASON },
68
+ { events: ["subagent_start"], reason: NO_SUBAGENT_START_REASON },
69
+ {
70
+ events: ["session_start"],
71
+ reason: "GROK_HOOK_EVENTS (this row's explicit `install --grok` writer) mirrors install.ts's HOOK_EVENT_MAP as of the doc verification date -- Grok's real hooks doc has not been re-checked for SessionStart support since, so it is left unwired rather than guessed at (Grok's *default*, non---grok path still rides Claude Code's own settings.json directly and does receive session_start there, same as claudecode)"
72
+ }
73
+ ]
74
+ },
75
+ /** What Copilot CLI's wired events can actually carry, read from the shipping 1.0.80 bundle rather than from its hooks reference page. A row's `implemented` set says an event is wired; it deliberately says nothing about how much of that event's response the harness honors, and for Copilot the difference matters: - `pre_tool_use` deny is real, and the reason text reaches the model. The native string table (runtime.node offset 98057208) carries `permissionDecision`, `permissionDecisionReason`, the default "No reason provided." and the formatter "Denied by preToolUse hook: " as distinct literals, and app.js sets `{textResultForLlm: reason, resultType: "denied"}` per denial and filters that call out of execution. This was previously only an inference drawn from an incident comment; it is now confirmed. The fail-closed "(hook errored)" deny-all strings sit beside these, so that incident was behavior layered on top of a working deny handler, not a substitute for one. - `post_tool_use` honors `modifiedResult`, so compression, injection fencing and image shrink do reach the model: `postToolExecution` (app.js offset 2043150) assigns the returned `toolResultJson` onto the tool result in place. - `post_tool_use` also carries `additionalContext` to the model. The 1.0.80 bundle's JS path has no supplier for it, but on 1.0.88 the native side folds it in: a marker returned there reached the model once, appended to the tool output after `Tool "view" succeeded. Additional guidance from postToolUse hooks:` (tg-captures C1a), and returned beside `modifiedResult` both arrived once, the output replaced and the context appended (C1c). - Failed tool calls never reach `post_tool_use` at all. Copilot routes them to a separate `postToolUseFailure` event, which is handed only a stringified error and honors only `additionalContext`; `modifiedResult` is documented as not honored there. So on Copilot the output of a failed tool call reaches the model unfenced, uncompressed and unshrunk, and no response shape token-goat's shim can emit changes that. Known gap, deliberately recorded. What `additionalContext` does on that event is no longer doc-derived: app.js offset 2043380 reads the native processor's return and, when it carries `additionalContext`, either folds it into `textResultForLlm` (if `appendFailureContextToToolResult` is set) or formats it and pushes `{content, source: "system"}` onto `toolResult.newMessages`. So the channel is real and model-visible -- it just carries advice alongside the failure, never a replacement for it. It is wired now, as its own `post_tool_use_failure` event rather than a reuse of `post_tool_use`: routing failures through the success event would let success-path handlers mark a file as successfully read when the read failed. Because the channel spends tokens instead of saving them, its handler (`src/hooks_tool_failure.ts`) stays silent on a first failure and speaks only on an exact repeat. - `pre_compact` is wired and fires, but nothing it returns can reach the model. Both dispatch sites call it in statement position and drop the result: app.js offset 2467452 (the manual `/compact` path) and offset 2571216 (`case "execute_pre_compact_hook"`). The contrast is what makes this conclusive rather than an absence of evidence -- the same `event()` runner's return IS read for other events, e.g. `notification` at offset 2296123 assigns it and forwards `additionalContext` as a prepended system prompt. The compaction prompt is then built from session history and the user's own focus text, with no hook channel into it. So token-goat's `pre_compact` registration here is observe-only by construction: 1.0.88 confirmed it by run as well as by reading, since a marker returned there as `additionalContext` appeared nowhere in the wire requests, the OTel spans or the model's reply after a manual `/compact` (tg-captures C7 and C7d). The session manifest built there is queued and delivered on the next prompt instead, through `userPromptSubmitted` (see COPILOT_NO_POST_COMPACT_REASON above). */
76
+ {
77
+ harness: "copilot_cli",
78
+ label: "Copilot CLI",
79
+ sourceFile: "src/bridges/copilot_cli_install.ts (COPILOT_CLI_HOOK_EVENTS), src/bridges/copilot_cli.ts (COPILOT_TO_TG_EVENT)",
80
+ verification: "dogfooded",
81
+ verificationNote: "doctor's checkCopilotCli drives the installed shim end to end, and every hook payload field is cross-checked against Copilot's own declarations pinned at 1.0.80 (schemas/copilot_cli.hooks.json). On 1.0.88 the model-visible channels were captured on the wire (tg-captures): postToolUse additionalContext and modifiedResult (C1a, C1b, C1c), preToolUse additionalContext (C2a, C2b), userPromptSubmitted additionalContext in 5 of 5 runs (C3), subagentStart additionalContext at the start of the subagent's own prompt (C4a), and preCompact additionalContext reaching nothing (C7, C7d).",
82
+ implemented: /* @__PURE__ */ new Set([
83
+ "session_start",
84
+ "pre_tool_use",
85
+ "post_tool_use",
86
+ "pre_compact",
87
+ "stop",
88
+ "subagent_stop",
89
+ "subagent_start",
90
+ "user_prompt_submit",
91
+ "post_tool_use_failure"
92
+ ]),
93
+ reasons: [
94
+ { events: ["post_compact"], reason: COPILOT_NO_POST_COMPACT_REASON },
95
+ {
96
+ events: ["notification"],
97
+ reason: "Copilot CLI has a real 'notification' hook event, but copilot_cli.ts's COPILOT_TO_TG_EVENT deliberately leaves it (and sessionEnd/errorOccurred/permissionRequest) unimplemented rather than guessed at"
98
+ }
99
+ ]
100
+ },
101
+ {
102
+ harness: "gemini",
103
+ label: "Gemini CLI",
104
+ sourceFile: "src/bridges/gemini_install.ts (GEMINI_HOOK_EVENTS)",
105
+ verification: "sourced",
106
+ verificationNote: "Verified against Gemini CLI's published hooks reference (src/bridges/gemini_install.ts); no run against a Gemini binary is recorded here.",
107
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact"]),
108
+ reasons: [
109
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
110
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
111
+ {
112
+ events: ["notification", "stop", "user_prompt_submit", "subagent_stop", "subagent_start", "session_start"],
113
+ reason: `Gemini CLI's hooks integration only wires BeforeTool/AfterTool/PreCompress (README "Gemini CLI users")`
114
+ }
115
+ ]
116
+ },
117
+ {
118
+ harness: "qwen",
119
+ label: "Qwen Code",
120
+ sourceFile: "src/bridges/qwen_install.ts (QWEN_HOOK_EVENTS)",
121
+ verification: "documented",
122
+ verificationNote: "Wired from QwenLM/qwen-code's hooks.md, which src/bridges/qwen_install.ts states was not live-tested against a running install.",
123
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "user_prompt_submit", "subagent_stop"]),
124
+ reasons: [
125
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
126
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
127
+ {
128
+ events: ["notification"],
129
+ reason: "Only five Qwen Code events have a token-goat handler; every other real event (Notification, SessionEnd, PostToolUseFailure, StopFailure, SubagentStart, PermissionRequest, TodoCreated, TodoCompleted) is left unimplemented rather than guessed at (qwen_install.ts)"
130
+ },
131
+ { events: ["stop"], reason: NO_SERVER_HANDLER_REASON },
132
+ { events: ["subagent_start"], reason: NO_SUBAGENT_START_REASON },
133
+ {
134
+ events: ["session_start"],
135
+ reason: "QWEN_EVENT_ARG has no session-start mapping wired yet -- left unimplemented rather than guessed at"
136
+ }
137
+ ]
138
+ },
139
+ {
140
+ harness: "vscode",
141
+ label: "VS Code (Copilot agent)",
142
+ sourceFile: "src/bridges/vscode_install.ts (vscodeHooksDir), src/bridges/copilot_cli.ts (isVscodePayload), src/bridges/vscode_hooks.ts",
143
+ verification: "sourced",
144
+ verificationNote: "Hook-file parsing, payload keys, tool names and response fields read from the VS Code 1.136.0 bundle (workbench.desktop.main.js, extensions/copilot/dist/extension.js, extensions/copilot/package.json); the installed shim is driven with VS Code-shaped payloads, but no run inside a live VS Code is recorded here.",
145
+ implemented: /* @__PURE__ */ new Set(["session_start", "pre_tool_use", "post_tool_use", "user_prompt_submit", "subagent_stop", "subagent_start"]),
146
+ reasons: [
147
+ {
148
+ events: ["pre_compact", "post_tool_use_failure"],
149
+ reason: "VS Code reads the shared Copilot hooks file but maps only sessionStart, sessionEnd, userPromptSubmitted, preToolUse, postToolUse, agentStop, subagentStop and errorOccurred out of it, so the file's preCompact and postToolUseFailure entries never fire there. Re-read in the 1.138.0 bundle, where the github-copilot branch of that table still lists exactly those eight: the compaction manifest is unavailable on this harness rather than merely unwired, and unlike Copilot CLI and Codex there is no queueing fallback, because the trigger itself never arrives"
150
+ },
151
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
152
+ { events: ["notification", "stop"], reason: NO_SERVER_HANDLER_REASON }
153
+ ]
154
+ },
155
+ {
156
+ harness: "visualstudio",
157
+ label: "Visual Studio (Copilot agent)",
158
+ sourceFile: "src/bridges/visualstudio_install.ts",
159
+ verification: "documented",
160
+ verificationNote: "MCP file locations and the servers key from Microsoft's Visual Studio MCP docs (learn.microsoft.com/en-us/visualstudio/ide/mcp-servers), instructions paths from its Copilot chat context page; no run inside a live Visual Studio is recorded here.",
161
+ implemented: /* @__PURE__ */ new Set(),
162
+ reasons: [
163
+ {
164
+ events: [...HOOK_EVENTS],
165
+ reason: "Visual Studio documents no agent hooks (GitHub lists hooks only for Copilot cloud agent and Copilot CLI), so install --visualstudio writes no hooks file and token-goat works there through its MCP tools and instructions only"
166
+ }
167
+ ]
168
+ },
169
+ {
170
+ harness: "kimi",
171
+ label: "Kimi Code CLI",
172
+ sourceFile: "src/bridges/kimi_install.ts (KIMI_EVENT_ARG), src/bridges/kimi.ts (KIMI_HOOK_SCRIPT)",
173
+ verification: "sourced",
174
+ verificationNote: "Payload keys and response contract read from MoonshotAI/kimi-code's own source (externalHooksRunner/runner.ts, externalHooksService.ts); no run against a Kimi binary is recorded here.",
175
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "user_prompt_submit", "subagent_stop", "session_start"]),
176
+ reasons: [
177
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
178
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
179
+ { events: ["notification", "stop"], reason: NO_SERVER_HANDLER_REASON },
180
+ { events: ["subagent_start"], reason: NO_SUBAGENT_START_REASON }
181
+ ]
182
+ },
183
+ {
184
+ harness: "antigravity",
185
+ label: "Antigravity CLI (agy)",
186
+ sourceFile: "src/bridges/antigravity_install.ts (ANTIGRAVITY_HOOK_EVENTS), src/bridges/antigravity_hooks.ts, src/hooks_cli.ts (antigravityToCanonicalWire)",
187
+ verification: "documented",
188
+ verificationNote: `PreToolUse/PostToolUse payload and response fields from atamel.dev's "Where agy hooks" (2026-07-16). The plugin layout and the Windows command form were driven against agy 1.2.11 (a plugin hook fired with the plugin directory as its working directory), but a tool event was not: agy's quota refused the model call, so no PreToolUse payload has been captured.`,
189
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use"]),
190
+ reasons: [
191
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
192
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
193
+ { events: ["notification", "stop"], reason: NO_SERVER_HANDLER_REASON },
194
+ { events: ["subagent_start"], reason: NO_SUBAGENT_START_REASON },
195
+ {
196
+ events: ["pre_compact", "session_start", "subagent_stop"],
197
+ reason: "agy documents PreToolUse, PostToolUse, PreInvocation, PostInvocation and Stop only: no compaction, session-start or subagent event exists to wire"
198
+ },
199
+ {
200
+ events: ["user_prompt_submit"],
201
+ reason: "agy's nearest event is PreInvocation, which fires before each model call rather than once per prompt, and its payload has not been captured; left unwired rather than guessed at"
202
+ }
203
+ ]
204
+ },
205
+ {
206
+ harness: "opencode",
207
+ label: "opencode",
208
+ sourceFile: "src/bridges/opencode.ts",
209
+ verification: "sourced",
210
+ verificationNote: "Tool ids, parameter keys and handler behavior read directly from opencode's own source (src/bridges/opencode.ts); no run against a running gateway is recorded here.",
211
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact"]),
212
+ reasons: [
213
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
214
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
215
+ {
216
+ events: ["notification", "stop", "user_prompt_submit", "subagent_stop", "subagent_start", "session_start"],
217
+ reason: "opencode's plugin API only exposes three relevant hooks -- tool.execute.before, tool.execute.after, experimental.session.compacting (opencode.ts module docstring, verified against opencode's real source)"
218
+ }
219
+ ]
220
+ },
221
+ {
222
+ harness: "openclaw",
223
+ label: "OpenClaw",
224
+ sourceFile: "src/bridges/openclaw.ts",
225
+ verification: "sourced",
226
+ verificationNote: "Verified against the live plugin docs and OpenClaw's aristotle-agent/types.ts; the bridge's own note lists what stays unverified without a live instance (built-in tool names, session id).",
227
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact"]),
228
+ reasons: [
229
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
230
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
231
+ {
232
+ events: ["notification", "stop", "user_prompt_submit", "subagent_stop", "subagent_start", "session_start"],
233
+ reason: "OpenClaw's in-process plugin API only exposes before_tool_call/after_tool_call/before_compaction as api.on() handlers relevant here"
234
+ }
235
+ ]
236
+ },
237
+ {
238
+ harness: "pi",
239
+ label: "pi (pi-coding-agent)",
240
+ sourceFile: "src/bridges/pi.ts",
241
+ verification: "sourced",
242
+ verificationNote: "Response shape verified against pi's own TextContent/ImageContent types (src/bridges/pi.ts); no run against a pi binary is recorded here.",
243
+ implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact"]),
244
+ reasons: [
245
+ { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
246
+ { events: ["post_compact"], reason: NO_POST_COMPACT_EVENT_REASON },
247
+ {
248
+ events: ["notification", "stop", "user_prompt_submit", "subagent_stop", "subagent_start", "session_start"],
249
+ reason: "pi's extension API subscribes to session_start/tool_call/tool_result/session_before_compact/session_compact, of which only tool_call/tool_result/session_before_compact map onto real HOOK_EVENTS names (pre_tool_use/post_tool_use/pre_compact) -- pi's own session_start event is never forwarded to token-goat's callHook()"
250
+ }
251
+ ]
252
+ }
253
+ ];
254
+ function bridgesStatusToJson(matrix = BRIDGE_CAPABILITY_MATRIX) {
255
+ return matrix.map((row) => {
256
+ const events = {};
257
+ for (const event of HOOK_EVENTS) {
258
+ events[event] = row.implemented.has(event);
259
+ }
260
+ const reasons = {};
261
+ for (const { events: missingEvents, reason } of row.reasons) {
262
+ for (const event of missingEvents) {
263
+ reasons[event] = reason;
264
+ }
265
+ }
266
+ return {
267
+ harness: row.harness,
268
+ label: row.label,
269
+ sourceFile: row.sourceFile,
270
+ verification: row.verification,
271
+ verificationNote: row.verificationNote,
272
+ events,
273
+ reasons
274
+ };
275
+ });
276
+ }
277
+ function formatBridgesStatus(matrix = BRIDGE_CAPABILITY_MATRIX) {
278
+ const lines = [];
279
+ lines.push("# Bridge hook-event parity matrix");
280
+ lines.push("");
281
+ lines.push("Columns: " + HOOK_EVENTS.join(", ") + " (source: HOOK_EVENTS in src/types.ts)");
282
+ lines.push("Read-only static analysis of src/bridges/*_install.ts and *.ts -- never invokes a real harness binary.");
283
+ lines.push("");
284
+ const harnessWidth = Math.max(...matrix.map((r) => r.harness.length), "harness".length);
285
+ const verifyWidth = Math.max(...matrix.map((r) => r.verification.length), "verified".length);
286
+ const header = ["harness".padEnd(harnessWidth), ...HOOK_EVENTS.map((e) => e), "score", "verified".padEnd(verifyWidth)].join(" ");
287
+ lines.push(header);
288
+ for (const row of matrix) {
289
+ const cells = HOOK_EVENTS.map((event) => {
290
+ const cell = row.implemented.has(event) ? "yes" : "no";
291
+ return cell.padEnd(event.length);
292
+ });
293
+ const score = `${row.implemented.size}/${HOOK_EVENTS.length}`;
294
+ lines.push([row.harness.padEnd(harnessWidth), ...cells, score, row.verification.padEnd(verifyWidth)].join(" "));
295
+ }
296
+ lines.push("");
297
+ lines.push("## How each row was established");
298
+ for (const level of Object.keys(VERIFICATION_RANK)) {
299
+ lines.push(`- ${level}: ${VERIFICATION_BLURB[level]}`);
300
+ }
301
+ lines.push("");
302
+ for (const row of [...matrix].sort((a, b) => VERIFICATION_RANK[a.verification] - VERIFICATION_RANK[b.verification])) {
303
+ lines.push(`- ${row.harness} (${row.verification}): ${row.verificationNote}`);
304
+ }
305
+ const gapRows = matrix.filter((r) => r.reasons.length > 0);
306
+ if (gapRows.length > 0) {
307
+ lines.push("");
308
+ lines.push("## Documented gaps");
309
+ for (const row of gapRows) {
310
+ for (const { events, reason } of row.reasons) {
311
+ lines.push(`- ${row.harness}: ${events.join(", ")} -- ${reason}`);
312
+ }
313
+ }
314
+ }
315
+ return lines.join("\n");
316
+ }
317
+ function installVerificationNotice(harness) {
318
+ const row = BRIDGE_CAPABILITY_MATRIX.find((r) => r.harness === harness);
319
+ if (row === void 0 || row.verification === "dogfooded") return null;
320
+ return `NOTE: the ${row.label} bridge is ${row.verification} -- ${VERIFICATION_BLURB[row.verification]}. If a token-goat feature seems to do nothing here, run \`token-goat doctor\` (its "Tool names" check reports what ${row.label} actually sent) and please open an issue. Details: token-goat bridges-status.`;
321
+ }
322
+
323
+ export {
324
+ BRIDGE_CAPABILITY_MATRIX,
325
+ bridgesStatusToJson,
326
+ formatBridgesStatus,
327
+ installVerificationNotice
328
+ };
@@ -0,0 +1,147 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ init_define_import_meta_env
5
+ } from "./token-goat-chunk-A37V4PBF.mjs";
6
+
7
+ // src/line_matchers.ts
8
+ init_define_import_meta_env();
9
+ var ATX_OPEN_RE = /^ {0,3}(#{1,6})(\s+)/;
10
+ var TABLE_OPEN_RE = /^\s*\[+/;
11
+ var TOML_OPEN_RE = /^\s*\[/;
12
+ var TABLE_TAIL_RE = /^\s*(?:[#;].*)?$/;
13
+ var WS_RE = /\s/;
14
+ var ATX_DOT_BREAK_RE = /[\n\r\u{2028}\u{2029}]/u;
15
+ var ATX_CLASS_BREAK_RE = /[\r\n]/;
16
+ function matchAtxHeading(line, lineBreak, absorbTrailingSpace) {
17
+ const open = ATX_OPEN_RE.exec(line);
18
+ if (open === null) return null;
19
+ const level = open[1].length;
20
+ const gap = open[2];
21
+ const rest = line.slice(open[0].length);
22
+ if (rest === "") {
23
+ if (gap.length < 2) return null;
24
+ const lowest = absorbTrailingSpace ? 1 : gap.length - 1;
25
+ for (let j = gap.length - 1; j >= lowest; j--) if (!lineBreak.test(gap.charAt(j))) return { level, name: "" };
26
+ return null;
27
+ }
28
+ const body = rest.trimEnd();
29
+ let hashStart = body.length;
30
+ while (hashStart > 0 && body.charAt(hashStart - 1) === "#") hashStart--;
31
+ let title = absorbTrailingSpace ? body : rest;
32
+ if (hashStart < body.length && hashStart > 0 && WS_RE.test(body.charAt(hashStart - 1))) {
33
+ let p = hashStart;
34
+ while (p > 0 && WS_RE.test(body.charAt(p - 1))) p--;
35
+ title = body.slice(0, p);
36
+ }
37
+ if (lineBreak.test(title)) return hashStart === 0 ? closingFromGap(gap, level, lineBreak) : null;
38
+ return { level, name: title.trim() };
39
+ }
40
+ function closingFromGap(gap, level, lineBreak) {
41
+ for (let i = gap.length - 2; i >= 1; i--) if (!lineBreak.test(gap.charAt(i))) return { level, name: "" };
42
+ return null;
43
+ }
44
+ function matchTomlSectionName(line) {
45
+ const open = TOML_OPEN_RE.exec(line);
46
+ if (open === null) return null;
47
+ const close = line.indexOf("]", open[0].length);
48
+ if (close < 0) return null;
49
+ const inner = line.slice(open[0].length, close);
50
+ const start = inner.startsWith("[") ? 1 : 0;
51
+ let first = start;
52
+ while (first < inner.length && WS_RE.test(inner.charAt(first))) first++;
53
+ if (first < inner.length) return inner.slice(first);
54
+ if (first > start) return inner.charAt(first - 1);
55
+ return start === 1 ? "[" : null;
56
+ }
57
+ function matchTableHeaderName(line) {
58
+ const open = TABLE_OPEN_RE.exec(line);
59
+ if (open === null) return null;
60
+ const close = line.indexOf("]", open[0].length);
61
+ if (close < 0) return null;
62
+ let after = close;
63
+ while (line.charAt(after) === "]") after++;
64
+ if (!TABLE_TAIL_RE.test(line.slice(after))) return null;
65
+ const inner = line.slice(open[0].length, close);
66
+ let first = 0;
67
+ while (first < inner.length && WS_RE.test(inner.charAt(first))) first++;
68
+ if (first < inner.length) {
69
+ let last = inner.length;
70
+ while (WS_RE.test(inner.charAt(last - 1))) last--;
71
+ return inner.slice(first, last);
72
+ }
73
+ if (first > 0) return inner.charAt(first - 1);
74
+ return open[0].trimStart().length >= 2 ? "[" : null;
75
+ }
76
+ function matchRuleBannerTitle(line) {
77
+ const n = line.length;
78
+ if (line.charAt(0) !== "#") return null;
79
+ let p = 1;
80
+ while (p < n && WS_RE.test(line.charAt(p))) p++;
81
+ let run = 0;
82
+ while (p + run < n && isRuleChar(line.charAt(p + run))) run++;
83
+ let tail = 0;
84
+ while (tail < n && isRuleChar(line.charAt(n - 1 - tail))) tail++;
85
+ if (run < 2 || tail < 2) return null;
86
+ let wsStart = n - tail;
87
+ while (WS_RE.test(line.charAt(wsStart - 1))) wsStart--;
88
+ const firstEnd = (from) => {
89
+ if (from <= wsStart) return wsStart;
90
+ const end = Math.max(from, n - tail + 1);
91
+ return end <= n - 2 ? end : -1;
92
+ };
93
+ const nextBreak = lineBreakIndex(line);
94
+ for (let k = run; k >= 2; k--) {
95
+ let start = p + k;
96
+ if (k === run) while (start < n && WS_RE.test(line.charAt(start))) start++;
97
+ if (start >= n) continue;
98
+ const end = firstEnd(start + 2);
99
+ if (end >= 0 && nextBreak(start) >= end) return line.slice(start, end);
100
+ if (firstEnd(start + 1) === start + 1) return line.charAt(start);
101
+ }
102
+ return null;
103
+ }
104
+ function matchRestOfLine(text, start, minGap) {
105
+ const n = text.length;
106
+ let k = start;
107
+ while (k < n && WS_RE.test(text.charAt(k))) k++;
108
+ if (k - start < minGap) return null;
109
+ if (k < n) {
110
+ let lineEnd = k;
111
+ while (lineEnd < n && !ATX_DOT_BREAK_RE.test(text.charAt(lineEnd))) lineEnd++;
112
+ return text.slice(k, lineEnd).trimEnd();
113
+ }
114
+ for (let m = n - 1; m >= start + minGap; m--) if (!ATX_DOT_BREAK_RE.test(text.charAt(m))) return text.charAt(m);
115
+ return null;
116
+ }
117
+ function isRuleChar(c) {
118
+ return c === "-" || c === "=";
119
+ }
120
+ function lineBreakIndex(line) {
121
+ if (!ATX_DOT_BREAK_RE.test(line)) return () => line.length;
122
+ const next = new Array(line.length + 1);
123
+ next[line.length] = line.length;
124
+ for (let i = line.length - 1; i >= 0; i--) next[i] = ATX_DOT_BREAK_RE.test(line.charAt(i)) ? i : next[i + 1];
125
+ return (from) => next[from];
126
+ }
127
+ function matchCssSelectorSpan(line) {
128
+ const brace = line.indexOf("{");
129
+ if (brace < 0) return null;
130
+ let indent = 0;
131
+ while (indent < line.length && (line.charAt(indent) === " " || line.charAt(indent) === " ")) indent++;
132
+ let start = Math.min(indent, brace - 1);
133
+ if (start >= 0 && (line.charAt(start) === "}" || line.charAt(start) === "@")) start--;
134
+ if (start < 0) return null;
135
+ return { start, end: brace };
136
+ }
137
+
138
+ export {
139
+ ATX_DOT_BREAK_RE,
140
+ ATX_CLASS_BREAK_RE,
141
+ matchAtxHeading,
142
+ matchTomlSectionName,
143
+ matchTableHeaderName,
144
+ matchRuleBannerTitle,
145
+ matchRestOfLine,
146
+ matchCssSelectorSpan
147
+ };