@fusengine/harness 0.1.89 → 0.1.91

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 (419) hide show
  1. package/dist/adapters/claude/index.d.mts +1 -1
  2. package/dist/adapters/claude/index.mjs +1 -1
  3. package/dist/adapters/cline/index.mjs +1 -1
  4. package/dist/adapters/codex/index.d.mts +2 -2
  5. package/dist/adapters/codex/index.mjs +5 -4
  6. package/dist/adapters/cursor/index.d.mts +15 -28
  7. package/dist/adapters/cursor/index.mjs +35 -46
  8. package/dist/adapters/gemini/index.mjs +1 -1
  9. package/dist/adapters/hermes/index.d.mts +1 -1
  10. package/dist/adapters/hermes/index.mjs +1 -1
  11. package/dist/adapters/kimi/index.d.mts +1 -1
  12. package/dist/adapters/kimi/index.mjs +1 -1
  13. package/dist/{claude-5bC8TDAz.mjs → claude-Ckv2_TgP.mjs} +3 -43
  14. package/dist/cli/bin.mjs +429 -16
  15. package/dist/cli/index.mjs +1 -1
  16. package/dist/command-string-CALMTnwN.mjs +42 -0
  17. package/dist/{evaluate-C1VSI5pb.mjs → evaluate-CMiIqHeH.mjs} +261 -13
  18. package/dist/{handle-DHhukRdh.mjs → handle-C43gA-Pr.mjs} +737 -150
  19. package/dist/{hermes-kP6NUQlG.mjs → hermes-B9-p_3IF.mjs} +3 -2
  20. package/dist/{index-DBgnIZn9.d.mts → index-B8PG82su.d.mts} +1 -1
  21. package/dist/{index-D4C2-IIc.d.mts → index-SmKYkk2N.d.mts} +1 -1
  22. package/dist/index.d.mts +2 -2
  23. package/dist/index.mjs +2 -2
  24. package/dist/init/index.d.mts +1 -1
  25. package/dist/init/index.mjs +1 -1
  26. package/dist/{kimi-D6X7b8wF.mjs → kimi-G2wcSh5-.mjs} +3 -2
  27. package/dist/normalize-BjG6unTj.mjs +317 -0
  28. package/dist/permission-mode-B-SFyR0X.mjs +226 -0
  29. package/dist/policy/index.d.mts +1 -1
  30. package/dist/policy/index.mjs +2 -2
  31. package/dist/prompt/index.d.mts +1 -1
  32. package/dist/{run-CdIlUtjv.mjs → run-DkrzC0gb.mjs} +1 -1
  33. package/dist/{run-TAXNRSpD.mjs → run-GHAMqcOn.mjs} +26 -3
  34. package/dist/runtime/index.d.mts +27 -16
  35. package/dist/runtime/index.mjs +2 -2
  36. package/dist/{types-C0-igRKr.d.mts → types-Bh0jEF3_.d.mts} +2 -0
  37. package/dist/{validate-DZFtAbLP.mjs → validate-KjZ1X9tH.mjs} +1 -1
  38. package/package.json +3 -2
  39. package/src/adapters/claude/index.ts +92 -0
  40. package/src/adapters/cline/index.ts +36 -0
  41. package/src/adapters/codex/apply-patch.ts +94 -0
  42. package/src/adapters/codex/index.ts +84 -0
  43. package/src/adapters/codex/permission-mode.ts +16 -0
  44. package/src/adapters/cursor/context.ts +46 -0
  45. package/src/adapters/cursor/events.ts +38 -0
  46. package/src/adapters/cursor/index.ts +43 -0
  47. package/src/adapters/cursor/interfaces/types.ts +88 -0
  48. package/src/adapters/cursor/native-response.ts +158 -0
  49. package/src/adapters/cursor/normalize.ts +123 -0
  50. package/src/adapters/cursor/respond.ts +123 -0
  51. package/src/adapters/gemini/index.ts +36 -0
  52. package/src/adapters/hermes/index.ts +55 -0
  53. package/src/adapters/hermes/interfaces/types.ts +26 -0
  54. package/src/adapters/kimi/index.ts +96 -0
  55. package/src/adapters/kimi/interfaces/types.ts +55 -0
  56. package/src/cache/compact.ts +55 -0
  57. package/src/cache/index.ts +5 -0
  58. package/src/cache/io.ts +38 -0
  59. package/src/cache/mcp-response.ts +39 -0
  60. package/src/cache/mcp-store.ts +70 -0
  61. package/src/cache/store.ts +93 -0
  62. package/src/changelog/fetch.ts +79 -0
  63. package/src/cli/bin.ts +100 -0
  64. package/src/cli/cursor-event-scanner.ts +175 -0
  65. package/src/cli/cursor-stdin-reader.ts +65 -0
  66. package/src/cli/doctor.ts +96 -0
  67. package/src/cli/hook-io.ts +130 -0
  68. package/src/cli/hook-sound.ts +49 -0
  69. package/src/cli/index.ts +1 -0
  70. package/src/cli/json-primitive-scanner.ts +83 -0
  71. package/src/cli/run.ts +36 -0
  72. package/src/cli/scope.ts +31 -0
  73. package/src/codex-rules/build.ts +63 -0
  74. package/src/codex-rules/index.ts +8 -0
  75. package/src/codex-rules/mapping.ts +42 -0
  76. package/src/codex-rules/rules/absolute-paths.ts +52 -0
  77. package/src/codex-rules/rules/ask.ts +44 -0
  78. package/src/codex-rules/rules/chmod-ask.ts +57 -0
  79. package/src/codex-rules/rules/dd.ts +23 -0
  80. package/src/codex-rules/rules/diskutil.ts +33 -0
  81. package/src/codex-rules/rules/mkfs.ts +42 -0
  82. package/src/codex-rules/rules/privilege.ts +49 -0
  83. package/src/codex-rules/rules/remote-fetch.ts +31 -0
  84. package/src/codex-rules/rules/rm-variants.ts +58 -0
  85. package/src/codex-rules/rules/single-commands.ts +57 -0
  86. package/src/codex-rules/skip-list.ts +25 -0
  87. package/src/codex-rules/starlark.ts +46 -0
  88. package/src/codex-rules/types.ts +36 -0
  89. package/src/config/dotenv.ts +55 -0
  90. package/src/config/env.ts +10 -0
  91. package/src/config/home-dir.ts +36 -0
  92. package/src/config/index.ts +5 -0
  93. package/src/config/layout.ts +52 -0
  94. package/src/config/limits.ts +56 -0
  95. package/src/config/ttl.ts +30 -0
  96. package/src/detect/harness.ts +73 -0
  97. package/src/detect/index.ts +1 -0
  98. package/src/detect/interfaces/types.ts +18 -0
  99. package/src/freshness/agent-evidence-record.ts +95 -0
  100. package/src/freshness/agent-evidence.ts +95 -0
  101. package/src/freshness/codex-spawn-evidence.ts +91 -0
  102. package/src/freshness/doc-helpers.ts +90 -0
  103. package/src/freshness/evidence-harvest-io.ts +72 -0
  104. package/src/freshness/evidence-harvest.ts +61 -0
  105. package/src/freshness/explore-tools.ts +95 -0
  106. package/src/freshness/index.ts +2 -0
  107. package/src/freshness/query-framework.ts +73 -0
  108. package/src/freshness/ref-evidence.ts +49 -0
  109. package/src/freshness/ref-journal.ts +98 -0
  110. package/src/freshness/trivial-edit-counter.ts +30 -0
  111. package/src/index.ts +11 -0
  112. package/src/init/index.ts +2 -0
  113. package/src/init/run.ts +32 -0
  114. package/src/init/templates.ts +75 -0
  115. package/src/memory/gitignore.ts +14 -0
  116. package/src/memory/index.ts +3 -0
  117. package/src/memory/registry.ts +39 -0
  118. package/src/memory/session-roots.ts +99 -0
  119. package/src/memory/state.ts +58 -0
  120. package/src/policy/apex-authorization.ts +100 -0
  121. package/src/policy/apex-gates.ts +91 -0
  122. package/src/policy/apex-target-steps.ts +73 -0
  123. package/src/policy/apex-target.ts +49 -0
  124. package/src/policy/apex-task-context.ts +81 -0
  125. package/src/policy/apex.ts +94 -0
  126. package/src/policy/cartographer/build-tree.ts +69 -0
  127. package/src/policy/cartographer/describe.ts +53 -0
  128. package/src/policy/cartographer/entry.ts +38 -0
  129. package/src/policy/cartographer/frontmatter.ts +48 -0
  130. package/src/policy/cartographer/indicators.ts +34 -0
  131. package/src/policy/claude-md-context.ts +66 -0
  132. package/src/policy/conventions/index.ts +11 -0
  133. package/src/policy/conventions/interfaces.ts +71 -0
  134. package/src/policy/conventions/langs.ts +53 -0
  135. package/src/policy/conventions/query.ts +49 -0
  136. package/src/policy/conventions/react-hooks.ts +18 -0
  137. package/src/policy/conventions/store-or-query.ts +21 -0
  138. package/src/policy/conventions/stores.ts +56 -0
  139. package/src/policy/conventions/strip.ts +87 -0
  140. package/src/policy/conventions/verdict.ts +38 -0
  141. package/src/policy/creation-intent.ts +11 -0
  142. package/src/policy/deny-loop.ts +88 -0
  143. package/src/policy/design/allowed-write.ts +28 -0
  144. package/src/policy/design/content-checks.ts +45 -0
  145. package/src/policy/design/corpus-fs.ts +21 -0
  146. package/src/policy/design/corpus-resolve-cache.ts +49 -0
  147. package/src/policy/design/corpus-resolve.ts +99 -0
  148. package/src/policy/design/corpus.ts +92 -0
  149. package/src/policy/design/design-system-rules.ts +45 -0
  150. package/src/policy/design/flag.ts +30 -0
  151. package/src/policy/design/gates-pipeline.ts +105 -0
  152. package/src/policy/design/gates.ts +87 -0
  153. package/src/policy/design/screenshot-tools.ts +24 -0
  154. package/src/policy/design/skill-evidence.ts +34 -0
  155. package/src/policy/design/skill-gate.ts +81 -0
  156. package/src/policy/design/skill-triggers.ts +51 -0
  157. package/src/policy/design/state.ts +92 -0
  158. package/src/policy/design/template-urls.ts +54 -0
  159. package/src/policy/design/transitions.ts +68 -0
  160. package/src/policy/detect-claude-md-project-type.ts +32 -0
  161. package/src/policy/detect-framework.ts +99 -0
  162. package/src/policy/detect-primitive-checks.ts +100 -0
  163. package/src/policy/detect-primitive-lib.ts +55 -0
  164. package/src/policy/detect-project.ts +99 -0
  165. package/src/policy/edit-outcome.ts +53 -0
  166. package/src/policy/evaluate.ts +81 -0
  167. package/src/policy/expert-agents.ts +60 -0
  168. package/src/policy/file-size-scope.ts +32 -0
  169. package/src/policy/file-size.ts +99 -0
  170. package/src/policy/framework-solid-exclude.ts +52 -0
  171. package/src/policy/framework-solid-extended.ts +93 -0
  172. package/src/policy/framework-solid-gates-systems.ts +99 -0
  173. package/src/policy/framework-solid-gates.ts +98 -0
  174. package/src/policy/framework-solid.ts +88 -0
  175. package/src/policy/gemini-mcp-gate.ts +83 -0
  176. package/src/policy/git-gates.ts +40 -0
  177. package/src/policy/guards/bash-command-anchor.ts +40 -0
  178. package/src/policy/guards/bash-write-patterns.ts +140 -0
  179. package/src/policy/guards/bash-write-redirects.ts +201 -0
  180. package/src/policy/guards/bash-write-safe-paths.ts +62 -0
  181. package/src/policy/guards/bash-write.ts +76 -0
  182. package/src/policy/guards/context.ts +12 -0
  183. package/src/policy/guards/index.ts +61 -0
  184. package/src/policy/guards/install.ts +22 -0
  185. package/src/policy/guards/interface-separation-ext.ts +41 -0
  186. package/src/policy/guards/interface-separation.ts +100 -0
  187. package/src/policy/guards/protected-path.ts +100 -0
  188. package/src/policy/guards/security.ts +97 -0
  189. package/src/policy/index.ts +19 -0
  190. package/src/policy/interfaces/types.ts +46 -0
  191. package/src/policy/js-gate-route.ts +51 -0
  192. package/src/policy/lessons/lesson-gate.ts +0 -0
  193. package/src/policy/lessons/trigger-index.ts +84 -0
  194. package/src/policy/lessons/types.ts +31 -0
  195. package/src/policy/module-layout.ts +31 -0
  196. package/src/policy/nearest-manifest.ts +75 -0
  197. package/src/policy/never-approval.ts +95 -0
  198. package/src/policy/patterns.ts +80 -0
  199. package/src/policy/seo/validate.ts +51 -0
  200. package/src/policy/shadcn-project.ts +22 -0
  201. package/src/policy/shadcn-skill-gate.ts +97 -0
  202. package/src/policy/shell-read-refs.ts +96 -0
  203. package/src/policy/skill-path.ts +46 -0
  204. package/src/policy/skill-patterns/laravel.ts +40 -0
  205. package/src/policy/skill-patterns/nextjs.ts +29 -0
  206. package/src/policy/skill-patterns/react.ts +27 -0
  207. package/src/policy/skill-patterns/shadcn-subskills.ts +33 -0
  208. package/src/policy/skill-patterns/shadcn.ts +66 -0
  209. package/src/policy/skill-patterns/swift.ts +30 -0
  210. package/src/policy/skill-patterns/tailwind.ts +40 -0
  211. package/src/policy/skill-source.ts +52 -0
  212. package/src/policy/skill-trigger-patterns.ts +33 -0
  213. package/src/policy/skill-triggers.ts +108 -0
  214. package/src/policy/tailwind-skill-gate.ts +63 -0
  215. package/src/policy/trivial-edits.ts +52 -0
  216. package/src/policy/verbosity.ts +39 -0
  217. package/src/prompt/index.ts +1 -0
  218. package/src/prompt/types.ts +36 -0
  219. package/src/refs/discover.ts +69 -0
  220. package/src/refs/frontmatter.ts +24 -0
  221. package/src/refs/index.ts +4 -0
  222. package/src/refs/loader.ts +59 -0
  223. package/src/refs/ref-key.ts +41 -0
  224. package/src/refs/router.ts +63 -0
  225. package/src/refs/types.ts +25 -0
  226. package/src/runtime/activity.ts +99 -0
  227. package/src/runtime/apply-patch-gate.ts +41 -0
  228. package/src/runtime/burst-window.ts +21 -0
  229. package/src/runtime/codex-shell-tool.ts +37 -0
  230. package/src/runtime/command-string.ts +37 -0
  231. package/src/runtime/confirm/codex-confirm.ts +126 -0
  232. package/src/runtime/confirm/codex-prompt-origin.ts +16 -0
  233. package/src/runtime/confirm/confirm-code.ts +33 -0
  234. package/src/runtime/confirm/confirm-gate.ts +65 -0
  235. package/src/runtime/confirm/confirm-irreversible.ts +32 -0
  236. package/src/runtime/confirm/confirm-pending.ts +34 -0
  237. package/src/runtime/confirm/confirm-state.ts +56 -0
  238. package/src/runtime/confirm/confirm-subagent.ts +112 -0
  239. package/src/runtime/confirm/confirm-submit.ts +38 -0
  240. package/src/runtime/core-guards-active.ts +84 -0
  241. package/src/runtime/core-guards-wired.ts +47 -0
  242. package/src/runtime/deny-loop-store.ts +94 -0
  243. package/src/runtime/deny-notice.ts +52 -0
  244. package/src/runtime/design-cache-resolve.ts +51 -0
  245. package/src/runtime/design-content-gate.ts +95 -0
  246. package/src/runtime/design-files-gate.ts +114 -0
  247. package/src/runtime/design-helpers.ts +93 -0
  248. package/src/runtime/design-lifecycle.ts +39 -0
  249. package/src/runtime/design-read-credit.ts +28 -0
  250. package/src/runtime/design.ts +116 -0
  251. package/src/runtime/dev-context.ts +43 -0
  252. package/src/runtime/dry-patterns.ts +32 -0
  253. package/src/runtime/dry.ts +96 -0
  254. package/src/runtime/fragment-registry.ts +33 -0
  255. package/src/runtime/framework-skill-gate.ts +79 -0
  256. package/src/runtime/fs-cleanup.ts +71 -0
  257. package/src/runtime/gate-apex.ts +81 -0
  258. package/src/runtime/gate-helpers.ts +52 -0
  259. package/src/runtime/gate-input.ts +26 -0
  260. package/src/runtime/gate.ts +128 -0
  261. package/src/runtime/handle-post.ts +104 -0
  262. package/src/runtime/handle-pre.ts +137 -0
  263. package/src/runtime/handle-scope-async.ts +29 -0
  264. package/src/runtime/handle-types.ts +27 -0
  265. package/src/runtime/handle.ts +116 -0
  266. package/src/runtime/home-state.ts +55 -0
  267. package/src/runtime/index.ts +18 -0
  268. package/src/runtime/inform.ts +28 -0
  269. package/src/runtime/inject-budget-recap.ts +47 -0
  270. package/src/runtime/inject-budget.ts +81 -0
  271. package/src/runtime/inject-context.ts +85 -0
  272. package/src/runtime/inject-dedup-exclusive.ts +98 -0
  273. package/src/runtime/inject-dedup.ts +89 -0
  274. package/src/runtime/is-agent-tool.ts +19 -0
  275. package/src/runtime/lifecycle/agent-files.ts +49 -0
  276. package/src/runtime/lifecycle/agent-memory.ts +82 -0
  277. package/src/runtime/lifecycle/agent-transcript.ts +80 -0
  278. package/src/runtime/lifecycle/aipilot/analytics.ts +99 -0
  279. package/src/runtime/lifecycle/aipilot/apex-task-store.ts +61 -0
  280. package/src/runtime/lifecycle/aipilot/cache-base.ts +48 -0
  281. package/src/runtime/lifecycle/aipilot/cache-doc.ts +100 -0
  282. package/src/runtime/lifecycle/aipilot/cache-lessons.ts +58 -0
  283. package/src/runtime/lifecycle/aipilot/cache-test.ts +70 -0
  284. package/src/runtime/lifecycle/aipilot/curate-lessons.ts +64 -0
  285. package/src/runtime/lifecycle/aipilot/dispatch-aipilot.ts +100 -0
  286. package/src/runtime/lifecycle/aipilot/doc-cache-gate.ts +69 -0
  287. package/src/runtime/lifecycle/aipilot/inject-apex.ts +98 -0
  288. package/src/runtime/lifecycle/aipilot/inject-doc.ts +62 -0
  289. package/src/runtime/lifecycle/aipilot/inject-explore.ts +64 -0
  290. package/src/runtime/lifecycle/aipilot/inject-lessons.ts +61 -0
  291. package/src/runtime/lifecycle/aipilot/inject-test.ts +48 -0
  292. package/src/runtime/lifecycle/aipilot/lesson-archive.ts +60 -0
  293. package/src/runtime/lifecycle/aipilot/lesson-inject.ts +98 -0
  294. package/src/runtime/lifecycle/aipilot/lesson-parse.ts +74 -0
  295. package/src/runtime/lifecycle/aipilot/lessons.ts +72 -0
  296. package/src/runtime/lifecycle/aipilot/promote-global-lessons.ts +92 -0
  297. package/src/runtime/lifecycle/aipilot/solid-compliance.ts +69 -0
  298. package/src/runtime/lifecycle/aipilot/solid-notice.ts +47 -0
  299. package/src/runtime/lifecycle/aipilot/solid-transcript.ts +60 -0
  300. package/src/runtime/lifecycle/aipilot/source-scan.ts +56 -0
  301. package/src/runtime/lifecycle/aipilot/sync-task.ts +75 -0
  302. package/src/runtime/lifecycle/aipilot/transcript.ts +88 -0
  303. package/src/runtime/lifecycle/aipilot/types.ts +72 -0
  304. package/src/runtime/lifecycle/auto-document-reads.ts +73 -0
  305. package/src/runtime/lifecycle/cartographer/detect.ts +57 -0
  306. package/src/runtime/lifecycle/cartographer/ecosystem-map.ts +56 -0
  307. package/src/runtime/lifecycle/cartographer/fs-util.ts +64 -0
  308. package/src/runtime/lifecycle/cartographer/merge.ts +51 -0
  309. package/src/runtime/lifecycle/cartographer/project-map.ts +49 -0
  310. package/src/runtime/lifecycle/cartographer/scan-hooks.ts +48 -0
  311. package/src/runtime/lifecycle/cartographer/scan.ts +81 -0
  312. package/src/runtime/lifecycle/cartographer/session-start.ts +33 -0
  313. package/src/runtime/lifecycle/cartographer/track-enrichment.ts +45 -0
  314. package/src/runtime/lifecycle/cartographer/write-plugin-map.ts +43 -0
  315. package/src/runtime/lifecycle/cartographer/write-tree.ts +44 -0
  316. package/src/runtime/lifecycle/changelog-research.ts +43 -0
  317. package/src/runtime/lifecycle/check-file-size.ts +61 -0
  318. package/src/runtime/lifecycle/codex-resync/fingerprint.ts +63 -0
  319. package/src/runtime/lifecycle/codex-resync/lock.ts +46 -0
  320. package/src/runtime/lifecycle/codex-resync/managed-destination.ts +39 -0
  321. package/src/runtime/lifecycle/codex-resync/materialize-agents.ts +57 -0
  322. package/src/runtime/lifecycle/codex-resync/plugin-files.ts +65 -0
  323. package/src/runtime/lifecycle/codex-resync/plugin-roots.ts +62 -0
  324. package/src/runtime/lifecycle/codex-resync/resync.ts +45 -0
  325. package/src/runtime/lifecycle/codex-resync/symlink-commands.ts +25 -0
  326. package/src/runtime/lifecycle/dispatch.ts +109 -0
  327. package/src/runtime/lifecycle/failure-lesson.ts +51 -0
  328. package/src/runtime/lifecycle/index.ts +34 -0
  329. package/src/runtime/lifecycle/inject-rules.ts +50 -0
  330. package/src/runtime/lifecycle/instructions-loaded.ts +22 -0
  331. package/src/runtime/lifecycle/kimi-rules-native.ts +44 -0
  332. package/src/runtime/lifecycle/lessons/dispatch.ts +88 -0
  333. package/src/runtime/lifecycle/lessons/reminder.ts +89 -0
  334. package/src/runtime/lifecycle/lessons/state.ts +23 -0
  335. package/src/runtime/lifecycle/memory/agent-lesson.ts +35 -0
  336. package/src/runtime/lifecycle/memory/capture-error.ts +41 -0
  337. package/src/runtime/lifecycle/memory/client.ts +65 -0
  338. package/src/runtime/lifecycle/memory/dispatch.ts +42 -0
  339. package/src/runtime/lifecycle/memory/recall.ts +30 -0
  340. package/src/runtime/lifecycle/memory/salience.ts +31 -0
  341. package/src/runtime/lifecycle/memory/state.ts +49 -0
  342. package/src/runtime/lifecycle/memory/track-ops.ts +15 -0
  343. package/src/runtime/lifecycle/post-compact.ts +38 -0
  344. package/src/runtime/lifecycle/post-edit-ts.ts +49 -0
  345. package/src/runtime/lifecycle/post-tracking.ts +40 -0
  346. package/src/runtime/lifecycle/pre-compact.ts +38 -0
  347. package/src/runtime/lifecycle/rules-root.ts +83 -0
  348. package/src/runtime/lifecycle/security/check-skill.ts +63 -0
  349. package/src/runtime/lifecycle/security/scan-patterns.ts +53 -0
  350. package/src/runtime/lifecycle/security/scan.ts +76 -0
  351. package/src/runtime/lifecycle/security/skill-state.ts +47 -0
  352. package/src/runtime/lifecycle/security/track-mcp.ts +29 -0
  353. package/src/runtime/lifecycle/security/track-skill-read.ts +31 -0
  354. package/src/runtime/lifecycle/seo/post-tool-use.ts +45 -0
  355. package/src/runtime/lifecycle/session-end.ts +17 -0
  356. package/src/runtime/lifecycle/session-start.ts +57 -0
  357. package/src/runtime/lifecycle/snapshot/board.ts +27 -0
  358. package/src/runtime/lifecycle/snapshot/format.ts +60 -0
  359. package/src/runtime/lifecycle/snapshot/git.ts +71 -0
  360. package/src/runtime/lifecycle/snapshot/index.ts +52 -0
  361. package/src/runtime/lifecycle/snapshot/version.ts +34 -0
  362. package/src/runtime/lifecycle/solid-detect.ts +56 -0
  363. package/src/runtime/lifecycle/stop-core.ts +35 -0
  364. package/src/runtime/lifecycle/subagent-cache.ts +61 -0
  365. package/src/runtime/lifecycle/task-completed.ts +94 -0
  366. package/src/runtime/lifecycle/teammate-idle-check.ts +63 -0
  367. package/src/runtime/lifecycle/teammate-idle.ts +28 -0
  368. package/src/runtime/lifecycle/tool-failure.ts +24 -0
  369. package/src/runtime/lifecycle/track-changes.ts +61 -0
  370. package/src/runtime/lifecycle/validate-solid.ts +70 -0
  371. package/src/runtime/lifecycle/validate-tailwind.ts +80 -0
  372. package/src/runtime/lifecycle-bridge.ts +74 -0
  373. package/src/runtime/mcp-key.ts +44 -0
  374. package/src/runtime/mcp-tool-name.ts +92 -0
  375. package/src/runtime/mcp.ts +91 -0
  376. package/src/runtime/modular.ts +77 -0
  377. package/src/runtime/normalize.ts +107 -0
  378. package/src/runtime/notices.ts +91 -0
  379. package/src/runtime/notification-sound.ts +49 -0
  380. package/src/runtime/notifications.ts +77 -0
  381. package/src/runtime/paths.ts +59 -0
  382. package/src/runtime/post-fanout.ts +41 -0
  383. package/src/runtime/post-outcome.ts +61 -0
  384. package/src/runtime/pre-allow.ts +97 -0
  385. package/src/runtime/precommit.ts +60 -0
  386. package/src/runtime/prompt-text.ts +38 -0
  387. package/src/runtime/receipt-capture.ts +34 -0
  388. package/src/runtime/record.ts +26 -0
  389. package/src/runtime/respond.ts +92 -0
  390. package/src/runtime/solid-file-size-gate.ts +58 -0
  391. package/src/runtime/solid-pre.ts +53 -0
  392. package/src/runtime/storage.ts +9 -0
  393. package/src/statusline/colors.ts +31 -0
  394. package/src/statusline/constants.ts +17 -0
  395. package/src/statusline/formatters.ts +54 -0
  396. package/src/statusline/index.ts +4 -0
  397. package/src/statusline/progress-bar.ts +46 -0
  398. package/src/tracking/codex-post-failure.ts +73 -0
  399. package/src/tracking/index.ts +2 -0
  400. package/src/tracking/integrity.ts +99 -0
  401. package/src/tracking/one-shot-dedup.ts +34 -0
  402. package/src/tracking/one-shot-failure.ts +42 -0
  403. package/src/tracking/one-shot-store.ts +95 -0
  404. package/src/tracking/one-shot.ts +93 -0
  405. package/src/tracking/receipts.ts +95 -0
  406. package/src/tracking/session-state.ts +94 -0
  407. package/src/tracking/store.ts +96 -0
  408. package/src/tracking/track-compact.ts +100 -0
  409. package/src/tracking/track-diff.ts +50 -0
  410. package/src/tracking/track-journal.ts +97 -0
  411. package/src/tracking/track-lock-sync.ts +83 -0
  412. package/src/tracking/track-lock.ts +67 -0
  413. package/src/util/compact-json.ts +23 -0
  414. package/src/util/index.ts +2 -0
  415. package/src/util/json-io.ts +47 -0
  416. package/src/util/project-root.ts +41 -0
  417. package/src/util/runtime-io.ts +85 -0
  418. package/src/util/semver.ts +30 -0
  419. package/dist/permission-mode-B0MUl7FT.mjs +0 -136
package/dist/cli/bin.mjs CHANGED
@@ -3,9 +3,10 @@ import { o as resolveStdinMaxBytes } from "../limits-DG5pl-5s.mjs";
3
3
  import { c as resolveTtlSec, r as loadDotenv } from "../dotenv-BLBkBTww.mjs";
4
4
  import { t as detectHarness } from "../harness-BMuLJ9lm.mjs";
5
5
  import { t as claudeHome } from "../home-state-oUGFB4ds.mjs";
6
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CdIlUtjv.mjs";
7
- import { n as writeInitFile, t as initFor } from "../run-TAXNRSpD.mjs";
8
- import { $ as runningVersion, Q as runDoctor, Z as notify, et as versionBanner, i as respond, t as handleHook, zt as todayUtc } from "../handle-DHhukRdh.mjs";
6
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-DkrzC0gb.mjs";
7
+ import { n as writeInitFile, t as initFor } from "../run-GHAMqcOn.mjs";
8
+ import { $ as runDoctor, Bt as todayUtc, Q as notify, et as runningVersion, i as respond, t as handleHook, tt as versionBanner } from "../handle-C43gA-Pr.mjs";
9
+ import { r as cursorEventContract } from "../normalize-BjG6unTj.mjs";
9
10
  import { delimiter, join } from "node:path";
10
11
  import { existsSync, mkdirSync, readFileSync, readSync, readdirSync, writeFileSync } from "node:fs";
11
12
  import { homedir } from "node:os";
@@ -999,6 +1000,386 @@ function parseScope(scopeArg, err = (m) => process.stderr.write(m)) {
999
1000
  return scopeArg !== void 0 && VALID_SCOPES.has(scopeArg) ? scopeArg : "core";
1000
1001
  }
1001
1002
  //#endregion
1003
+ //#region src/cli/json-primitive-scanner.ts
1004
+ /** Validate one JSON literal or number incrementally with constant state. */
1005
+ var JsonPrimitiveScanner = class {
1006
+ literal;
1007
+ literalIndex = 0;
1008
+ number;
1009
+ valid = true;
1010
+ constructor(firstByte) {
1011
+ if (firstByte === 116) {
1012
+ this.literal = "true";
1013
+ this.literalIndex = 1;
1014
+ } else if (firstByte === 102) {
1015
+ this.literal = "false";
1016
+ this.literalIndex = 1;
1017
+ } else if (firstByte === 110) {
1018
+ this.literal = "null";
1019
+ this.literalIndex = 1;
1020
+ } else if (firstByte === 45) this.number = "minus";
1021
+ else if (firstByte === 48) this.number = "zero";
1022
+ else if (isOneToNine(firstByte)) this.number = "integer";
1023
+ else this.valid = false;
1024
+ }
1025
+ /** Consume one non-delimiter byte and report whether the prefix stays valid. */
1026
+ write(byte) {
1027
+ if (!this.valid) return false;
1028
+ if (this.literal) {
1029
+ this.valid = this.literal.charCodeAt(this.literalIndex) === byte;
1030
+ this.literalIndex += 1;
1031
+ return this.valid && this.literalIndex <= this.literal.length;
1032
+ }
1033
+ this.valid = this.writeNumber(byte);
1034
+ return this.valid;
1035
+ }
1036
+ /** Return whether the accumulated primitive is complete JSON grammar. */
1037
+ finish() {
1038
+ if (!this.valid) return false;
1039
+ if (this.literal) return this.literalIndex === this.literal.length;
1040
+ return this.number === "zero" || this.number === "integer" || this.number === "fraction" || this.number === "exponent";
1041
+ }
1042
+ writeNumber(byte) {
1043
+ if (this.number === "minus") return this.digitAfter(byte, "zero", "integer");
1044
+ if (this.number === "zero") return this.afterInteger(byte, false);
1045
+ if (this.number === "integer") {
1046
+ if (isDigit(byte)) return true;
1047
+ return this.afterInteger(byte, true);
1048
+ }
1049
+ if (this.number === "dot") {
1050
+ if (!isDigit(byte)) return false;
1051
+ this.number = "fraction";
1052
+ return true;
1053
+ }
1054
+ if (this.number === "fraction") {
1055
+ if (isDigit(byte)) return true;
1056
+ return this.startExponent(byte);
1057
+ }
1058
+ if (this.number === "exponentMark") {
1059
+ if (byte === 43 || byte === 45) {
1060
+ this.number = "exponentSign";
1061
+ return true;
1062
+ }
1063
+ return this.digitAfter(byte, "exponent", "exponent");
1064
+ }
1065
+ if (this.number === "exponentSign") return this.digitAfter(byte, "exponent", "exponent");
1066
+ return this.number === "exponent" && isDigit(byte);
1067
+ }
1068
+ afterInteger(byte, digitAllowed) {
1069
+ if (digitAllowed && isDigit(byte)) return true;
1070
+ if (byte === 46) {
1071
+ this.number = "dot";
1072
+ return true;
1073
+ }
1074
+ return this.startExponent(byte);
1075
+ }
1076
+ startExponent(byte) {
1077
+ if (byte !== 101 && byte !== 69) return false;
1078
+ this.number = "exponentMark";
1079
+ return true;
1080
+ }
1081
+ digitAfter(byte, zero, nonzero) {
1082
+ if (byte === 48) {
1083
+ this.number = zero;
1084
+ return true;
1085
+ }
1086
+ if (isOneToNine(byte)) {
1087
+ this.number = nonzero;
1088
+ return true;
1089
+ }
1090
+ return false;
1091
+ }
1092
+ };
1093
+ function isDigit(byte) {
1094
+ return byte >= 48 && byte <= 57;
1095
+ }
1096
+ function isOneToNine(byte) {
1097
+ return byte >= 49 && byte <= 57;
1098
+ }
1099
+ //#endregion
1100
+ //#region src/cli/cursor-event-scanner.ts
1101
+ /**
1102
+ * Fixed cardinality bounds used by the incremental Cursor JSON scanner.
1103
+ * `maxDepth` counts simultaneously open containers. Deeper valid JSON remains
1104
+ * indeterminate and the oversized Cursor path fails closed.
1105
+ */
1106
+ const CURSOR_SCANNER_LIMITS = {
1107
+ tokenEntries: 256,
1108
+ maxDepth: 1024
1109
+ };
1110
+ /** Incrementally validates JSON and extracts the last top-level Cursor event name. */
1111
+ var CursorEventScanner = class {
1112
+ frames = [];
1113
+ mode = "normal";
1114
+ token = [];
1115
+ tokenOverflow = false;
1116
+ primitive;
1117
+ escaped = false;
1118
+ unicode = 0;
1119
+ rootStarted = false;
1120
+ rootComplete = false;
1121
+ invalid = false;
1122
+ event;
1123
+ /** Consume another raw JSON byte chunk without retaining the payload. */
1124
+ write(chunk) {
1125
+ for (const byte of chunk) this.consume(byte);
1126
+ }
1127
+ /** Return the event only when the complete stream is valid JSON. */
1128
+ finish() {
1129
+ if (this.mode === "primitive") this.endPrimitive();
1130
+ if (this.mode !== "normal" || this.frames.length > 0 || !this.rootComplete) this.invalid = true;
1131
+ return this.invalid ? void 0 : this.event;
1132
+ }
1133
+ consume(byte) {
1134
+ if (this.invalid) return;
1135
+ if (this.mode === "string") {
1136
+ this.stringByte(byte);
1137
+ return;
1138
+ }
1139
+ if (this.mode === "primitive") {
1140
+ if (!isDelimiter(byte)) {
1141
+ if (!this.primitive?.write(byte)) this.invalid = true;
1142
+ return;
1143
+ }
1144
+ this.endPrimitive();
1145
+ if (this.invalid) return;
1146
+ }
1147
+ if (isWhitespace(byte)) return;
1148
+ if (byte === 34) {
1149
+ this.startString();
1150
+ return;
1151
+ }
1152
+ if (byte === 123 || byte === 91) {
1153
+ this.startContainer(byte === 123 ? "object" : "array");
1154
+ return;
1155
+ }
1156
+ if (byte === 125 || byte === 93) {
1157
+ this.endContainer(byte === 125 ? "object" : "array");
1158
+ return;
1159
+ }
1160
+ if (byte === 58) {
1161
+ this.colon();
1162
+ return;
1163
+ }
1164
+ if (byte === 44) {
1165
+ this.comma();
1166
+ return;
1167
+ }
1168
+ if (isPrimitiveStart(byte)) {
1169
+ this.startPrimitive(byte);
1170
+ return;
1171
+ }
1172
+ this.invalid = true;
1173
+ }
1174
+ startString() {
1175
+ this.mode = "string";
1176
+ this.token = [34];
1177
+ this.tokenOverflow = false;
1178
+ this.escaped = false;
1179
+ this.unicode = 0;
1180
+ }
1181
+ startPrimitive(byte) {
1182
+ this.mode = "primitive";
1183
+ this.primitive = new JsonPrimitiveScanner(byte);
1184
+ }
1185
+ stringByte(byte) {
1186
+ this.pushToken(byte);
1187
+ if (this.unicode > 0) {
1188
+ if (!isHex(byte)) {
1189
+ this.invalid = true;
1190
+ return;
1191
+ }
1192
+ this.unicode -= 1;
1193
+ return;
1194
+ }
1195
+ if (this.escaped) {
1196
+ if (byte === 117) this.unicode = 4;
1197
+ else if (![
1198
+ 34,
1199
+ 92,
1200
+ 47,
1201
+ 98,
1202
+ 102,
1203
+ 110,
1204
+ 114,
1205
+ 116
1206
+ ].includes(byte)) this.invalid = true;
1207
+ this.escaped = false;
1208
+ return;
1209
+ }
1210
+ if (byte === 92) {
1211
+ this.escaped = true;
1212
+ return;
1213
+ }
1214
+ if (byte < 32) {
1215
+ this.invalid = true;
1216
+ return;
1217
+ }
1218
+ if (byte !== 34) return;
1219
+ this.mode = "normal";
1220
+ const value = this.tokenOverflow ? void 0 : decodeString(this.token);
1221
+ if (value === null) {
1222
+ this.invalid = true;
1223
+ return;
1224
+ }
1225
+ this.acceptString(value);
1226
+ }
1227
+ acceptString(value) {
1228
+ const frame = this.frames.at(-1);
1229
+ if (frame?.kind === "object" && (frame.state === "key" || frame.state === "keyOrEnd")) {
1230
+ frame.key = value;
1231
+ frame.state = "colon";
1232
+ return;
1233
+ }
1234
+ this.acceptValue("string", value);
1235
+ }
1236
+ startContainer(kind) {
1237
+ this.acceptValue(kind);
1238
+ if (this.invalid) return;
1239
+ if (this.frames.length >= CURSOR_SCANNER_LIMITS.maxDepth) {
1240
+ this.invalid = true;
1241
+ return;
1242
+ }
1243
+ this.frames.push(kind === "object" ? {
1244
+ kind,
1245
+ state: "keyOrEnd"
1246
+ } : {
1247
+ kind,
1248
+ state: "valueOrEnd"
1249
+ });
1250
+ }
1251
+ endContainer(kind) {
1252
+ const frame = this.frames.at(-1);
1253
+ if (!(frame?.kind === kind && (kind === "object" ? frame.state === "keyOrEnd" || frame.state === "commaOrEnd" : frame.state === "valueOrEnd" || frame.state === "commaOrEnd"))) {
1254
+ this.invalid = true;
1255
+ return;
1256
+ }
1257
+ this.frames.pop();
1258
+ if (this.frames.length === 0) this.rootComplete = true;
1259
+ }
1260
+ acceptValue(kind, value) {
1261
+ if (this.rootComplete) {
1262
+ this.invalid = true;
1263
+ return;
1264
+ }
1265
+ const frame = this.frames.at(-1);
1266
+ if (!frame) {
1267
+ if (this.rootStarted) {
1268
+ this.invalid = true;
1269
+ return;
1270
+ }
1271
+ this.rootStarted = true;
1272
+ if (kind === "string" || kind === "primitive") this.rootComplete = true;
1273
+ return;
1274
+ }
1275
+ if (!(frame.kind === "object" ? frame.state === "value" : frame.state === "value" || frame.state === "valueOrEnd")) {
1276
+ this.invalid = true;
1277
+ return;
1278
+ }
1279
+ if (frame.kind === "object") {
1280
+ if (this.frames.length === 1 && frame.key === "hook_event_name") this.event = kind === "string" ? value : void 0;
1281
+ frame.key = void 0;
1282
+ }
1283
+ frame.state = "commaOrEnd";
1284
+ }
1285
+ colon() {
1286
+ const frame = this.frames.at(-1);
1287
+ if (frame?.kind !== "object" || frame.state !== "colon") {
1288
+ this.invalid = true;
1289
+ return;
1290
+ }
1291
+ frame.state = "value";
1292
+ }
1293
+ comma() {
1294
+ const frame = this.frames.at(-1);
1295
+ if (!frame || frame.state !== "commaOrEnd") {
1296
+ this.invalid = true;
1297
+ return;
1298
+ }
1299
+ frame.state = frame.kind === "object" ? "key" : "value";
1300
+ }
1301
+ endPrimitive() {
1302
+ const valid = this.primitive?.finish() === true;
1303
+ this.mode = "normal";
1304
+ this.primitive = void 0;
1305
+ if (valid) this.acceptValue("primitive");
1306
+ else this.invalid = true;
1307
+ }
1308
+ pushToken(byte) {
1309
+ if (this.token.length < CURSOR_SCANNER_LIMITS.tokenEntries) this.token.push(byte);
1310
+ else this.tokenOverflow = true;
1311
+ }
1312
+ };
1313
+ function decodeString(bytes) {
1314
+ try {
1315
+ const value = JSON.parse(Buffer.from(bytes).toString("utf8"));
1316
+ return typeof value === "string" ? value : null;
1317
+ } catch {
1318
+ return null;
1319
+ }
1320
+ }
1321
+ function isWhitespace(byte) {
1322
+ return byte === 32 || byte === 9 || byte === 10 || byte === 13;
1323
+ }
1324
+ function isDelimiter(byte) {
1325
+ return isWhitespace(byte) || [
1326
+ 44,
1327
+ 93,
1328
+ 125
1329
+ ].includes(byte);
1330
+ }
1331
+ function isPrimitiveStart(byte) {
1332
+ return byte === 45 || byte === 116 || byte === 102 || byte === 110 || byte >= 48 && byte <= 57;
1333
+ }
1334
+ function isHex(byte) {
1335
+ return byte >= 48 && byte <= 57 || byte >= 65 && byte <= 70 || byte >= 97 && byte <= 102;
1336
+ }
1337
+ //#endregion
1338
+ //#region src/cli/cursor-stdin-reader.ts
1339
+ const HEAD_BYTES$1 = 4096;
1340
+ const CHUNK_BYTES = 64 * 1024;
1341
+ /**
1342
+ * Read Cursor stdin through EOF for valid top-level event classification.
1343
+ * Cursor's host-configured execution timeout bounds an idle open pipe.
1344
+ */
1345
+ function readCursorBounded(fd, maxBytes) {
1346
+ const chunk = Buffer.alloc(CHUNK_BYTES);
1347
+ const head = Buffer.alloc(HEAD_BYTES$1);
1348
+ const retained = Buffer.alloc(maxBytes);
1349
+ const scanner = new CursorEventScanner();
1350
+ let headLength = 0;
1351
+ let retainedLength = 0;
1352
+ let total = 0;
1353
+ let oversize = false;
1354
+ for (;;) {
1355
+ const length = readSync(fd, chunk, 0, CHUNK_BYTES, null);
1356
+ if (length === 0) break;
1357
+ const view = chunk.subarray(0, length);
1358
+ scanner.write(view);
1359
+ total += length;
1360
+ if (headLength < HEAD_BYTES$1) {
1361
+ const copied = Math.min(length, HEAD_BYTES$1 - headLength);
1362
+ view.copy(head, headLength, 0, copied);
1363
+ headLength += copied;
1364
+ }
1365
+ if (!oversize) {
1366
+ const copied = Math.min(length, Math.max(0, maxBytes - retainedLength));
1367
+ if (copied > 0) view.copy(retained, retainedLength, 0, copied);
1368
+ retainedLength += copied;
1369
+ if (total > maxBytes) oversize = true;
1370
+ }
1371
+ }
1372
+ if (!oversize) return {
1373
+ kind: "ok",
1374
+ text: retained.subarray(0, total).toString("utf8")
1375
+ };
1376
+ const event = scanner.finish();
1377
+ return {
1378
+ kind: "oversize",
1379
+ head: event ? JSON.stringify({ hook_event_name: event }) : head.subarray(0, headLength).toString("utf8")
1380
+ };
1381
+ }
1382
+ //#endregion
1002
1383
  //#region src/cli/hook-io.ts
1003
1384
  /**
1004
1385
  * Hook stdin reading + debug tracing for `harness hook` — extracted from
@@ -1006,22 +1387,34 @@ function parseScope(scopeArg, err = (m) => process.stderr.write(m)) {
1006
1387
  * Tracing is stderr-only and active only when FUSE_HARNESS_DEBUG=1 AND
1007
1388
  * CI=true (both set by test/sim/exec.ts; never in an interactive session).
1008
1389
  *
1009
- * Stdin is read BOUNDED (`resolveStdinMaxBytes`, default 16 MiB): the reader
1010
- * never buffers past the cap, so an oversized payload cannot exhaust memory
1011
- * nor slip an uninspected tool call through (fail-closed see `bin.ts`).
1390
+ * `resolveStdinMaxBytes` (default 16 MiB) caps retained payload content.
1391
+ * The legacy reader may also retain its overflow chunk; Cursor additionally
1392
+ * requests fixed scanner/chunk buffers while reading to EOF. Buffer alias views,
1393
+ * JS objects/strings, and RSS are runtime-dependent, so this is not a physical
1394
+ * memory guarantee. Unclassified oversized Cursor input fails closed.
1012
1395
  */
1013
1396
  const hookDebug = process.env.FUSE_HARNESS_DEBUG === "1" && process.env.CI === "true";
1014
1397
  /** stderr-only trace, no-op outside the debug flag combination above. */
1015
1398
  function traceHook(label, data) {
1016
1399
  if (hookDebug) process.stderr.write(`[hook-debug] ${label}: ${typeof data === "string" ? data : JSON.stringify(data)}\n`);
1017
1400
  }
1401
+ const MALFORMED_STDIN = Symbol("cursor-malformed-stdin");
1018
1402
  /** Type guard for the oversize variant (narrows the readStdin union). */
1019
1403
  function isOversize(x) {
1020
1404
  return typeof x === "object" && x !== null && x.kind === "oversize";
1021
1405
  }
1022
- /** First 4 KiB are kept on oversize for event-name sniffing downstream. */
1406
+ /** Identify Cursor JSON parse failures without accepting a forgeable payload field. */
1407
+ function isMalformedCursorStdin(x) {
1408
+ return typeof x === "object" && x !== null && MALFORMED_STDIN in x;
1409
+ }
1410
+ /** First 4 KiB are the fallback diagnostic probe when no event key is found. */
1023
1411
  const HEAD_BYTES = 4096;
1024
1412
  const CHUNK = 64 * 1024;
1413
+ const CURSOR_MAX_STDIN_BYTES = 64 * 1024 * 1024;
1414
+ /** Resolve and clamp Cursor's stdin cap while preserving other harness limits. */
1415
+ function resolveCursorStdinMaxBytes(env = process.env) {
1416
+ return Math.min(CURSOR_MAX_STDIN_BYTES, resolveStdinMaxBytes(env));
1417
+ }
1025
1418
  /**
1026
1419
  * Read a file descriptor to EOF, bounded at `maxBytes` (+1 byte to detect
1027
1420
  * the overflow). Injectable fd so tests never touch process stdin.
@@ -1048,9 +1441,10 @@ function readBounded(fd, maxBytes) {
1048
1441
  text: Buffer.concat(parts).toString("utf8")
1049
1442
  };
1050
1443
  }
1051
- /** Read the hook payload from stdin; `{}` on empty or invalid JSON (fail-open parity). */
1052
- async function readStdin() {
1053
- const read = readBounded(0, resolveStdinMaxBytes());
1444
+ /** Read hook stdin; Cursor distinguishes malformed non-empty JSON from historical empty input. */
1445
+ async function readStdin(id) {
1446
+ const cap = id === "cursor" ? resolveCursorStdinMaxBytes() : resolveStdinMaxBytes();
1447
+ const read = id === "cursor" ? readCursorBounded(0, cap) : readBounded(0, cap);
1054
1448
  if (read.kind === "oversize") return read;
1055
1449
  const text = read.text.trim();
1056
1450
  if (!text) return {};
@@ -1059,7 +1453,7 @@ async function readStdin() {
1059
1453
  return typeof parsed === "object" && parsed !== null ? parsed : {};
1060
1454
  } catch (e) {
1061
1455
  traceHook("stdin-parse-error", e instanceof Error ? e.message : String(e));
1062
- return {};
1456
+ return id === "cursor" ? { [MALFORMED_STDIN]: true } : {};
1063
1457
  }
1064
1458
  }
1065
1459
  /** Blockable hook events (fail-closed on oversize); others are observation-only. */
@@ -1076,13 +1470,31 @@ const BLOCKABLE = /* @__PURE__ */ new Set([
1076
1470
  * @param head - The first bytes of the payload (event-name sniffing).
1077
1471
  */
1078
1472
  function oversizeStdout(id, head) {
1079
- const event = /"hook_event_name"\s*:\s*"([^"]+)"/.exec(head)?.[1] ?? "";
1080
- if (event && !BLOCKABLE.has(event)) return "";
1473
+ const event = id === "cursor" ? probeEvent(head) : legacyProbeEvent(head);
1474
+ const maxBytes = id === "cursor" ? resolveCursorStdinMaxBytes() : resolveStdinMaxBytes();
1475
+ if (id === "cursor" && event) {
1476
+ const contract = cursorEventContract(event);
1477
+ if (!contract.known || !contract.blockable) return "{}";
1478
+ }
1479
+ if (id !== "cursor" && event && !BLOCKABLE.has(event)) return "";
1081
1480
  return respond(id, {
1082
1481
  kind: "block",
1083
1482
  title: "Oversize hook payload",
1084
- reason: `stdin payload exceeds ${resolveStdinMaxBytes()} bytes — denied uninspected`
1085
- });
1483
+ reason: `stdin payload exceeds ${maxBytes} bytes — denied uninspected`
1484
+ }, id === "cursor" ? event || "preToolUse" : "PreToolUse");
1485
+ }
1486
+ function legacyProbeEvent(head) {
1487
+ return /"hook_event_name"\s*:\s*"([^"]+)"/.exec(head)?.[1] ?? "";
1488
+ }
1489
+ function probeEvent(head) {
1490
+ try {
1491
+ const parsed = JSON.parse(head);
1492
+ if (typeof parsed !== "object" || parsed === null) return "";
1493
+ const event = parsed.hook_event_name;
1494
+ return typeof event === "string" ? event : "";
1495
+ } catch {
1496
+ return "";
1497
+ }
1086
1498
  }
1087
1499
  //#endregion
1088
1500
  //#region src/cli/hook-sound.ts
@@ -1166,12 +1578,13 @@ if (cmd === "--version" || cmd === "-v") {
1166
1578
  });
1167
1579
  let outcome;
1168
1580
  try {
1169
- const stdin = await readStdin();
1581
+ const stdin = await readStdin(id);
1170
1582
  if (isOversize(stdin)) {
1171
1583
  const stdout = oversizeStdout(id, stdin.head);
1172
1584
  if (stdout) process.stdout.write(stdout);
1173
1585
  process.exit(0);
1174
1586
  }
1587
+ if (isMalformedCursorStdin(stdin)) process.exit(1);
1175
1588
  outcome = await handleHook(id, stdin, {
1176
1589
  now: Date.now(),
1177
1590
  cwd: process.cwd(),
@@ -1,2 +1,2 @@
1
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CdIlUtjv.mjs";
1
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-DkrzC0gb.mjs";
2
2
  export { checkStaged, stagedContent, stagedFiles };
@@ -0,0 +1,42 @@
1
+ //#region src/runtime/command-string.ts
2
+ /** Shell basenames whose `-c`-style argv carries the real script in argv[2]. */
3
+ const SHELLS = /* @__PURE__ */ new Set([
4
+ "bash",
5
+ "sh",
6
+ "zsh",
7
+ "dash"
8
+ ]);
9
+ /** True when `arg` is (a path to) a POSIX shell we know wraps a `-c` script. */
10
+ function isShell(arg) {
11
+ if (arg === void 0) return false;
12
+ const base = arg.slice(arg.lastIndexOf("/") + 1);
13
+ return SHELLS.has(base);
14
+ }
15
+ /** True for a shell command flag (`-c`, `-lc`, `-ic`, …) — anything ending in `c`. */
16
+ function isCommandFlag(arg) {
17
+ return arg !== void 0 && /^-[a-z]*c$/.test(arg);
18
+ }
19
+ /**
20
+ * Coerce a hook payload's `command` field to the shell string the guard chain
21
+ * expects. Harnesses disagree on the wire shape: Claude Code, Cursor, and Hermes
22
+ * send a plain string, but Codex CLI sends an argv ARRAY
23
+ * (`["bash", "-lc", "git commit -m x"]`). A naive `typeof === "string"` check
24
+ * dropped the array to `undefined`, blinding every `ctx.command` guard
25
+ * (destructive-git, mutators, install…) into a silent fail-open. This restores
26
+ * the script so the array and string payloads reach an identical verdict.
27
+ *
28
+ * @param v - Raw `command` value off the payload (string, argv array, or other).
29
+ * @returns A string as-is; a `[shell, -c|-lc, script]` argv reduced to its
30
+ * script; any other all-string array joined with spaces; and `undefined` for
31
+ * empty arrays, arrays holding non-strings, or any other type.
32
+ */
33
+ function commandToString(v) {
34
+ if (typeof v === "string") return v;
35
+ if (!Array.isArray(v)) return void 0;
36
+ if (v.length === 0 || !v.every((e) => typeof e === "string")) return void 0;
37
+ const argv = v;
38
+ if (argv.length >= 3 && isShell(argv[0]) && isCommandFlag(argv[1])) return argv[2];
39
+ return argv.join(" ");
40
+ }
41
+ //#endregion
42
+ export { commandToString as t };