@fusengine/harness 0.1.90 → 0.1.92

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 (422) 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-BF1dZFjY.mjs} +1194 -144
  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-Dy8g9Ybl.mjs +397 -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 +37 -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-budget.ts +144 -0
  44. package/src/adapters/cursor/context-limit.ts +115 -0
  45. package/src/adapters/cursor/context.ts +65 -0
  46. package/src/adapters/cursor/events.ts +38 -0
  47. package/src/adapters/cursor/index.ts +43 -0
  48. package/src/adapters/cursor/interfaces/context-budget.ts +25 -0
  49. package/src/adapters/cursor/interfaces/types.ts +88 -0
  50. package/src/adapters/cursor/native-response.ts +39 -0
  51. package/src/adapters/cursor/native-schemas.ts +161 -0
  52. package/src/adapters/cursor/normalize.ts +188 -0
  53. package/src/adapters/cursor/plugin-root.ts +103 -0
  54. package/src/adapters/cursor/respond.ts +170 -0
  55. package/src/adapters/gemini/index.ts +36 -0
  56. package/src/adapters/hermes/index.ts +55 -0
  57. package/src/adapters/hermes/interfaces/types.ts +26 -0
  58. package/src/adapters/kimi/index.ts +96 -0
  59. package/src/adapters/kimi/interfaces/types.ts +55 -0
  60. package/src/cache/compact.ts +55 -0
  61. package/src/cache/index.ts +5 -0
  62. package/src/cache/io.ts +38 -0
  63. package/src/cache/mcp-response.ts +39 -0
  64. package/src/cache/mcp-store.ts +70 -0
  65. package/src/cache/store.ts +93 -0
  66. package/src/changelog/fetch.ts +79 -0
  67. package/src/cli/bin.ts +100 -0
  68. package/src/cli/cursor-event-scanner.ts +175 -0
  69. package/src/cli/cursor-stdin-reader.ts +65 -0
  70. package/src/cli/doctor.ts +96 -0
  71. package/src/cli/hook-io.ts +130 -0
  72. package/src/cli/hook-sound.ts +49 -0
  73. package/src/cli/index.ts +1 -0
  74. package/src/cli/json-primitive-scanner.ts +83 -0
  75. package/src/cli/run.ts +36 -0
  76. package/src/cli/scope.ts +31 -0
  77. package/src/codex-rules/build.ts +63 -0
  78. package/src/codex-rules/index.ts +8 -0
  79. package/src/codex-rules/mapping.ts +42 -0
  80. package/src/codex-rules/rules/absolute-paths.ts +52 -0
  81. package/src/codex-rules/rules/ask.ts +44 -0
  82. package/src/codex-rules/rules/chmod-ask.ts +57 -0
  83. package/src/codex-rules/rules/dd.ts +23 -0
  84. package/src/codex-rules/rules/diskutil.ts +33 -0
  85. package/src/codex-rules/rules/mkfs.ts +42 -0
  86. package/src/codex-rules/rules/privilege.ts +49 -0
  87. package/src/codex-rules/rules/remote-fetch.ts +31 -0
  88. package/src/codex-rules/rules/rm-variants.ts +58 -0
  89. package/src/codex-rules/rules/single-commands.ts +57 -0
  90. package/src/codex-rules/skip-list.ts +25 -0
  91. package/src/codex-rules/starlark.ts +46 -0
  92. package/src/codex-rules/types.ts +36 -0
  93. package/src/config/dotenv.ts +55 -0
  94. package/src/config/env.ts +10 -0
  95. package/src/config/home-dir.ts +36 -0
  96. package/src/config/index.ts +5 -0
  97. package/src/config/layout.ts +52 -0
  98. package/src/config/limits.ts +56 -0
  99. package/src/config/ttl.ts +30 -0
  100. package/src/detect/harness.ts +73 -0
  101. package/src/detect/index.ts +1 -0
  102. package/src/detect/interfaces/types.ts +18 -0
  103. package/src/freshness/agent-evidence-record.ts +95 -0
  104. package/src/freshness/agent-evidence.ts +95 -0
  105. package/src/freshness/codex-spawn-evidence.ts +91 -0
  106. package/src/freshness/doc-helpers.ts +90 -0
  107. package/src/freshness/evidence-harvest-io.ts +72 -0
  108. package/src/freshness/evidence-harvest.ts +61 -0
  109. package/src/freshness/explore-tools.ts +95 -0
  110. package/src/freshness/index.ts +2 -0
  111. package/src/freshness/query-framework.ts +73 -0
  112. package/src/freshness/ref-evidence.ts +49 -0
  113. package/src/freshness/ref-journal.ts +98 -0
  114. package/src/freshness/trivial-edit-counter.ts +30 -0
  115. package/src/index.ts +11 -0
  116. package/src/init/index.ts +2 -0
  117. package/src/init/run.ts +32 -0
  118. package/src/init/templates.ts +75 -0
  119. package/src/memory/gitignore.ts +14 -0
  120. package/src/memory/index.ts +3 -0
  121. package/src/memory/registry.ts +39 -0
  122. package/src/memory/session-roots.ts +99 -0
  123. package/src/memory/state.ts +58 -0
  124. package/src/policy/apex-authorization.ts +100 -0
  125. package/src/policy/apex-gates.ts +91 -0
  126. package/src/policy/apex-target-steps.ts +73 -0
  127. package/src/policy/apex-target.ts +49 -0
  128. package/src/policy/apex-task-context.ts +81 -0
  129. package/src/policy/apex.ts +94 -0
  130. package/src/policy/cartographer/build-tree.ts +69 -0
  131. package/src/policy/cartographer/describe.ts +53 -0
  132. package/src/policy/cartographer/entry.ts +38 -0
  133. package/src/policy/cartographer/frontmatter.ts +48 -0
  134. package/src/policy/cartographer/indicators.ts +34 -0
  135. package/src/policy/claude-md-context.ts +66 -0
  136. package/src/policy/conventions/index.ts +11 -0
  137. package/src/policy/conventions/interfaces.ts +71 -0
  138. package/src/policy/conventions/langs.ts +53 -0
  139. package/src/policy/conventions/query.ts +49 -0
  140. package/src/policy/conventions/react-hooks.ts +18 -0
  141. package/src/policy/conventions/store-or-query.ts +21 -0
  142. package/src/policy/conventions/stores.ts +56 -0
  143. package/src/policy/conventions/strip.ts +87 -0
  144. package/src/policy/conventions/verdict.ts +38 -0
  145. package/src/policy/creation-intent.ts +11 -0
  146. package/src/policy/deny-loop.ts +88 -0
  147. package/src/policy/design/allowed-write.ts +28 -0
  148. package/src/policy/design/content-checks.ts +45 -0
  149. package/src/policy/design/corpus-fs.ts +21 -0
  150. package/src/policy/design/corpus-resolve-cache.ts +49 -0
  151. package/src/policy/design/corpus-resolve.ts +99 -0
  152. package/src/policy/design/corpus.ts +92 -0
  153. package/src/policy/design/design-system-rules.ts +45 -0
  154. package/src/policy/design/flag.ts +30 -0
  155. package/src/policy/design/gates-pipeline.ts +105 -0
  156. package/src/policy/design/gates.ts +87 -0
  157. package/src/policy/design/screenshot-tools.ts +24 -0
  158. package/src/policy/design/skill-evidence.ts +34 -0
  159. package/src/policy/design/skill-gate.ts +81 -0
  160. package/src/policy/design/skill-triggers.ts +51 -0
  161. package/src/policy/design/state.ts +92 -0
  162. package/src/policy/design/template-urls.ts +54 -0
  163. package/src/policy/design/transitions.ts +68 -0
  164. package/src/policy/detect-claude-md-project-type.ts +32 -0
  165. package/src/policy/detect-framework.ts +99 -0
  166. package/src/policy/detect-primitive-checks.ts +100 -0
  167. package/src/policy/detect-primitive-lib.ts +55 -0
  168. package/src/policy/detect-project.ts +99 -0
  169. package/src/policy/edit-outcome.ts +53 -0
  170. package/src/policy/evaluate.ts +81 -0
  171. package/src/policy/expert-agents.ts +60 -0
  172. package/src/policy/file-size-scope.ts +32 -0
  173. package/src/policy/file-size.ts +99 -0
  174. package/src/policy/framework-solid-exclude.ts +52 -0
  175. package/src/policy/framework-solid-extended.ts +93 -0
  176. package/src/policy/framework-solid-gates-systems.ts +99 -0
  177. package/src/policy/framework-solid-gates.ts +98 -0
  178. package/src/policy/framework-solid.ts +88 -0
  179. package/src/policy/gemini-mcp-gate.ts +83 -0
  180. package/src/policy/git-gates.ts +40 -0
  181. package/src/policy/guards/bash-command-anchor.ts +40 -0
  182. package/src/policy/guards/bash-write-patterns.ts +140 -0
  183. package/src/policy/guards/bash-write-redirects.ts +201 -0
  184. package/src/policy/guards/bash-write-safe-paths.ts +62 -0
  185. package/src/policy/guards/bash-write.ts +76 -0
  186. package/src/policy/guards/context.ts +12 -0
  187. package/src/policy/guards/index.ts +61 -0
  188. package/src/policy/guards/install.ts +22 -0
  189. package/src/policy/guards/interface-separation-ext.ts +41 -0
  190. package/src/policy/guards/interface-separation.ts +100 -0
  191. package/src/policy/guards/protected-path.ts +100 -0
  192. package/src/policy/guards/security.ts +97 -0
  193. package/src/policy/index.ts +19 -0
  194. package/src/policy/interfaces/types.ts +46 -0
  195. package/src/policy/js-gate-route.ts +51 -0
  196. package/src/policy/lessons/lesson-gate.ts +0 -0
  197. package/src/policy/lessons/trigger-index.ts +84 -0
  198. package/src/policy/lessons/types.ts +31 -0
  199. package/src/policy/module-layout.ts +31 -0
  200. package/src/policy/nearest-manifest.ts +75 -0
  201. package/src/policy/never-approval.ts +95 -0
  202. package/src/policy/patterns.ts +80 -0
  203. package/src/policy/seo/validate.ts +51 -0
  204. package/src/policy/shadcn-project.ts +22 -0
  205. package/src/policy/shadcn-skill-gate.ts +97 -0
  206. package/src/policy/shell-read-refs.ts +96 -0
  207. package/src/policy/skill-path.ts +46 -0
  208. package/src/policy/skill-patterns/laravel.ts +40 -0
  209. package/src/policy/skill-patterns/nextjs.ts +29 -0
  210. package/src/policy/skill-patterns/react.ts +27 -0
  211. package/src/policy/skill-patterns/shadcn-subskills.ts +33 -0
  212. package/src/policy/skill-patterns/shadcn.ts +66 -0
  213. package/src/policy/skill-patterns/swift.ts +30 -0
  214. package/src/policy/skill-patterns/tailwind.ts +40 -0
  215. package/src/policy/skill-source.ts +52 -0
  216. package/src/policy/skill-trigger-patterns.ts +33 -0
  217. package/src/policy/skill-triggers.ts +108 -0
  218. package/src/policy/tailwind-skill-gate.ts +63 -0
  219. package/src/policy/trivial-edits.ts +52 -0
  220. package/src/policy/verbosity.ts +39 -0
  221. package/src/prompt/index.ts +1 -0
  222. package/src/prompt/types.ts +36 -0
  223. package/src/refs/discover.ts +69 -0
  224. package/src/refs/frontmatter.ts +24 -0
  225. package/src/refs/index.ts +4 -0
  226. package/src/refs/loader.ts +59 -0
  227. package/src/refs/ref-key.ts +41 -0
  228. package/src/refs/router.ts +63 -0
  229. package/src/refs/types.ts +25 -0
  230. package/src/runtime/activity.ts +99 -0
  231. package/src/runtime/apply-patch-gate.ts +41 -0
  232. package/src/runtime/burst-window.ts +21 -0
  233. package/src/runtime/codex-shell-tool.ts +37 -0
  234. package/src/runtime/command-string.ts +37 -0
  235. package/src/runtime/confirm/codex-confirm.ts +126 -0
  236. package/src/runtime/confirm/codex-prompt-origin.ts +16 -0
  237. package/src/runtime/confirm/confirm-code.ts +33 -0
  238. package/src/runtime/confirm/confirm-gate.ts +65 -0
  239. package/src/runtime/confirm/confirm-irreversible.ts +32 -0
  240. package/src/runtime/confirm/confirm-pending.ts +34 -0
  241. package/src/runtime/confirm/confirm-state.ts +56 -0
  242. package/src/runtime/confirm/confirm-subagent.ts +112 -0
  243. package/src/runtime/confirm/confirm-submit.ts +38 -0
  244. package/src/runtime/core-guards-active.ts +84 -0
  245. package/src/runtime/core-guards-wired.ts +47 -0
  246. package/src/runtime/deny-loop-store.ts +94 -0
  247. package/src/runtime/deny-notice.ts +52 -0
  248. package/src/runtime/design-cache-resolve.ts +51 -0
  249. package/src/runtime/design-content-gate.ts +95 -0
  250. package/src/runtime/design-files-gate.ts +114 -0
  251. package/src/runtime/design-helpers.ts +93 -0
  252. package/src/runtime/design-lifecycle.ts +39 -0
  253. package/src/runtime/design-read-credit.ts +28 -0
  254. package/src/runtime/design.ts +116 -0
  255. package/src/runtime/dev-context.ts +43 -0
  256. package/src/runtime/dry-patterns.ts +32 -0
  257. package/src/runtime/dry.ts +96 -0
  258. package/src/runtime/fragment-registry.ts +33 -0
  259. package/src/runtime/framework-skill-gate.ts +79 -0
  260. package/src/runtime/fs-cleanup.ts +71 -0
  261. package/src/runtime/gate-apex.ts +81 -0
  262. package/src/runtime/gate-helpers.ts +52 -0
  263. package/src/runtime/gate-input.ts +26 -0
  264. package/src/runtime/gate.ts +128 -0
  265. package/src/runtime/handle-post.ts +104 -0
  266. package/src/runtime/handle-pre.ts +137 -0
  267. package/src/runtime/handle-scope-async.ts +29 -0
  268. package/src/runtime/handle-types.ts +27 -0
  269. package/src/runtime/handle.ts +197 -0
  270. package/src/runtime/home-state.ts +55 -0
  271. package/src/runtime/index.ts +18 -0
  272. package/src/runtime/inform.ts +28 -0
  273. package/src/runtime/inject-budget-recap.ts +47 -0
  274. package/src/runtime/inject-budget.ts +81 -0
  275. package/src/runtime/inject-context.ts +85 -0
  276. package/src/runtime/inject-dedup-exclusive.ts +98 -0
  277. package/src/runtime/inject-dedup.ts +89 -0
  278. package/src/runtime/is-agent-tool.ts +19 -0
  279. package/src/runtime/lifecycle/agent-files.ts +49 -0
  280. package/src/runtime/lifecycle/agent-memory.ts +82 -0
  281. package/src/runtime/lifecycle/agent-transcript.ts +80 -0
  282. package/src/runtime/lifecycle/aipilot/analytics.ts +99 -0
  283. package/src/runtime/lifecycle/aipilot/apex-task-store.ts +61 -0
  284. package/src/runtime/lifecycle/aipilot/cache-base.ts +48 -0
  285. package/src/runtime/lifecycle/aipilot/cache-doc.ts +100 -0
  286. package/src/runtime/lifecycle/aipilot/cache-lessons.ts +58 -0
  287. package/src/runtime/lifecycle/aipilot/cache-test.ts +70 -0
  288. package/src/runtime/lifecycle/aipilot/curate-lessons.ts +64 -0
  289. package/src/runtime/lifecycle/aipilot/dispatch-aipilot.ts +106 -0
  290. package/src/runtime/lifecycle/aipilot/doc-cache-gate.ts +69 -0
  291. package/src/runtime/lifecycle/aipilot/inject-apex.ts +98 -0
  292. package/src/runtime/lifecycle/aipilot/inject-doc.ts +62 -0
  293. package/src/runtime/lifecycle/aipilot/inject-explore.ts +64 -0
  294. package/src/runtime/lifecycle/aipilot/inject-lessons.ts +61 -0
  295. package/src/runtime/lifecycle/aipilot/inject-test.ts +48 -0
  296. package/src/runtime/lifecycle/aipilot/lesson-archive.ts +60 -0
  297. package/src/runtime/lifecycle/aipilot/lesson-inject.ts +98 -0
  298. package/src/runtime/lifecycle/aipilot/lesson-parse.ts +74 -0
  299. package/src/runtime/lifecycle/aipilot/lessons.ts +72 -0
  300. package/src/runtime/lifecycle/aipilot/promote-global-lessons.ts +92 -0
  301. package/src/runtime/lifecycle/aipilot/solid-compliance.ts +69 -0
  302. package/src/runtime/lifecycle/aipilot/solid-notice.ts +47 -0
  303. package/src/runtime/lifecycle/aipilot/solid-transcript.ts +60 -0
  304. package/src/runtime/lifecycle/aipilot/source-scan.ts +56 -0
  305. package/src/runtime/lifecycle/aipilot/sync-task.ts +75 -0
  306. package/src/runtime/lifecycle/aipilot/transcript.ts +88 -0
  307. package/src/runtime/lifecycle/aipilot/types.ts +72 -0
  308. package/src/runtime/lifecycle/auto-document-reads.ts +73 -0
  309. package/src/runtime/lifecycle/cartographer/detect.ts +57 -0
  310. package/src/runtime/lifecycle/cartographer/ecosystem-map.ts +56 -0
  311. package/src/runtime/lifecycle/cartographer/fs-util.ts +64 -0
  312. package/src/runtime/lifecycle/cartographer/merge.ts +51 -0
  313. package/src/runtime/lifecycle/cartographer/project-map.ts +49 -0
  314. package/src/runtime/lifecycle/cartographer/scan-hooks.ts +48 -0
  315. package/src/runtime/lifecycle/cartographer/scan.ts +81 -0
  316. package/src/runtime/lifecycle/cartographer/session-start.ts +33 -0
  317. package/src/runtime/lifecycle/cartographer/track-enrichment.ts +45 -0
  318. package/src/runtime/lifecycle/cartographer/write-plugin-map.ts +43 -0
  319. package/src/runtime/lifecycle/cartographer/write-tree.ts +44 -0
  320. package/src/runtime/lifecycle/changelog-research.ts +43 -0
  321. package/src/runtime/lifecycle/check-file-size.ts +61 -0
  322. package/src/runtime/lifecycle/codex-resync/fingerprint.ts +63 -0
  323. package/src/runtime/lifecycle/codex-resync/lock.ts +46 -0
  324. package/src/runtime/lifecycle/codex-resync/managed-destination.ts +39 -0
  325. package/src/runtime/lifecycle/codex-resync/materialize-agents.ts +57 -0
  326. package/src/runtime/lifecycle/codex-resync/plugin-files.ts +65 -0
  327. package/src/runtime/lifecycle/codex-resync/plugin-roots.ts +62 -0
  328. package/src/runtime/lifecycle/codex-resync/resync.ts +45 -0
  329. package/src/runtime/lifecycle/codex-resync/symlink-commands.ts +25 -0
  330. package/src/runtime/lifecycle/dispatch.ts +109 -0
  331. package/src/runtime/lifecycle/failure-lesson.ts +55 -0
  332. package/src/runtime/lifecycle/index.ts +34 -0
  333. package/src/runtime/lifecycle/inject-rules.ts +50 -0
  334. package/src/runtime/lifecycle/instructions-loaded.ts +22 -0
  335. package/src/runtime/lifecycle/kimi-rules-native.ts +44 -0
  336. package/src/runtime/lifecycle/lessons/dispatch.ts +88 -0
  337. package/src/runtime/lifecycle/lessons/reminder.ts +89 -0
  338. package/src/runtime/lifecycle/lessons/state.ts +23 -0
  339. package/src/runtime/lifecycle/memory/agent-lesson.ts +35 -0
  340. package/src/runtime/lifecycle/memory/capture-error.ts +41 -0
  341. package/src/runtime/lifecycle/memory/client.ts +65 -0
  342. package/src/runtime/lifecycle/memory/dispatch.ts +42 -0
  343. package/src/runtime/lifecycle/memory/recall.ts +30 -0
  344. package/src/runtime/lifecycle/memory/salience.ts +31 -0
  345. package/src/runtime/lifecycle/memory/state.ts +49 -0
  346. package/src/runtime/lifecycle/memory/track-ops.ts +15 -0
  347. package/src/runtime/lifecycle/post-compact.ts +38 -0
  348. package/src/runtime/lifecycle/post-edit-ts.ts +49 -0
  349. package/src/runtime/lifecycle/post-tracking.ts +40 -0
  350. package/src/runtime/lifecycle/pre-compact.ts +38 -0
  351. package/src/runtime/lifecycle/rules-root.ts +99 -0
  352. package/src/runtime/lifecycle/security/check-skill.ts +63 -0
  353. package/src/runtime/lifecycle/security/scan-patterns.ts +53 -0
  354. package/src/runtime/lifecycle/security/scan.ts +76 -0
  355. package/src/runtime/lifecycle/security/skill-state.ts +47 -0
  356. package/src/runtime/lifecycle/security/track-mcp.ts +29 -0
  357. package/src/runtime/lifecycle/security/track-skill-read.ts +31 -0
  358. package/src/runtime/lifecycle/seo/post-tool-use.ts +45 -0
  359. package/src/runtime/lifecycle/session-end.ts +17 -0
  360. package/src/runtime/lifecycle/session-start.ts +57 -0
  361. package/src/runtime/lifecycle/snapshot/board.ts +27 -0
  362. package/src/runtime/lifecycle/snapshot/format.ts +60 -0
  363. package/src/runtime/lifecycle/snapshot/git.ts +71 -0
  364. package/src/runtime/lifecycle/snapshot/index.ts +52 -0
  365. package/src/runtime/lifecycle/snapshot/version.ts +34 -0
  366. package/src/runtime/lifecycle/solid-detect.ts +56 -0
  367. package/src/runtime/lifecycle/stop-core.ts +35 -0
  368. package/src/runtime/lifecycle/subagent-cache.ts +61 -0
  369. package/src/runtime/lifecycle/task-completed.ts +94 -0
  370. package/src/runtime/lifecycle/teammate-idle-check.ts +63 -0
  371. package/src/runtime/lifecycle/teammate-idle.ts +28 -0
  372. package/src/runtime/lifecycle/tool-failure.ts +24 -0
  373. package/src/runtime/lifecycle/track-changes.ts +61 -0
  374. package/src/runtime/lifecycle/validate-solid.ts +70 -0
  375. package/src/runtime/lifecycle/validate-tailwind.ts +80 -0
  376. package/src/runtime/lifecycle-bridge.ts +74 -0
  377. package/src/runtime/mcp-key.ts +44 -0
  378. package/src/runtime/mcp-tool-name.ts +92 -0
  379. package/src/runtime/mcp.ts +91 -0
  380. package/src/runtime/modular.ts +77 -0
  381. package/src/runtime/normalize.ts +107 -0
  382. package/src/runtime/notices.ts +91 -0
  383. package/src/runtime/notification-sound.ts +49 -0
  384. package/src/runtime/notifications.ts +77 -0
  385. package/src/runtime/paths.ts +59 -0
  386. package/src/runtime/post-fanout.ts +41 -0
  387. package/src/runtime/post-outcome.ts +61 -0
  388. package/src/runtime/pre-allow.ts +97 -0
  389. package/src/runtime/precommit.ts +60 -0
  390. package/src/runtime/prompt-text.ts +38 -0
  391. package/src/runtime/receipt-capture.ts +34 -0
  392. package/src/runtime/record.ts +26 -0
  393. package/src/runtime/respond.ts +92 -0
  394. package/src/runtime/solid-file-size-gate.ts +58 -0
  395. package/src/runtime/solid-pre.ts +53 -0
  396. package/src/runtime/storage.ts +9 -0
  397. package/src/statusline/colors.ts +31 -0
  398. package/src/statusline/constants.ts +17 -0
  399. package/src/statusline/formatters.ts +54 -0
  400. package/src/statusline/index.ts +4 -0
  401. package/src/statusline/progress-bar.ts +46 -0
  402. package/src/tracking/codex-post-failure.ts +73 -0
  403. package/src/tracking/index.ts +2 -0
  404. package/src/tracking/integrity.ts +99 -0
  405. package/src/tracking/one-shot-dedup.ts +34 -0
  406. package/src/tracking/one-shot-failure.ts +42 -0
  407. package/src/tracking/one-shot-store.ts +95 -0
  408. package/src/tracking/one-shot.ts +93 -0
  409. package/src/tracking/receipts.ts +95 -0
  410. package/src/tracking/session-state.ts +94 -0
  411. package/src/tracking/store.ts +96 -0
  412. package/src/tracking/track-compact.ts +100 -0
  413. package/src/tracking/track-diff.ts +50 -0
  414. package/src/tracking/track-journal.ts +97 -0
  415. package/src/tracking/track-lock-sync.ts +83 -0
  416. package/src/tracking/track-lock.ts +67 -0
  417. package/src/util/compact-json.ts +23 -0
  418. package/src/util/index.ts +2 -0
  419. package/src/util/json-io.ts +47 -0
  420. package/src/util/project-root.ts +41 -0
  421. package/src/util/runtime-io.ts +85 -0
  422. package/src/util/semver.ts +30 -0
@@ -0,0 +1,83 @@
1
+ type NumberState = "minus" | "zero" | "integer" | "dot" | "fraction" | "exponentMark" | "exponentSign" | "exponent";
2
+
3
+ /** Validate one JSON literal or number incrementally with constant state. */
4
+ export class JsonPrimitiveScanner {
5
+ private literal: "true" | "false" | "null" | undefined;
6
+ private literalIndex = 0;
7
+ private number: NumberState | undefined;
8
+ private valid = true;
9
+
10
+ constructor(firstByte: number) {
11
+ if (firstByte === 0x74) { this.literal = "true"; this.literalIndex = 1; }
12
+ else if (firstByte === 0x66) { this.literal = "false"; this.literalIndex = 1; }
13
+ else if (firstByte === 0x6e) { this.literal = "null"; this.literalIndex = 1; }
14
+ else if (firstByte === 0x2d) this.number = "minus";
15
+ else if (firstByte === 0x30) this.number = "zero";
16
+ else if (isOneToNine(firstByte)) this.number = "integer";
17
+ else this.valid = false;
18
+ }
19
+
20
+ /** Consume one non-delimiter byte and report whether the prefix stays valid. */
21
+ write(byte: number): boolean {
22
+ if (!this.valid) return false;
23
+ if (this.literal) {
24
+ this.valid = this.literal.charCodeAt(this.literalIndex) === byte;
25
+ this.literalIndex += 1;
26
+ return this.valid && this.literalIndex <= this.literal.length;
27
+ }
28
+ this.valid = this.writeNumber(byte);
29
+ return this.valid;
30
+ }
31
+
32
+ /** Return whether the accumulated primitive is complete JSON grammar. */
33
+ finish(): boolean {
34
+ if (!this.valid) return false;
35
+ if (this.literal) return this.literalIndex === this.literal.length;
36
+ return this.number === "zero" || this.number === "integer" || this.number === "fraction" || this.number === "exponent";
37
+ }
38
+
39
+ private writeNumber(byte: number): boolean {
40
+ if (this.number === "minus") return this.digitAfter(byte, "zero", "integer");
41
+ if (this.number === "zero") return this.afterInteger(byte, false);
42
+ if (this.number === "integer") {
43
+ if (isDigit(byte)) return true;
44
+ return this.afterInteger(byte, true);
45
+ }
46
+ if (this.number === "dot") {
47
+ if (!isDigit(byte)) return false;
48
+ this.number = "fraction";
49
+ return true;
50
+ }
51
+ if (this.number === "fraction") {
52
+ if (isDigit(byte)) return true;
53
+ return this.startExponent(byte);
54
+ }
55
+ if (this.number === "exponentMark") {
56
+ if (byte === 0x2b || byte === 0x2d) { this.number = "exponentSign"; return true; }
57
+ return this.digitAfter(byte, "exponent", "exponent");
58
+ }
59
+ if (this.number === "exponentSign") return this.digitAfter(byte, "exponent", "exponent");
60
+ return this.number === "exponent" && isDigit(byte);
61
+ }
62
+
63
+ private afterInteger(byte: number, digitAllowed: boolean): boolean {
64
+ if (digitAllowed && isDigit(byte)) return true;
65
+ if (byte === 0x2e) { this.number = "dot"; return true; }
66
+ return this.startExponent(byte);
67
+ }
68
+
69
+ private startExponent(byte: number): boolean {
70
+ if (byte !== 0x65 && byte !== 0x45) return false;
71
+ this.number = "exponentMark";
72
+ return true;
73
+ }
74
+
75
+ private digitAfter(byte: number, zero: NumberState, nonzero: NumberState): boolean {
76
+ if (byte === 0x30) { this.number = zero; return true; }
77
+ if (isOneToNine(byte)) { this.number = nonzero; return true; }
78
+ return false;
79
+ }
80
+ }
81
+
82
+ function isDigit(byte: number): boolean { return byte >= 0x30 && byte <= 0x39; }
83
+ function isOneToNine(byte: number): boolean { return byte >= 0x31 && byte <= 0x39; }
package/src/cli/run.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { evaluate } from "../policy/evaluate";
3
+ import { formatPrompt } from "../prompt/types";
4
+ import { isCodeFile } from "../util/project-root";
5
+
6
+ /** Staged files (Added/Copied/Modified/Renamed). Uses `node:child_process` (Bun shell can hang on `git show`). */
7
+ export function stagedFiles(): string[] {
8
+ const out = execFileSync("git", ["diff", "--cached", "--name-only", "--diff-filter=ACMR"], {
9
+ encoding: "utf8",
10
+ });
11
+ return out.trim().split("\n").filter(Boolean);
12
+ }
13
+
14
+ /**
15
+ * Read a file's staged (index) content — not the working-tree version.
16
+ * Uses `execFileSync` with an argv array (never a shell), so a staged
17
+ * filename containing shell metacharacters (backticks, `$(...)`, quotes)
18
+ * reaches `git show` as a single literal argument — see issue #87.
19
+ */
20
+ export function stagedContent(path: string): string {
21
+ return execFileSync("git", ["show", `:${path}`], { encoding: "utf8" });
22
+ }
23
+
24
+ /**
25
+ * Evaluate staged code files against the policy core; return violation blocks.
26
+ * `read` is injected (the real impl is {@link stagedContent}) so this is pure + testable.
27
+ */
28
+ export function checkStaged(files: string[], read: (path: string) => string): string[] {
29
+ const violations: string[] = [];
30
+ for (const file of files) {
31
+ if (!isCodeFile(file)) continue;
32
+ const r = evaluate({ tool: "Write", filePath: file, content: read(file) });
33
+ if (r.decision === "deny" && r.prompt) violations.push(`${file}\n${formatPrompt(r.prompt)}`);
34
+ }
35
+ return violations;
36
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * CLI scope argument parsing for `harness hook <id> [scope]`. The scope set is
3
+ * closed (plugin-scoped lifecycle behaviors); an unknown value historically
4
+ * fell back to `"core"` SILENTLY, which made a typo'd plugin name apply the
5
+ * core guards with no sign of the mistake. The fallback stays (wiring
6
+ * compatibility) but now warns on stderr — harnesses never parse stderr, so
7
+ * the wire contract is untouched.
8
+ */
9
+ import type { PluginScope } from "../runtime/lifecycle";
10
+
11
+ /** Closed set of plugin scopes accepted after `harness hook <id>`. */
12
+ const VALID_SCOPES = new Set<string>([
13
+ "solid", "rules", "carto", "security", "changelog",
14
+ "aipilot", "lessons", "seo", "memory", "tailwindcss",
15
+ ]);
16
+
17
+ /**
18
+ * Parse the optional scope argument.
19
+ * @param scopeArg - `process.argv[4]`, when present.
20
+ * @param err - Warning sink (defaults to stderr; injectable for tests).
21
+ * @returns The valid scope, or `"core"` (with a warning) otherwise.
22
+ */
23
+ export function parseScope(
24
+ scopeArg: string | undefined,
25
+ err: (msg: string) => void = (m) => process.stderr.write(m),
26
+ ): PluginScope {
27
+ if (scopeArg !== undefined && scopeArg !== "core" && !VALID_SCOPES.has(scopeArg)) {
28
+ err(`harness: unknown scope "${scopeArg}", falling back to "core"\n`);
29
+ }
30
+ return scopeArg !== undefined && VALID_SCOPES.has(scopeArg) ? (scopeArg as PluginScope) : "core";
31
+ }
@@ -0,0 +1,63 @@
1
+ import { ALL_RULES, SKIP_LIST } from "./mapping";
2
+ import { renderPrefixRules, sanitizeComment } from "./starlark";
3
+
4
+ const HEADER =
5
+ '# Codex execpolicy rules — generated from @fusengine/harness src/policy/guards/security.ts\n' +
6
+ "# DO NOT hand-edit: regenerate via `harness codex-rules`.\n" +
7
+ "#\n" +
8
+ "# security.ts is the source of truth for dangerous-command detection; every\n" +
9
+ '# CRITICAL_PATTERNS label maps to decision = "forbidden", every ASK_PATTERNS\n' +
10
+ '# label maps to decision = "prompt". Strictest decision wins across matches.\n' +
11
+ "# The harness remains the AUTHORITATIVE enforcement layer — this file is a\n" +
12
+ "# complementary defense layer on the Codex side, not a replacement.\n" +
13
+ "#\n" +
14
+ "# IRREDUCIBLE gaps (shell syntax, invisible to argv-prefix matching, no\n" +
15
+ "# prefix_rule can express them) — compensated by sandbox_mode +\n" +
16
+ "# approval_policy.granular.sandbox_approval, not by this file:\n" +
17
+ "# - fork bomb: `:(){ :|:& };:`\n" +
18
+ "# - redirect to a raw disk device: `> /dev/sda`\n" +
19
+ "# - write to /etc via redirection: `> /etc/...`\n" +
20
+ "#\n" +
21
+ "# ASSUMED over-width (intentionally broader than security.ts, chosen to\n" +
22
+ "# avoid a silent gap rather than an exact-but-brittle translation):\n" +
23
+ "# - dd: prompts on every dd invocation; security.ts only fires on of=/dev/*\n" +
24
+ "# - rm: prompts even on paths security.ts exempts via a 'trash' substring\n" +
25
+ "# - rm/eval/unlink: prompts even on a bare token with no trailing argument;\n" +
26
+ "# security.ts requires a space (i.e. an argument) after the command\n" +
27
+ "# - chmod 777: prompts on relative paths too, not only absolute ones\n" +
28
+ "# - sudo (/usr/bin/sudo alias): forbids the absolute-path form too;\n" +
29
+ "# security.ts's word-boundary regex does not match a preceding '/'\n" +
30
+ "# - curl/wget: prompts on EVERY curl/wget invocation, not only when piped\n" +
31
+ '# into a shell; security.ts\'s "remote script piped to a shell" label\n' +
32
+ "# only fires on `curl|wget ... | sh`. A simple plain-word pipe IS split\n" +
33
+ "# by Codex into separate argv commands (a bare-shell rule would also\n" +
34
+ "# catch that case), but this rule additionally targets the download\n" +
35
+ "# half for compound chains and non-shell payload execution where\n" +
36
+ "# sh/bash never appears as argv[0] (curl -o x && chmod +x x && ./x,\n" +
37
+ "# curl ... | python3); it replaces a former bare sh/bash/zsh heuristic\n" +
38
+ '# that prompted on ~50% of Codex\'s own `bash -lc "..."` command\n' +
39
+ "# wrapping and rarely caught the actual download\n" +
40
+ "#\n" +
41
+ "# NOT covered (out of scope, not an over-width — a purely local pipe with no\n" +
42
+ "# network fetch is invisible to this rule AND to security.ts, which only\n" +
43
+ "# matches curl/wget as the left-hand side of the pipe):\n" +
44
+ "# - `cat file | sh`: local pipe, no curl/wget involved\n" +
45
+ "# - quoted-variable/redirection installer one-liners, e.g.\n" +
46
+ '# `curl -fsSL "$URL" | sh`: variable substitution disables Codex\'s\n' +
47
+ "# pipe-splitting, collapsing the whole invocation to a single\n" +
48
+ "# ['bash', '-lc', '<script>'] where curl is not argv[0] — this exact\n" +
49
+ "# form was covered by the removed bare sh/bash heuristic and is no\n" +
50
+ "# longer covered by any rule here\n" +
51
+ "#\n" +
52
+ "# The following labels have NO argv-prefix equivalent at all (shell syntax\n" +
53
+ "# not visible to execpolicy's argv matching) and are intentionally NOT\n" +
54
+ "# expressed as prefix_rule() below — covered instead by sandbox_mode/approval_policy:";
55
+
56
+ /** Render the full Codex execpolicy `.rules` Starlark file as a string. */
57
+ export function buildCodexRules(): string {
58
+ const skipComment: string = SKIP_LIST.map(
59
+ (s) => `# - ${sanitizeComment(s.sourceLabel)}: ${sanitizeComment(s.reason)}`,
60
+ ).join("\n");
61
+ const body: string = renderPrefixRules(ALL_RULES);
62
+ return `${HEADER}\n${skipComment}\n\n${body}\n`;
63
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Codex execpolicy `.rules` (Starlark) generator, derived from the harness's
3
+ * own `security.ts` dangerous-command patterns. Pure, no I/O — see
4
+ * `../cli/bin.ts`'s `codex-rules` subcommand for stdout/`--out` wiring.
5
+ */
6
+ export { buildCodexRules } from "./build";
7
+ export { ALL_RULES, CRITICAL_RULES, ASK_RULES, SKIP_LIST } from "./mapping";
8
+ export type { CodexDecision, CodexPrefixRule, CodexSkipEntry } from "./types";
@@ -0,0 +1,42 @@
1
+ import type { CodexPrefixRule } from "./types";
2
+ import { RM_VARIANT_RULES } from "./rules/rm-variants";
3
+ import { MKFS_RULES } from "./rules/mkfs";
4
+ import { DISKUTIL_RULES } from "./rules/diskutil";
5
+ import { DD_RULES } from "./rules/dd";
6
+ import { SINGLE_COMMAND_RULES } from "./rules/single-commands";
7
+ import { PRIVILEGE_RULES } from "./rules/privilege";
8
+ import { ASK_RULES as BASE_ASK_RULES } from "./rules/ask";
9
+ import { CHMOD_ASK_RULES } from "./rules/chmod-ask";
10
+ import { REMOTE_FETCH_RULES } from "./rules/remote-fetch";
11
+ import { withAbsolutePathAliases } from "./rules/absolute-paths";
12
+ import { SKIP_LIST } from "./skip-list";
13
+
14
+ /** Every `decision = "forbidden"` rule, hand-mapped from CRITICAL_PATTERNS. */
15
+ const CRITICAL_BASE: CodexPrefixRule[] = [
16
+ ...RM_VARIANT_RULES,
17
+ ...MKFS_RULES,
18
+ ...DISKUTIL_RULES,
19
+ ...SINGLE_COMMAND_RULES,
20
+ ...PRIVILEGE_RULES,
21
+ ];
22
+
23
+ /** Every `decision = "prompt"` rule, hand-mapped from ASK_PATTERNS (+ dd, downgraded). */
24
+ const ASK_BASE: CodexPrefixRule[] = [...BASE_ASK_RULES, ...CHMOD_ASK_RULES, ...DD_RULES, ...REMOTE_FETCH_RULES];
25
+
26
+ /** Absolute-path mirrors of the bare-name rules above (see `rules/absolute-paths.ts`). */
27
+ const ABSOLUTE_ALIASES: CodexPrefixRule[] = withAbsolutePathAliases([...CRITICAL_BASE, ...ASK_BASE]);
28
+
29
+ export const CRITICAL_RULES: CodexPrefixRule[] = [
30
+ ...CRITICAL_BASE,
31
+ ...ABSOLUTE_ALIASES.filter((r) => r.decision === "forbidden"),
32
+ ];
33
+
34
+ export const ASK_RULES: CodexPrefixRule[] = [
35
+ ...ASK_BASE,
36
+ ...ABSOLUTE_ALIASES.filter((r) => r.decision === "prompt"),
37
+ ];
38
+
39
+ export { SKIP_LIST };
40
+
41
+ /** Every generated `prefix_rule`, critical (`forbidden`) + ask (`prompt`). */
42
+ export const ALL_RULES: CodexPrefixRule[] = [...CRITICAL_RULES, ...ASK_RULES];
@@ -0,0 +1,52 @@
1
+ import type { CodexPrefixRule } from "../types";
2
+
3
+ /**
4
+ * Absolute-path executable aliases — Codex only resolves an absolute path
5
+ * to its basename rule when the CLI is run with `--resolve-host-executables`
6
+ * (opt-in, off by default; this generated `.rules` file cannot assume it).
7
+ * `/bin/rm -rf /` and a bare `rm -rf /` are two DIFFERENT argv prefixes to
8
+ * execpolicy, so every rule keyed on one of these bare names is mirrored
9
+ * onto its common absolute-path forms.
10
+ */
11
+ const ABSOLUTE_PATH_ALIASES: Record<string, string[]> = {
12
+ rm: ["/bin/rm", "/usr/bin/rm"],
13
+ chmod: ["/bin/chmod", "/usr/bin/chmod"],
14
+ diskutil: ["/usr/sbin/diskutil"],
15
+ dd: ["/bin/dd", "/usr/bin/dd"],
16
+ sudo: ["/usr/bin/sudo"],
17
+ };
18
+
19
+ /** Escape regex metacharacters so a dynamic token can be safely embedded in a `RegExp` literal. */
20
+ function escapeRegExp(token: string): string {
21
+ return token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22
+ }
23
+
24
+ /** Replace a match/notMatch example's leading token with an absolute-path alias. */
25
+ function aliasExample(example: string, from: string, to: string): string {
26
+ return example.replace(new RegExp(`^${escapeRegExp(from)}\\b`), to);
27
+ }
28
+
29
+ /**
30
+ * Clone every rule in `rules` whose first pattern token has a known
31
+ * absolute-path alias, producing one variant per alias (same decision,
32
+ * same sourceLabel — traced back to the same `security.ts` label).
33
+ */
34
+ export function withAbsolutePathAliases(rules: CodexPrefixRule[]): CodexPrefixRule[] {
35
+ const out: CodexPrefixRule[] = [];
36
+ for (const rule of rules) {
37
+ const first = rule.pattern[0];
38
+ if (typeof first !== "string") continue;
39
+ const aliases = ABSOLUTE_PATH_ALIASES[first];
40
+ if (!aliases) continue;
41
+ for (const alias of aliases) {
42
+ out.push({
43
+ ...rule,
44
+ pattern: [alias, ...rule.pattern.slice(1)],
45
+ match: rule.match.map((m) => aliasExample(m, first, alias)),
46
+ notMatch: rule.notMatch?.map((m) => aliasExample(m, first, alias)),
47
+ justification: `${rule.justification} (absolute-path form; Codex does not resolve executable basenames by default).`,
48
+ });
49
+ }
50
+ }
51
+ return out;
52
+ }
@@ -0,0 +1,44 @@
1
+ import type { CodexPrefixRule } from "../types";
2
+
3
+ /**
4
+ * `prompt`-decision rules — hand-mapped 1:1 from `security.ts`'s
5
+ * ASK_PATTERNS. `DANGEROUS PATTERN: chmod 777` lives in `chmod-ask.ts`
6
+ * (needed multiple flag-order variants). `DANGEROUS PATTERN: write to /etc`
7
+ * is intentionally absent here: it fires on shell redirection
8
+ * (`> /etc/...`), which is not a single argv invocation — see
9
+ * `../skip-list.ts`.
10
+ */
11
+ export const ASK_RULES: CodexPrefixRule[] = [
12
+ {
13
+ sourceLabel: "DANGEROUS PATTERN: recursive chown",
14
+ pattern: ["chown", "-R"],
15
+ decision: "prompt",
16
+ justification: "Recursive ownership change; confirm scope.",
17
+ match: ["chown -R user:user /srv/app"],
18
+ notMatch: ["chown user file.txt"],
19
+ },
20
+ {
21
+ sourceLabel: "DANGEROUS PATTERN: eval",
22
+ pattern: ["eval"],
23
+ decision: "prompt",
24
+ justification: "Evaluates arbitrary shell input.",
25
+ match: ["eval $(cat script.sh)"],
26
+ notMatch: ["node eval.js"],
27
+ },
28
+ {
29
+ sourceLabel: "DELETE: 'rm' permanently deletes - confirmation required",
30
+ pattern: ["rm"],
31
+ decision: "prompt",
32
+ justification: "rm permanently deletes; confirm before running.",
33
+ match: ["rm file.txt"],
34
+ notMatch: ["rmdir empty"],
35
+ },
36
+ {
37
+ sourceLabel: "DELETE: 'unlink' command detected - confirmation required",
38
+ pattern: ["unlink"],
39
+ decision: "prompt",
40
+ justification: "unlink permanently removes a file; confirm before running.",
41
+ match: ["unlink file.txt"],
42
+ notMatch: ["ln -s a b"],
43
+ },
44
+ ];
@@ -0,0 +1,57 @@
1
+ import type { CodexPrefixRule } from "../types";
2
+
3
+ /**
4
+ * `chmod 777` `prompt`-decision variants — hand-mapped from `security.ts`'s
5
+ * `DANGEROUS PATTERN: chmod 777` ASK_PATTERNS label. The source regex
6
+ * accepts any chain of `-[a-zA-Z]+` flags before `777`; `prefix_rule` needs
7
+ * one literal-token variant per common flag order, so every frequent
8
+ * ordering is enumerated. Always `prompt`: `prefix_rule` cannot distinguish
9
+ * an absolute-path target from a relative one, so both are prompted rather
10
+ * than letting an absolute-path `chmod 777` fall through silently.
11
+ */
12
+ export const CHMOD_ASK_RULES: CodexPrefixRule[] = [
13
+ {
14
+ sourceLabel: "DANGEROUS PATTERN: chmod 777",
15
+ pattern: ["chmod", "777"],
16
+ decision: "prompt",
17
+ justification: "World-writable permissions; confirm the target is intended.",
18
+ match: ["chmod 777 file.txt", "chmod 777 /tmp/file"],
19
+ notMatch: ["chmod 755 file.txt"],
20
+ },
21
+ {
22
+ sourceLabel: "DANGEROUS PATTERN: chmod 777",
23
+ pattern: ["chmod", "-R", "777"],
24
+ decision: "prompt",
25
+ justification: "World-writable permissions, recursive; confirm the target is intended.",
26
+ match: ["chmod -R 777 dir"],
27
+ notMatch: ["chmod -R 755 dir"],
28
+ },
29
+ {
30
+ sourceLabel: "DANGEROUS PATTERN: chmod 777",
31
+ pattern: ["chmod", "-r", "777"],
32
+ decision: "prompt",
33
+ justification: "World-writable permissions, recursive (lowercase flag); confirm the target is intended.",
34
+ match: ["chmod -r 777 dir"],
35
+ },
36
+ {
37
+ sourceLabel: "DANGEROUS PATTERN: chmod 777",
38
+ pattern: ["chmod", "-v", "777"],
39
+ decision: "prompt",
40
+ justification: "World-writable permissions, verbose flag; confirm the target is intended.",
41
+ match: ["chmod -v 777 file.txt"],
42
+ },
43
+ {
44
+ sourceLabel: "DANGEROUS PATTERN: chmod 777",
45
+ pattern: ["chmod", "-Rv", "777"],
46
+ decision: "prompt",
47
+ justification: "World-writable permissions, combined recursive+verbose flags; confirm the target is intended.",
48
+ match: ["chmod -Rv 777 dir"],
49
+ },
50
+ {
51
+ sourceLabel: "DANGEROUS PATTERN: chmod 777",
52
+ pattern: ["chmod", "-vR", "777"],
53
+ decision: "prompt",
54
+ justification: "World-writable permissions, combined verbose+recursive flags; confirm the target is intended.",
55
+ match: ["chmod -vR 777 dir"],
56
+ },
57
+ ];
@@ -0,0 +1,23 @@
1
+ import type { CodexPrefixRule } from "../types";
2
+
3
+ /**
4
+ * `dd` — hand-mapped from `security.ts`'s `CRITICAL: Detected dangerous
5
+ * command 'dd if='` label (source regex only fires on `of=/dev/...`).
6
+ * Owner decision: DOWNGRADE forbidden -> prompt. `prefix_rule` cannot
7
+ * glob-match a `key=value` argv token against a raw-device path, so a
8
+ * literal forbidden translation would silently block legitimate
9
+ * `dd if=a.img of=b.img` usage — prompting on every `dd` invocation instead
10
+ * never lets a raw-disk write through silently, without blocking safe use.
11
+ */
12
+ export const DD_RULES: CodexPrefixRule[] = [
13
+ {
14
+ sourceLabel: "CRITICAL: Detected dangerous command 'dd if='",
15
+ pattern: ["dd"],
16
+ decision: "prompt",
17
+ justification:
18
+ "dd can overwrite a raw block device via of=/dev/...; prompts on every dd invocation " +
19
+ "(broader than security.ts, which only fires on of=/dev/*) because execpolicy cannot " +
20
+ "glob-match that argv token — owner decision: do not block legitimate dd usage.",
21
+ match: ["dd if=/dev/zero of=/dev/sda", "dd if=a.img of=b.img"],
22
+ },
23
+ ];
@@ -0,0 +1,33 @@
1
+ import type { CodexPrefixRule } from "../types";
2
+
3
+ /**
4
+ * `diskutil` erase/partition variants — hand-mapped from `security.ts`'s
5
+ * case-insensitive `\bdiskutil\s+(?:erase|partitionDisk)\b/i` CRITICAL
6
+ * label. `prefix_rule` has no case-insensitive matching, so every real
7
+ * casing macOS users actually type (camelCase, all-lowercase, all-caps) is
8
+ * enumerated explicitly as an alternation at position 1.
9
+ */
10
+ export const DISKUTIL_RULES: CodexPrefixRule[] = [
11
+ {
12
+ sourceLabel: "CRITICAL: Detected dangerous command 'diskutil erase'",
13
+ pattern: [
14
+ "diskutil",
15
+ [
16
+ "erase",
17
+ "eraseDisk",
18
+ "erasedisk",
19
+ "ERASEDISK",
20
+ "eraseVolume",
21
+ "erasevolume",
22
+ "ERASEVOLUME",
23
+ "partitionDisk",
24
+ "partitiondisk",
25
+ "PARTITIONDISK",
26
+ ],
27
+ ],
28
+ decision: "forbidden",
29
+ justification: "Erases or repartitions a macOS disk/volume (case-variant enumeration; execpolicy has no case-insensitive match).",
30
+ match: ["diskutil eraseDisk /dev/disk2", "diskutil ERASEDISK /dev/disk2", "diskutil erase /dev/disk2"],
31
+ notMatch: ["diskutil list"],
32
+ },
33
+ ];
@@ -0,0 +1,42 @@
1
+ import type { CodexPrefixRule } from "../types";
2
+
3
+ /**
4
+ * `mkfs` filesystem-formatting variants — hand-mapped from `security.ts`'s
5
+ * `\bmkfs(?:\.[a-z0-9]+)?\b` CRITICAL_PATTERNS label. The source regex
6
+ * accepts ANY `.suffix`; `prefix_rule` cannot express an open-ended suffix,
7
+ * so every real-world `mkfs.*` filesystem type is enumerated explicitly as
8
+ * an alternation at position 0 (exhaustive, not a mechanical derivation).
9
+ */
10
+ export const MKFS_RULES: CodexPrefixRule[] = [
11
+ {
12
+ sourceLabel: "CRITICAL: Detected dangerous command 'mkfs'",
13
+ pattern: [
14
+ [
15
+ "mkfs",
16
+ "mkfs.ext2",
17
+ "mkfs.ext3",
18
+ "mkfs.ext4",
19
+ "mkfs.xfs",
20
+ "mkfs.btrfs",
21
+ "mkfs.exfat",
22
+ "mkfs.vfat",
23
+ "mkfs.fat",
24
+ "mkfs.ntfs",
25
+ "mkfs.f2fs",
26
+ "mkfs.hfsplus",
27
+ "mkfs.apfs",
28
+ "mkfs.msdos",
29
+ "mkfs.minix",
30
+ "mkfs.jfs",
31
+ "mkfs.reiserfs",
32
+ "mkfs.udf",
33
+ "mkfs.bfs",
34
+ "mkfs.cramfs",
35
+ ],
36
+ ],
37
+ decision: "forbidden",
38
+ justification: "Formats a block device, destroying its contents (exhaustive mkfs.* variant enumeration).",
39
+ match: ["mkfs.exfat /dev/sda1", "mkfs.f2fs /dev/sdb1", "mkfs /dev/sdb1", "mkfs.ext4 /dev/sda1"],
40
+ notMatch: ["ls /dev"],
41
+ },
42
+ ];
@@ -0,0 +1,49 @@
1
+ import type { CodexPrefixRule } from "../types";
2
+
3
+ /**
4
+ * Privilege-escalation binaries — hand-mapped 1:1 from `security.ts`'s
5
+ * `sudo`/`su`/`doas`/`passwd`/`del` CRITICAL_PATTERNS labels (parity
6
+ * `security_rules.PRIVILEGE_COMMANDS`).
7
+ */
8
+ export const PRIVILEGE_RULES: CodexPrefixRule[] = [
9
+ {
10
+ sourceLabel: "PRIVILEGE ESCALATION: sudo",
11
+ pattern: ["sudo"],
12
+ decision: "forbidden",
13
+ justification: "Runs a command with elevated privileges.",
14
+ match: ["sudo rm -rf /tmp"],
15
+ notMatch: ["echo sudo"],
16
+ },
17
+ {
18
+ sourceLabel: "PRIVILEGE ESCALATION: su",
19
+ pattern: ["su"],
20
+ decision: "forbidden",
21
+ justification: "Switches to another user, typically root.",
22
+ match: ["su -", "su root"],
23
+ notMatch: ["sudo ls"],
24
+ },
25
+ {
26
+ sourceLabel: "PRIVILEGE ESCALATION: doas",
27
+ pattern: ["doas"],
28
+ decision: "forbidden",
29
+ justification: "BSD-style sudo alternative for elevated privileges.",
30
+ match: ["doas reboot"],
31
+ notMatch: ["ls"],
32
+ },
33
+ {
34
+ sourceLabel: "PRIVILEGE ESCALATION: passwd",
35
+ pattern: ["passwd"],
36
+ decision: "forbidden",
37
+ justification: "Changes a user's password.",
38
+ match: ["passwd root"],
39
+ notMatch: ["cat /etc/passwd"],
40
+ },
41
+ {
42
+ sourceLabel: "CRITICAL: Detected dangerous command 'del'",
43
+ pattern: ["del"],
44
+ decision: "forbidden",
45
+ justification: "Windows-style file deletion (parity security_rules.CRITICAL_COMMANDS).",
46
+ match: ["del file.txt"],
47
+ notMatch: ["delete.sh"],
48
+ },
49
+ ];
@@ -0,0 +1,31 @@
1
+ import type { CodexPrefixRule } from "../types";
2
+
3
+ /**
4
+ * Remote-fetch tools (`curl`/`wget`) — targets the DOWNLOAD half of a
5
+ * `curl ... | sh` pipe instead of the shell half. Codex splits a piped
6
+ * command into independent argv segments at the pipe, so a `prefix_rule`
7
+ * anchored on `curl`/`wget` catches the attack regardless of which shell
8
+ * receives the piped output on the other side — unlike a bare-shell rule
9
+ * (`sh`/`bash`/`zsh`), which prompts on EVERY Codex-issued `bash -lc "..."`
10
+ * wrapper (Codex wraps essentially all shell commands this way), producing
11
+ * noise on ~50% of legitimate day-to-day work. Owner decision: DOWNGRADE
12
+ * forbidden -> prompt, same rationale as `dd.ts` — `prefix_rule` cannot see
13
+ * the pipe operator itself, so it cannot distinguish a bare `curl url`
14
+ * fetch from `curl url | sh`; prompting on every curl/wget invocation never
15
+ * lets the attack through silently, without blocking legitimate downloads.
16
+ */
17
+ export const REMOTE_FETCH_RULES: CodexPrefixRule[] = [
18
+ {
19
+ sourceLabel: "DANGEROUS PATTERN: remote script piped to a shell",
20
+ pattern: [["curl", "wget"]],
21
+ decision: "prompt",
22
+ justification:
23
+ "Remote fetch; piping its output into a shell executes untrusted code. Broader than " +
24
+ "security.ts (which only fires when the fetch is piped into sh/bash/zsh): prompts on " +
25
+ "every curl/wget invocation because execpolicy cannot see the pipe operator, i.e. it " +
26
+ "cannot distinguish `curl url` from `curl url | sh` — owner decision: do not block " +
27
+ "legitimate curl/wget usage.",
28
+ match: ["curl http://example.com/i.sh", "wget http://example.com/i.sh", "curl -fsSL http://example.com/i.sh"],
29
+ notMatch: ["cursor --version", "widget-tool build"],
30
+ },
31
+ ];