@fusengine/harness 0.1.90 → 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 (417) 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 +3 -2
  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-CBaOcFZq.mjs → handle-C43gA-Pr.mjs} +701 -134
  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/policy/index.d.mts +1 -1
  29. package/dist/policy/index.mjs +2 -2
  30. package/dist/prompt/index.d.mts +1 -1
  31. package/dist/{run-CdIlUtjv.mjs → run-DkrzC0gb.mjs} +1 -1
  32. package/dist/{run-TAXNRSpD.mjs → run-GHAMqcOn.mjs} +26 -3
  33. package/dist/runtime/index.d.mts +27 -16
  34. package/dist/runtime/index.mjs +2 -2
  35. package/dist/{types-C0-igRKr.d.mts → types-Bh0jEF3_.d.mts} +2 -0
  36. package/dist/{validate-DZFtAbLP.mjs → validate-KjZ1X9tH.mjs} +1 -1
  37. package/package.json +3 -2
  38. package/src/adapters/claude/index.ts +92 -0
  39. package/src/adapters/cline/index.ts +36 -0
  40. package/src/adapters/codex/apply-patch.ts +94 -0
  41. package/src/adapters/codex/index.ts +84 -0
  42. package/src/adapters/codex/permission-mode.ts +16 -0
  43. package/src/adapters/cursor/context.ts +46 -0
  44. package/src/adapters/cursor/events.ts +38 -0
  45. package/src/adapters/cursor/index.ts +43 -0
  46. package/src/adapters/cursor/interfaces/types.ts +88 -0
  47. package/src/adapters/cursor/native-response.ts +158 -0
  48. package/src/adapters/cursor/normalize.ts +123 -0
  49. package/src/adapters/cursor/respond.ts +123 -0
  50. package/src/adapters/gemini/index.ts +36 -0
  51. package/src/adapters/hermes/index.ts +55 -0
  52. package/src/adapters/hermes/interfaces/types.ts +26 -0
  53. package/src/adapters/kimi/index.ts +96 -0
  54. package/src/adapters/kimi/interfaces/types.ts +55 -0
  55. package/src/cache/compact.ts +55 -0
  56. package/src/cache/index.ts +5 -0
  57. package/src/cache/io.ts +38 -0
  58. package/src/cache/mcp-response.ts +39 -0
  59. package/src/cache/mcp-store.ts +70 -0
  60. package/src/cache/store.ts +93 -0
  61. package/src/changelog/fetch.ts +79 -0
  62. package/src/cli/bin.ts +100 -0
  63. package/src/cli/cursor-event-scanner.ts +175 -0
  64. package/src/cli/cursor-stdin-reader.ts +65 -0
  65. package/src/cli/doctor.ts +96 -0
  66. package/src/cli/hook-io.ts +130 -0
  67. package/src/cli/hook-sound.ts +49 -0
  68. package/src/cli/index.ts +1 -0
  69. package/src/cli/json-primitive-scanner.ts +83 -0
  70. package/src/cli/run.ts +36 -0
  71. package/src/cli/scope.ts +31 -0
  72. package/src/codex-rules/build.ts +63 -0
  73. package/src/codex-rules/index.ts +8 -0
  74. package/src/codex-rules/mapping.ts +42 -0
  75. package/src/codex-rules/rules/absolute-paths.ts +52 -0
  76. package/src/codex-rules/rules/ask.ts +44 -0
  77. package/src/codex-rules/rules/chmod-ask.ts +57 -0
  78. package/src/codex-rules/rules/dd.ts +23 -0
  79. package/src/codex-rules/rules/diskutil.ts +33 -0
  80. package/src/codex-rules/rules/mkfs.ts +42 -0
  81. package/src/codex-rules/rules/privilege.ts +49 -0
  82. package/src/codex-rules/rules/remote-fetch.ts +31 -0
  83. package/src/codex-rules/rules/rm-variants.ts +58 -0
  84. package/src/codex-rules/rules/single-commands.ts +57 -0
  85. package/src/codex-rules/skip-list.ts +25 -0
  86. package/src/codex-rules/starlark.ts +46 -0
  87. package/src/codex-rules/types.ts +36 -0
  88. package/src/config/dotenv.ts +55 -0
  89. package/src/config/env.ts +10 -0
  90. package/src/config/home-dir.ts +36 -0
  91. package/src/config/index.ts +5 -0
  92. package/src/config/layout.ts +52 -0
  93. package/src/config/limits.ts +56 -0
  94. package/src/config/ttl.ts +30 -0
  95. package/src/detect/harness.ts +73 -0
  96. package/src/detect/index.ts +1 -0
  97. package/src/detect/interfaces/types.ts +18 -0
  98. package/src/freshness/agent-evidence-record.ts +95 -0
  99. package/src/freshness/agent-evidence.ts +95 -0
  100. package/src/freshness/codex-spawn-evidence.ts +91 -0
  101. package/src/freshness/doc-helpers.ts +90 -0
  102. package/src/freshness/evidence-harvest-io.ts +72 -0
  103. package/src/freshness/evidence-harvest.ts +61 -0
  104. package/src/freshness/explore-tools.ts +95 -0
  105. package/src/freshness/index.ts +2 -0
  106. package/src/freshness/query-framework.ts +73 -0
  107. package/src/freshness/ref-evidence.ts +49 -0
  108. package/src/freshness/ref-journal.ts +98 -0
  109. package/src/freshness/trivial-edit-counter.ts +30 -0
  110. package/src/index.ts +11 -0
  111. package/src/init/index.ts +2 -0
  112. package/src/init/run.ts +32 -0
  113. package/src/init/templates.ts +75 -0
  114. package/src/memory/gitignore.ts +14 -0
  115. package/src/memory/index.ts +3 -0
  116. package/src/memory/registry.ts +39 -0
  117. package/src/memory/session-roots.ts +99 -0
  118. package/src/memory/state.ts +58 -0
  119. package/src/policy/apex-authorization.ts +100 -0
  120. package/src/policy/apex-gates.ts +91 -0
  121. package/src/policy/apex-target-steps.ts +73 -0
  122. package/src/policy/apex-target.ts +49 -0
  123. package/src/policy/apex-task-context.ts +81 -0
  124. package/src/policy/apex.ts +94 -0
  125. package/src/policy/cartographer/build-tree.ts +69 -0
  126. package/src/policy/cartographer/describe.ts +53 -0
  127. package/src/policy/cartographer/entry.ts +38 -0
  128. package/src/policy/cartographer/frontmatter.ts +48 -0
  129. package/src/policy/cartographer/indicators.ts +34 -0
  130. package/src/policy/claude-md-context.ts +66 -0
  131. package/src/policy/conventions/index.ts +11 -0
  132. package/src/policy/conventions/interfaces.ts +71 -0
  133. package/src/policy/conventions/langs.ts +53 -0
  134. package/src/policy/conventions/query.ts +49 -0
  135. package/src/policy/conventions/react-hooks.ts +18 -0
  136. package/src/policy/conventions/store-or-query.ts +21 -0
  137. package/src/policy/conventions/stores.ts +56 -0
  138. package/src/policy/conventions/strip.ts +87 -0
  139. package/src/policy/conventions/verdict.ts +38 -0
  140. package/src/policy/creation-intent.ts +11 -0
  141. package/src/policy/deny-loop.ts +88 -0
  142. package/src/policy/design/allowed-write.ts +28 -0
  143. package/src/policy/design/content-checks.ts +45 -0
  144. package/src/policy/design/corpus-fs.ts +21 -0
  145. package/src/policy/design/corpus-resolve-cache.ts +49 -0
  146. package/src/policy/design/corpus-resolve.ts +99 -0
  147. package/src/policy/design/corpus.ts +92 -0
  148. package/src/policy/design/design-system-rules.ts +45 -0
  149. package/src/policy/design/flag.ts +30 -0
  150. package/src/policy/design/gates-pipeline.ts +105 -0
  151. package/src/policy/design/gates.ts +87 -0
  152. package/src/policy/design/screenshot-tools.ts +24 -0
  153. package/src/policy/design/skill-evidence.ts +34 -0
  154. package/src/policy/design/skill-gate.ts +81 -0
  155. package/src/policy/design/skill-triggers.ts +51 -0
  156. package/src/policy/design/state.ts +92 -0
  157. package/src/policy/design/template-urls.ts +54 -0
  158. package/src/policy/design/transitions.ts +68 -0
  159. package/src/policy/detect-claude-md-project-type.ts +32 -0
  160. package/src/policy/detect-framework.ts +99 -0
  161. package/src/policy/detect-primitive-checks.ts +100 -0
  162. package/src/policy/detect-primitive-lib.ts +55 -0
  163. package/src/policy/detect-project.ts +99 -0
  164. package/src/policy/edit-outcome.ts +53 -0
  165. package/src/policy/evaluate.ts +81 -0
  166. package/src/policy/expert-agents.ts +60 -0
  167. package/src/policy/file-size-scope.ts +32 -0
  168. package/src/policy/file-size.ts +99 -0
  169. package/src/policy/framework-solid-exclude.ts +52 -0
  170. package/src/policy/framework-solid-extended.ts +93 -0
  171. package/src/policy/framework-solid-gates-systems.ts +99 -0
  172. package/src/policy/framework-solid-gates.ts +98 -0
  173. package/src/policy/framework-solid.ts +88 -0
  174. package/src/policy/gemini-mcp-gate.ts +83 -0
  175. package/src/policy/git-gates.ts +40 -0
  176. package/src/policy/guards/bash-command-anchor.ts +40 -0
  177. package/src/policy/guards/bash-write-patterns.ts +140 -0
  178. package/src/policy/guards/bash-write-redirects.ts +201 -0
  179. package/src/policy/guards/bash-write-safe-paths.ts +62 -0
  180. package/src/policy/guards/bash-write.ts +76 -0
  181. package/src/policy/guards/context.ts +12 -0
  182. package/src/policy/guards/index.ts +61 -0
  183. package/src/policy/guards/install.ts +22 -0
  184. package/src/policy/guards/interface-separation-ext.ts +41 -0
  185. package/src/policy/guards/interface-separation.ts +100 -0
  186. package/src/policy/guards/protected-path.ts +100 -0
  187. package/src/policy/guards/security.ts +97 -0
  188. package/src/policy/index.ts +19 -0
  189. package/src/policy/interfaces/types.ts +46 -0
  190. package/src/policy/js-gate-route.ts +51 -0
  191. package/src/policy/lessons/lesson-gate.ts +0 -0
  192. package/src/policy/lessons/trigger-index.ts +84 -0
  193. package/src/policy/lessons/types.ts +31 -0
  194. package/src/policy/module-layout.ts +31 -0
  195. package/src/policy/nearest-manifest.ts +75 -0
  196. package/src/policy/never-approval.ts +95 -0
  197. package/src/policy/patterns.ts +80 -0
  198. package/src/policy/seo/validate.ts +51 -0
  199. package/src/policy/shadcn-project.ts +22 -0
  200. package/src/policy/shadcn-skill-gate.ts +97 -0
  201. package/src/policy/shell-read-refs.ts +96 -0
  202. package/src/policy/skill-path.ts +46 -0
  203. package/src/policy/skill-patterns/laravel.ts +40 -0
  204. package/src/policy/skill-patterns/nextjs.ts +29 -0
  205. package/src/policy/skill-patterns/react.ts +27 -0
  206. package/src/policy/skill-patterns/shadcn-subskills.ts +33 -0
  207. package/src/policy/skill-patterns/shadcn.ts +66 -0
  208. package/src/policy/skill-patterns/swift.ts +30 -0
  209. package/src/policy/skill-patterns/tailwind.ts +40 -0
  210. package/src/policy/skill-source.ts +52 -0
  211. package/src/policy/skill-trigger-patterns.ts +33 -0
  212. package/src/policy/skill-triggers.ts +108 -0
  213. package/src/policy/tailwind-skill-gate.ts +63 -0
  214. package/src/policy/trivial-edits.ts +52 -0
  215. package/src/policy/verbosity.ts +39 -0
  216. package/src/prompt/index.ts +1 -0
  217. package/src/prompt/types.ts +36 -0
  218. package/src/refs/discover.ts +69 -0
  219. package/src/refs/frontmatter.ts +24 -0
  220. package/src/refs/index.ts +4 -0
  221. package/src/refs/loader.ts +59 -0
  222. package/src/refs/ref-key.ts +41 -0
  223. package/src/refs/router.ts +63 -0
  224. package/src/refs/types.ts +25 -0
  225. package/src/runtime/activity.ts +99 -0
  226. package/src/runtime/apply-patch-gate.ts +41 -0
  227. package/src/runtime/burst-window.ts +21 -0
  228. package/src/runtime/codex-shell-tool.ts +37 -0
  229. package/src/runtime/command-string.ts +37 -0
  230. package/src/runtime/confirm/codex-confirm.ts +126 -0
  231. package/src/runtime/confirm/codex-prompt-origin.ts +16 -0
  232. package/src/runtime/confirm/confirm-code.ts +33 -0
  233. package/src/runtime/confirm/confirm-gate.ts +65 -0
  234. package/src/runtime/confirm/confirm-irreversible.ts +32 -0
  235. package/src/runtime/confirm/confirm-pending.ts +34 -0
  236. package/src/runtime/confirm/confirm-state.ts +56 -0
  237. package/src/runtime/confirm/confirm-subagent.ts +112 -0
  238. package/src/runtime/confirm/confirm-submit.ts +38 -0
  239. package/src/runtime/core-guards-active.ts +84 -0
  240. package/src/runtime/core-guards-wired.ts +47 -0
  241. package/src/runtime/deny-loop-store.ts +94 -0
  242. package/src/runtime/deny-notice.ts +52 -0
  243. package/src/runtime/design-cache-resolve.ts +51 -0
  244. package/src/runtime/design-content-gate.ts +95 -0
  245. package/src/runtime/design-files-gate.ts +114 -0
  246. package/src/runtime/design-helpers.ts +93 -0
  247. package/src/runtime/design-lifecycle.ts +39 -0
  248. package/src/runtime/design-read-credit.ts +28 -0
  249. package/src/runtime/design.ts +116 -0
  250. package/src/runtime/dev-context.ts +43 -0
  251. package/src/runtime/dry-patterns.ts +32 -0
  252. package/src/runtime/dry.ts +96 -0
  253. package/src/runtime/fragment-registry.ts +33 -0
  254. package/src/runtime/framework-skill-gate.ts +79 -0
  255. package/src/runtime/fs-cleanup.ts +71 -0
  256. package/src/runtime/gate-apex.ts +81 -0
  257. package/src/runtime/gate-helpers.ts +52 -0
  258. package/src/runtime/gate-input.ts +26 -0
  259. package/src/runtime/gate.ts +128 -0
  260. package/src/runtime/handle-post.ts +104 -0
  261. package/src/runtime/handle-pre.ts +137 -0
  262. package/src/runtime/handle-scope-async.ts +29 -0
  263. package/src/runtime/handle-types.ts +27 -0
  264. package/src/runtime/handle.ts +116 -0
  265. package/src/runtime/home-state.ts +55 -0
  266. package/src/runtime/index.ts +18 -0
  267. package/src/runtime/inform.ts +28 -0
  268. package/src/runtime/inject-budget-recap.ts +47 -0
  269. package/src/runtime/inject-budget.ts +81 -0
  270. package/src/runtime/inject-context.ts +85 -0
  271. package/src/runtime/inject-dedup-exclusive.ts +98 -0
  272. package/src/runtime/inject-dedup.ts +89 -0
  273. package/src/runtime/is-agent-tool.ts +19 -0
  274. package/src/runtime/lifecycle/agent-files.ts +49 -0
  275. package/src/runtime/lifecycle/agent-memory.ts +82 -0
  276. package/src/runtime/lifecycle/agent-transcript.ts +80 -0
  277. package/src/runtime/lifecycle/aipilot/analytics.ts +99 -0
  278. package/src/runtime/lifecycle/aipilot/apex-task-store.ts +61 -0
  279. package/src/runtime/lifecycle/aipilot/cache-base.ts +48 -0
  280. package/src/runtime/lifecycle/aipilot/cache-doc.ts +100 -0
  281. package/src/runtime/lifecycle/aipilot/cache-lessons.ts +58 -0
  282. package/src/runtime/lifecycle/aipilot/cache-test.ts +70 -0
  283. package/src/runtime/lifecycle/aipilot/curate-lessons.ts +64 -0
  284. package/src/runtime/lifecycle/aipilot/dispatch-aipilot.ts +100 -0
  285. package/src/runtime/lifecycle/aipilot/doc-cache-gate.ts +69 -0
  286. package/src/runtime/lifecycle/aipilot/inject-apex.ts +98 -0
  287. package/src/runtime/lifecycle/aipilot/inject-doc.ts +62 -0
  288. package/src/runtime/lifecycle/aipilot/inject-explore.ts +64 -0
  289. package/src/runtime/lifecycle/aipilot/inject-lessons.ts +61 -0
  290. package/src/runtime/lifecycle/aipilot/inject-test.ts +48 -0
  291. package/src/runtime/lifecycle/aipilot/lesson-archive.ts +60 -0
  292. package/src/runtime/lifecycle/aipilot/lesson-inject.ts +98 -0
  293. package/src/runtime/lifecycle/aipilot/lesson-parse.ts +74 -0
  294. package/src/runtime/lifecycle/aipilot/lessons.ts +72 -0
  295. package/src/runtime/lifecycle/aipilot/promote-global-lessons.ts +92 -0
  296. package/src/runtime/lifecycle/aipilot/solid-compliance.ts +69 -0
  297. package/src/runtime/lifecycle/aipilot/solid-notice.ts +47 -0
  298. package/src/runtime/lifecycle/aipilot/solid-transcript.ts +60 -0
  299. package/src/runtime/lifecycle/aipilot/source-scan.ts +56 -0
  300. package/src/runtime/lifecycle/aipilot/sync-task.ts +75 -0
  301. package/src/runtime/lifecycle/aipilot/transcript.ts +88 -0
  302. package/src/runtime/lifecycle/aipilot/types.ts +72 -0
  303. package/src/runtime/lifecycle/auto-document-reads.ts +73 -0
  304. package/src/runtime/lifecycle/cartographer/detect.ts +57 -0
  305. package/src/runtime/lifecycle/cartographer/ecosystem-map.ts +56 -0
  306. package/src/runtime/lifecycle/cartographer/fs-util.ts +64 -0
  307. package/src/runtime/lifecycle/cartographer/merge.ts +51 -0
  308. package/src/runtime/lifecycle/cartographer/project-map.ts +49 -0
  309. package/src/runtime/lifecycle/cartographer/scan-hooks.ts +48 -0
  310. package/src/runtime/lifecycle/cartographer/scan.ts +81 -0
  311. package/src/runtime/lifecycle/cartographer/session-start.ts +33 -0
  312. package/src/runtime/lifecycle/cartographer/track-enrichment.ts +45 -0
  313. package/src/runtime/lifecycle/cartographer/write-plugin-map.ts +43 -0
  314. package/src/runtime/lifecycle/cartographer/write-tree.ts +44 -0
  315. package/src/runtime/lifecycle/changelog-research.ts +43 -0
  316. package/src/runtime/lifecycle/check-file-size.ts +61 -0
  317. package/src/runtime/lifecycle/codex-resync/fingerprint.ts +63 -0
  318. package/src/runtime/lifecycle/codex-resync/lock.ts +46 -0
  319. package/src/runtime/lifecycle/codex-resync/managed-destination.ts +39 -0
  320. package/src/runtime/lifecycle/codex-resync/materialize-agents.ts +57 -0
  321. package/src/runtime/lifecycle/codex-resync/plugin-files.ts +65 -0
  322. package/src/runtime/lifecycle/codex-resync/plugin-roots.ts +62 -0
  323. package/src/runtime/lifecycle/codex-resync/resync.ts +45 -0
  324. package/src/runtime/lifecycle/codex-resync/symlink-commands.ts +25 -0
  325. package/src/runtime/lifecycle/dispatch.ts +109 -0
  326. package/src/runtime/lifecycle/failure-lesson.ts +51 -0
  327. package/src/runtime/lifecycle/index.ts +34 -0
  328. package/src/runtime/lifecycle/inject-rules.ts +50 -0
  329. package/src/runtime/lifecycle/instructions-loaded.ts +22 -0
  330. package/src/runtime/lifecycle/kimi-rules-native.ts +44 -0
  331. package/src/runtime/lifecycle/lessons/dispatch.ts +88 -0
  332. package/src/runtime/lifecycle/lessons/reminder.ts +89 -0
  333. package/src/runtime/lifecycle/lessons/state.ts +23 -0
  334. package/src/runtime/lifecycle/memory/agent-lesson.ts +35 -0
  335. package/src/runtime/lifecycle/memory/capture-error.ts +41 -0
  336. package/src/runtime/lifecycle/memory/client.ts +65 -0
  337. package/src/runtime/lifecycle/memory/dispatch.ts +42 -0
  338. package/src/runtime/lifecycle/memory/recall.ts +30 -0
  339. package/src/runtime/lifecycle/memory/salience.ts +31 -0
  340. package/src/runtime/lifecycle/memory/state.ts +49 -0
  341. package/src/runtime/lifecycle/memory/track-ops.ts +15 -0
  342. package/src/runtime/lifecycle/post-compact.ts +38 -0
  343. package/src/runtime/lifecycle/post-edit-ts.ts +49 -0
  344. package/src/runtime/lifecycle/post-tracking.ts +40 -0
  345. package/src/runtime/lifecycle/pre-compact.ts +38 -0
  346. package/src/runtime/lifecycle/rules-root.ts +83 -0
  347. package/src/runtime/lifecycle/security/check-skill.ts +63 -0
  348. package/src/runtime/lifecycle/security/scan-patterns.ts +53 -0
  349. package/src/runtime/lifecycle/security/scan.ts +76 -0
  350. package/src/runtime/lifecycle/security/skill-state.ts +47 -0
  351. package/src/runtime/lifecycle/security/track-mcp.ts +29 -0
  352. package/src/runtime/lifecycle/security/track-skill-read.ts +31 -0
  353. package/src/runtime/lifecycle/seo/post-tool-use.ts +45 -0
  354. package/src/runtime/lifecycle/session-end.ts +17 -0
  355. package/src/runtime/lifecycle/session-start.ts +57 -0
  356. package/src/runtime/lifecycle/snapshot/board.ts +27 -0
  357. package/src/runtime/lifecycle/snapshot/format.ts +60 -0
  358. package/src/runtime/lifecycle/snapshot/git.ts +71 -0
  359. package/src/runtime/lifecycle/snapshot/index.ts +52 -0
  360. package/src/runtime/lifecycle/snapshot/version.ts +34 -0
  361. package/src/runtime/lifecycle/solid-detect.ts +56 -0
  362. package/src/runtime/lifecycle/stop-core.ts +35 -0
  363. package/src/runtime/lifecycle/subagent-cache.ts +61 -0
  364. package/src/runtime/lifecycle/task-completed.ts +94 -0
  365. package/src/runtime/lifecycle/teammate-idle-check.ts +63 -0
  366. package/src/runtime/lifecycle/teammate-idle.ts +28 -0
  367. package/src/runtime/lifecycle/tool-failure.ts +24 -0
  368. package/src/runtime/lifecycle/track-changes.ts +61 -0
  369. package/src/runtime/lifecycle/validate-solid.ts +70 -0
  370. package/src/runtime/lifecycle/validate-tailwind.ts +80 -0
  371. package/src/runtime/lifecycle-bridge.ts +74 -0
  372. package/src/runtime/mcp-key.ts +44 -0
  373. package/src/runtime/mcp-tool-name.ts +92 -0
  374. package/src/runtime/mcp.ts +91 -0
  375. package/src/runtime/modular.ts +77 -0
  376. package/src/runtime/normalize.ts +107 -0
  377. package/src/runtime/notices.ts +91 -0
  378. package/src/runtime/notification-sound.ts +49 -0
  379. package/src/runtime/notifications.ts +77 -0
  380. package/src/runtime/paths.ts +59 -0
  381. package/src/runtime/post-fanout.ts +41 -0
  382. package/src/runtime/post-outcome.ts +61 -0
  383. package/src/runtime/pre-allow.ts +97 -0
  384. package/src/runtime/precommit.ts +60 -0
  385. package/src/runtime/prompt-text.ts +38 -0
  386. package/src/runtime/receipt-capture.ts +34 -0
  387. package/src/runtime/record.ts +26 -0
  388. package/src/runtime/respond.ts +92 -0
  389. package/src/runtime/solid-file-size-gate.ts +58 -0
  390. package/src/runtime/solid-pre.ts +53 -0
  391. package/src/runtime/storage.ts +9 -0
  392. package/src/statusline/colors.ts +31 -0
  393. package/src/statusline/constants.ts +17 -0
  394. package/src/statusline/formatters.ts +54 -0
  395. package/src/statusline/index.ts +4 -0
  396. package/src/statusline/progress-bar.ts +46 -0
  397. package/src/tracking/codex-post-failure.ts +73 -0
  398. package/src/tracking/index.ts +2 -0
  399. package/src/tracking/integrity.ts +99 -0
  400. package/src/tracking/one-shot-dedup.ts +34 -0
  401. package/src/tracking/one-shot-failure.ts +42 -0
  402. package/src/tracking/one-shot-store.ts +95 -0
  403. package/src/tracking/one-shot.ts +93 -0
  404. package/src/tracking/receipts.ts +95 -0
  405. package/src/tracking/session-state.ts +94 -0
  406. package/src/tracking/store.ts +96 -0
  407. package/src/tracking/track-compact.ts +100 -0
  408. package/src/tracking/track-diff.ts +50 -0
  409. package/src/tracking/track-journal.ts +97 -0
  410. package/src/tracking/track-lock-sync.ts +83 -0
  411. package/src/tracking/track-lock.ts +67 -0
  412. package/src/util/compact-json.ts +23 -0
  413. package/src/util/index.ts +2 -0
  414. package/src/util/json-io.ts +47 -0
  415. package/src/util/project-root.ts +41 -0
  416. package/src/util/runtime-io.ts +85 -0
  417. package/src/util/semver.ts +30 -0
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Synchronous twin of {@link withTrackLock} for lifecycle paths that CANNOT
3
+ * float async work (the SubagentStop dispatch runs synchronously in a
4
+ * short-lived hook process — an async write could be dropped before exit,
5
+ * see `evidence-harvest-io.ts`). Same semantics: `wx` lockfile, bounded total
6
+ * retry, named skipped write on contention, stale reclamation. The wait uses
7
+ * `Atomics.wait` (allowed on the main thread in both Node and Bun).
8
+ */
9
+ import { closeSync, mkdirSync, openSync, statSync, unlinkSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { LOCK_FAILED, LOCK_RETRY_TOTAL_MS, LOCK_TTL_MS } from "./track-lock";
12
+
13
+ export { LOCK_FAILED } from "./track-lock";
14
+
15
+ /** Block the thread for `ms` (bounded by the caller's total budget). */
16
+ function sleepSync(ms: number): void {
17
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
18
+ }
19
+
20
+ /** True when the lockfile is older than the TTL (orphaned by a dead process). */
21
+ function isStale(lock: string): boolean {
22
+ try { return Date.now() - statSync(lock).mtimeMs > LOCK_TTL_MS; } catch { return false; }
23
+ }
24
+
25
+ /**
26
+ * Run `fn` under the track lock of `dir`, synchronously.
27
+ * @param dir - The track state directory (lockfile lives inside).
28
+ * @param fn - The protected read-modify-write.
29
+ * @returns `fn`'s result, or {@link LOCK_FAILED} when the lock stayed busy.
30
+ */
31
+ export function withTrackLockSync<T>(dir: string, fn: () => T): T | typeof LOCK_FAILED {
32
+ mkdirSync(dir, { recursive: true });
33
+ const lock = join(dir, "track.lock");
34
+ const deadline = Date.now() + LOCK_RETRY_TOTAL_MS;
35
+ for (;;) {
36
+ try {
37
+ const fd = openSync(lock, "wx");
38
+ closeSync(fd);
39
+ break;
40
+ } catch {
41
+ if (isStale(lock)) { try { unlinkSync(lock); } catch { /* raced */ } continue; }
42
+ if (Date.now() >= deadline) {
43
+ process.stderr.write(`harness: track lock busy, write skipped (${lock})\n`);
44
+ return LOCK_FAILED;
45
+ }
46
+ sleepSync(8);
47
+ }
48
+ }
49
+ try {
50
+ return fn();
51
+ } finally {
52
+ try { unlinkSync(lock); } catch { /* best-effort release */ }
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Blocking twin of {@link withTrackLockSync}: NEVER skips — spins (1 ms step)
58
+ * until the lock is acquired. Used by the journal append path (track-journal
59
+ * `appendEvent`): an append must wait out an in-flight compaction (same
60
+ * `track.lock`), never race its rename/fold/unlink, never be skipped — a lost
61
+ * write is not an option. The stale-lock TTL (dead-process reclamation) is the
62
+ * only anti-deadlock guard. Do NOT use on paths that may already hold the lock.
63
+ */
64
+ export function withTrackLockSyncBlocking<T>(dir: string, fn: () => T): T {
65
+ mkdirSync(dir, { recursive: true });
66
+ const lock = join(dir, "track.lock");
67
+ for (;;) {
68
+ try {
69
+ const fd = openSync(lock, "wx");
70
+ closeSync(fd);
71
+ break;
72
+ } catch {
73
+ if (isStale(lock)) { try { unlinkSync(lock); } catch { /* raced */ } }
74
+ sleepSync(1);
75
+ }
76
+ }
77
+ try {
78
+ return fn();
79
+ } finally {
80
+ try { unlinkSync(lock); } catch { /* best-effort release */ }
81
+ }
82
+ }
83
+
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Cross-process lock for session-track read-modify-write. The ~11-hook
3
+ * fan-out races plain `loadTrack → mutate → saveTrack` (writes silently
4
+ * lost — `refsRead` was the only mitigated channel, via its journal). This
5
+ * lockfile (`wx`, atomic create) serializes the whole RMW:
6
+ * - retry is bounded in TOTAL time (400 ms, far under any hook timeout);
7
+ * - after the budget, NEVER crash: stderr is logged and the caller skips the
8
+ * write — a named lost write beats a fail-open crash (hook fail-open
9
+ * semantics preserved);
10
+ * - an orphaned lockfile (dead process) is reclaimed after a 10 s TTL, so a
11
+ * crash mid-write never blocks a project forever.
12
+ */
13
+ import { closeSync, existsSync, mkdirSync, openSync, statSync, unlinkSync } from "node:fs";
14
+ import { join } from "node:path";
15
+
16
+ /** Orphaned lockfile lifetime before reclamation. */
17
+ export const LOCK_TTL_MS = 10_000;
18
+ /** Total bounded retry budget before the write is skipped (fail-open). */
19
+ export const LOCK_RETRY_TOTAL_MS = 400;
20
+ /** Delay between two lock acquisition attempts. */
21
+ const RETRY_STEP_MS = 8;
22
+
23
+ /** Sentinel returned by {@link withTrackLock} when the lock could not be taken. */
24
+ export const LOCK_FAILED: unique symbol = Symbol("track-lock-failed");
25
+
26
+ /** True when the lockfile is older than the TTL (orphaned by a dead process). */
27
+ function isStale(lock: string): boolean {
28
+ try { return Date.now() - statSync(lock).mtimeMs > LOCK_TTL_MS; } catch { return false; }
29
+ }
30
+
31
+ const sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));
32
+
33
+ /**
34
+ * Run `fn` under the track lock of `dir`, or skip with a stderr note.
35
+ * @param dir - The track state directory (lockfile lives inside).
36
+ * @param fn - The protected read-modify-write.
37
+ * @returns `fn`'s result, or {@link LOCK_FAILED} when the lock stayed busy.
38
+ */
39
+ export async function withTrackLock<T>(dir: string, fn: () => Promise<T>): Promise<T | typeof LOCK_FAILED> {
40
+ mkdirSync(dir, { recursive: true });
41
+ const lock = join(dir, "track.lock");
42
+ const deadline = Date.now() + LOCK_RETRY_TOTAL_MS;
43
+ for (;;) {
44
+ try {
45
+ const fd = openSync(lock, "wx");
46
+ closeSync(fd);
47
+ break;
48
+ } catch {
49
+ if (isStale(lock)) { try { unlinkSync(lock); } catch { /* raced */ } continue; }
50
+ if (Date.now() >= deadline) {
51
+ process.stderr.write(`harness: track lock busy, write skipped (${lock})\n`);
52
+ return LOCK_FAILED;
53
+ }
54
+ await sleep(RETRY_STEP_MS);
55
+ }
56
+ }
57
+ try {
58
+ return await fn();
59
+ } finally {
60
+ try { unlinkSync(lock); } catch { /* best-effort release */ }
61
+ }
62
+ }
63
+
64
+ /** Test helper: true when a lockfile currently exists in `dir`. */
65
+ export function trackLockExists(dir: string): boolean {
66
+ return existsSync(join(dir, "track.lock"));
67
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Compact JSON serializer for cache/state files.
3
+ * Top-level keys are indented one per line; nested objects/arrays render inline.
4
+ * Behaviour preserved from the fusengine hooks.
5
+ */
6
+ export function compactJson(data: unknown): string {
7
+ if (typeof data !== "object" || data === null) return `${JSON.stringify(data)}\n`;
8
+ if (Array.isArray(data)) {
9
+ if (data.length === 0) return "[]\n";
10
+ const items = data.map((item) => ` ${JSON.stringify(item)}`);
11
+ return `[\n${items.join(",\n")}\n]\n`;
12
+ }
13
+ const lines: string[] = [];
14
+ for (const [key, val] of Object.entries(data as Record<string, unknown>)) {
15
+ if (Array.isArray(val) && val.length > 0) {
16
+ const items = val.map((item) => ` ${JSON.stringify(item)}`);
17
+ lines.push(` "${key}": [\n${items.join(",\n")}\n ]`);
18
+ } else {
19
+ lines.push(` "${key}": ${JSON.stringify(val)}`);
20
+ }
21
+ }
22
+ return `{\n${lines.join(",\n")}\n}\n`;
23
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./compact-json";
2
+ export * from "./project-root";
@@ -0,0 +1,47 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import {
3
+ chmodSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync,
4
+ } from "node:fs";
5
+ import { dirname } from "node:path";
6
+ import { createHash, randomUUID } from "node:crypto";
7
+ import { compactJson } from "./compact-json";
8
+
9
+ /** Atomically write `data` to `path` (temp + rename, 0o600). Cross-FS safe on macOS/Linux. */
10
+ export function atomicWrite(path: string, data: string): void {
11
+ const parent = dirname(path);
12
+ mkdirSync(parent, { recursive: true });
13
+ const tmp = `${path}.${randomUUID()}.tmp`;
14
+ try {
15
+ writeFileSync(tmp, data, { encoding: "utf8" });
16
+ chmodSync(tmp, 0o600);
17
+ renameSync(tmp, path);
18
+ } catch (err) {
19
+ try { unlinkSync(tmp); } catch { /* noop */ }
20
+ throw err;
21
+ }
22
+ }
23
+
24
+ /** Ensure a directory exists. */
25
+ export async function ensureDir(dir: string): Promise<void> {
26
+ await mkdir(dir, { recursive: true });
27
+ }
28
+
29
+ /** Read & JSON-parse a file; null on missing/corrupt. */
30
+ export async function readJsonFile<T>(path: string): Promise<T | null> {
31
+ try {
32
+ if (!existsSync(path)) return null;
33
+ return JSON.parse(readFileSync(path, "utf8")) as T;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ /** Atomically write JSON (compact form when `compact`). */
40
+ export async function writeJsonFile(path: string, data: unknown, compact = false): Promise<void> {
41
+ atomicWrite(path, compact ? compactJson(data) : JSON.stringify(data, null, 2));
42
+ }
43
+
44
+ /** 8-char MD5 of text (cache key; non-cryptographic). Portable Node+Bun. */
45
+ export function hashText(text: string): string {
46
+ return createHash("md5").update(text).digest("hex").slice(0, 8);
47
+ }
@@ -0,0 +1,41 @@
1
+ import { existsSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+
4
+ /** Source-code file extensions worth tracking as "code was written". */
5
+ const CODE_EXT =
6
+ /\.(ts|tsx|js|jsx|py|php|swift|go|rs|rb|java|vue|svelte|astro|css|kt|dart|cpp|c)$/;
7
+ /** Generated/vendored directories that never count as code. */
8
+ const SKIP_DIRS = /(node_modules|vendor|dist|build|\.next|DerivedData|\.git)/;
9
+
10
+ /** True for a source-code file outside generated/vendored directories. */
11
+ export function isCodeFile(p: string): boolean {
12
+ return CODE_EXT.test(p) && !SKIP_DIRS.test(p);
13
+ }
14
+
15
+ /**
16
+ * Walk up from `dir` to the nearest ancestor directory containing `marker`.
17
+ * @param dir - Starting directory.
18
+ * @param marker - Sibling file/dir name to look for at each level.
19
+ * @returns The ancestor holding `marker`, or `null` at filesystem root.
20
+ */
21
+ export function walkUpFor(dir: string, marker: string): string | null {
22
+ let current = resolve(dir);
23
+ while (current !== "/") {
24
+ if (existsSync(`${current}/${marker}`)) return current;
25
+ current = dirname(current);
26
+ }
27
+ return null;
28
+ }
29
+
30
+ /**
31
+ * Resolve the project root, preferring the repo boundary (`.git`) over a
32
+ * nested `package.json` — avoids false roots in monorepos. Null if none found.
33
+ */
34
+ export function projectRootOrNull(dir: string): string | null {
35
+ return walkUpFor(dir, ".git") ?? walkUpFor(dir, "package.json");
36
+ }
37
+
38
+ /** Like {@link projectRootOrNull} but falls back to `process.cwd()`. */
39
+ export function projectRoot(dir: string): string {
40
+ return projectRootOrNull(dir) ?? process.cwd();
41
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Cross-runtime I/O helpers (Node + Bun). The published CLI ships a `node`
3
+ * shebang and is invoked via `npx`/`npm`/`bunx`/`bun`; using only `node:*` APIs
4
+ * here keeps the bundle runnable under EVERY runtime — replacing the Bun-only
5
+ * `Bun.file/write/spawn/sleep/stdin` calls and the `bun` `Glob` import that made
6
+ * the package crash with `Cannot find package 'bun'` under plain Node.
7
+ */
8
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, type Dirent } from "node:fs";
9
+ import { dirname, join } from "node:path";
10
+ import { spawnSync } from "node:child_process";
11
+
12
+ /** Read a file as UTF-8 text (throws on missing/unreadable — callers catch). */
13
+ export function readText(path: string): string {
14
+ return readFileSync(path, "utf8");
15
+ }
16
+
17
+ /** True when `path` exists. */
18
+ export function pathExists(path: string): boolean {
19
+ return existsSync(path);
20
+ }
21
+
22
+ /** Write `data` to `path`, creating parent dirs (mirrors `Bun.write`). */
23
+ export function writeText(path: string, data: string): void {
24
+ mkdirSync(dirname(path), { recursive: true });
25
+ writeFileSync(path, data, { encoding: "utf8" });
26
+ }
27
+
28
+ /** Resolve after `ms` milliseconds (`Bun.sleep` replacement). */
29
+ export function sleep(ms: number): Promise<void> {
30
+ return new Promise((resolve) => setTimeout(resolve, ms));
31
+ }
32
+
33
+ /** Run `cmd args` in `cwd` and capture stdout text ("" on failure/non-zero). */
34
+ export function spawnCapture(cmd: string, args: string[], cwd: string): string {
35
+ try {
36
+ const r = spawnSync(cmd, args, { cwd, encoding: "utf8" });
37
+ return r.status === 0 ? (r.stdout ?? "") : "";
38
+ } catch {
39
+ return "";
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Read the full process stdin as UTF-8 text (works under Node and Bun).
45
+ * Synchronous fd-0 read — never `for await (const c of process.stdin)` —
46
+ * because Bun has a confirmed Linux-only bug where merely adding a new
47
+ * top-level module import shifts stdin's internal init order and makes
48
+ * that async iterator silently yield zero bytes (oven-sh/bun#25320,
49
+ * #27849): exactly what broke every `harness hook` invocation on CI the
50
+ * moment `figures` became this package's first runtime dependency.
51
+ * `readFileSync(0)` bypasses that stream/ownership machinery entirely and
52
+ * is well-supported for piped (non-TTY) stdin under both runtimes.
53
+ */
54
+ export async function readStdin(): Promise<string> {
55
+ try {
56
+ return readFileSync(0, "utf8");
57
+ } catch {
58
+ return "";
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Recursively collect files under `dir` whose extension is in `exts`, skipping
64
+ * `node_modules` and dot-dirs, capped at `cap`. `Bun.Glob().scan()` replacement.
65
+ * @param dir - Directory to walk.
66
+ * @param exts - Allowed extensions including the dot (e.g. `.ts`).
67
+ * @param out - Accumulator (mutated in place).
68
+ * @param cap - Max files to collect.
69
+ */
70
+ export function collectFiles(dir: string, exts: ReadonlySet<string>, out: string[], cap: number): void {
71
+ if (out.length >= cap) return;
72
+ let entries: Dirent[];
73
+ try {
74
+ entries = readdirSync(dir, { withFileTypes: true });
75
+ } catch {
76
+ return;
77
+ }
78
+ for (const e of entries) {
79
+ if (out.length >= cap) return;
80
+ if (e.name === "node_modules" || e.name.startsWith(".")) continue;
81
+ const full = join(dir, e.name);
82
+ if (e.isDirectory()) collectFiles(full, exts, out, cap);
83
+ else if (exts.has(e.name.slice(e.name.lastIndexOf(".")))) out.push(full);
84
+ }
85
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Dependency-free semver ordering. `Array.prototype.sort()` compares strings
3
+ * lexicographically — `"1.0.9" > "1.0.23"` — so versioned directories (plugin
4
+ * caches) must be ordered with a numeric, segment-by-segment comparison.
5
+ */
6
+
7
+ /**
8
+ * Compare two dotted version strings numerically, segment by segment
9
+ * (shorter version wins when a prefix is equal: `1.0` < `1.0.1`). A segment
10
+ * that is not a plain integer (prerelease tag like `0-beta`) falls back to
11
+ * lexicographic comparison of that segment — never NaN, so `sort()` stays
12
+ * defined; identical strings compare 0.
13
+ * @returns Negative when `a < b`, positive when `a > b`, 0 when equal.
14
+ */
15
+ export function compareSemver(a: string, b: string): number {
16
+ const pa = a.split("."), pb = b.split(".");
17
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
18
+ const sa = pa[i] ?? "0", sb = pb[i] ?? "0";
19
+ if (sa === sb) continue;
20
+ const na = Number(sa), nb = Number(sb);
21
+ if (Number.isInteger(na) && Number.isInteger(nb) && na !== nb) return na - nb;
22
+ return sa < sb ? -1 : 1;
23
+ }
24
+ return 0;
25
+ }
26
+
27
+ /** The highest version of the list, or null when empty. */
28
+ export function maxSemver(versions: string[]): string | null {
29
+ return versions.length === 0 ? null : versions.reduce((a, b) => (compareSemver(a, b) >= 0 ? a : b));
30
+ }