@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.
- package/dist/adapters/claude/index.d.mts +1 -1
- package/dist/adapters/claude/index.mjs +1 -1
- package/dist/adapters/cline/index.mjs +1 -1
- package/dist/adapters/codex/index.d.mts +2 -2
- package/dist/adapters/codex/index.mjs +3 -2
- package/dist/adapters/cursor/index.d.mts +15 -28
- package/dist/adapters/cursor/index.mjs +35 -46
- package/dist/adapters/gemini/index.mjs +1 -1
- package/dist/adapters/hermes/index.d.mts +1 -1
- package/dist/adapters/hermes/index.mjs +1 -1
- package/dist/adapters/kimi/index.d.mts +1 -1
- package/dist/adapters/kimi/index.mjs +1 -1
- package/dist/{claude-5bC8TDAz.mjs → claude-Ckv2_TgP.mjs} +3 -43
- package/dist/cli/bin.mjs +429 -16
- package/dist/cli/index.mjs +1 -1
- package/dist/command-string-CALMTnwN.mjs +42 -0
- package/dist/{evaluate-C1VSI5pb.mjs → evaluate-CMiIqHeH.mjs} +261 -13
- package/dist/{handle-CBaOcFZq.mjs → handle-BF1dZFjY.mjs} +1194 -144
- package/dist/{hermes-kP6NUQlG.mjs → hermes-B9-p_3IF.mjs} +3 -2
- package/dist/{index-DBgnIZn9.d.mts → index-B8PG82su.d.mts} +1 -1
- package/dist/{index-D4C2-IIc.d.mts → index-SmKYkk2N.d.mts} +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/init/index.d.mts +1 -1
- package/dist/init/index.mjs +1 -1
- package/dist/{kimi-D6X7b8wF.mjs → kimi-G2wcSh5-.mjs} +3 -2
- package/dist/normalize-Dy8g9Ybl.mjs +397 -0
- package/dist/policy/index.d.mts +1 -1
- package/dist/policy/index.mjs +2 -2
- package/dist/prompt/index.d.mts +1 -1
- package/dist/{run-CdIlUtjv.mjs → run-DkrzC0gb.mjs} +1 -1
- package/dist/{run-TAXNRSpD.mjs → run-GHAMqcOn.mjs} +26 -3
- package/dist/runtime/index.d.mts +37 -16
- package/dist/runtime/index.mjs +2 -2
- package/dist/{types-C0-igRKr.d.mts → types-Bh0jEF3_.d.mts} +2 -0
- package/dist/{validate-DZFtAbLP.mjs → validate-KjZ1X9tH.mjs} +1 -1
- package/package.json +3 -2
- package/src/adapters/claude/index.ts +92 -0
- package/src/adapters/cline/index.ts +36 -0
- package/src/adapters/codex/apply-patch.ts +94 -0
- package/src/adapters/codex/index.ts +84 -0
- package/src/adapters/codex/permission-mode.ts +16 -0
- package/src/adapters/cursor/context-budget.ts +144 -0
- package/src/adapters/cursor/context-limit.ts +115 -0
- package/src/adapters/cursor/context.ts +65 -0
- package/src/adapters/cursor/events.ts +38 -0
- package/src/adapters/cursor/index.ts +43 -0
- package/src/adapters/cursor/interfaces/context-budget.ts +25 -0
- package/src/adapters/cursor/interfaces/types.ts +88 -0
- package/src/adapters/cursor/native-response.ts +39 -0
- package/src/adapters/cursor/native-schemas.ts +161 -0
- package/src/adapters/cursor/normalize.ts +188 -0
- package/src/adapters/cursor/plugin-root.ts +103 -0
- package/src/adapters/cursor/respond.ts +170 -0
- package/src/adapters/gemini/index.ts +36 -0
- package/src/adapters/hermes/index.ts +55 -0
- package/src/adapters/hermes/interfaces/types.ts +26 -0
- package/src/adapters/kimi/index.ts +96 -0
- package/src/adapters/kimi/interfaces/types.ts +55 -0
- package/src/cache/compact.ts +55 -0
- package/src/cache/index.ts +5 -0
- package/src/cache/io.ts +38 -0
- package/src/cache/mcp-response.ts +39 -0
- package/src/cache/mcp-store.ts +70 -0
- package/src/cache/store.ts +93 -0
- package/src/changelog/fetch.ts +79 -0
- package/src/cli/bin.ts +100 -0
- package/src/cli/cursor-event-scanner.ts +175 -0
- package/src/cli/cursor-stdin-reader.ts +65 -0
- package/src/cli/doctor.ts +96 -0
- package/src/cli/hook-io.ts +130 -0
- package/src/cli/hook-sound.ts +49 -0
- package/src/cli/index.ts +1 -0
- package/src/cli/json-primitive-scanner.ts +83 -0
- package/src/cli/run.ts +36 -0
- package/src/cli/scope.ts +31 -0
- package/src/codex-rules/build.ts +63 -0
- package/src/codex-rules/index.ts +8 -0
- package/src/codex-rules/mapping.ts +42 -0
- package/src/codex-rules/rules/absolute-paths.ts +52 -0
- package/src/codex-rules/rules/ask.ts +44 -0
- package/src/codex-rules/rules/chmod-ask.ts +57 -0
- package/src/codex-rules/rules/dd.ts +23 -0
- package/src/codex-rules/rules/diskutil.ts +33 -0
- package/src/codex-rules/rules/mkfs.ts +42 -0
- package/src/codex-rules/rules/privilege.ts +49 -0
- package/src/codex-rules/rules/remote-fetch.ts +31 -0
- package/src/codex-rules/rules/rm-variants.ts +58 -0
- package/src/codex-rules/rules/single-commands.ts +57 -0
- package/src/codex-rules/skip-list.ts +25 -0
- package/src/codex-rules/starlark.ts +46 -0
- package/src/codex-rules/types.ts +36 -0
- package/src/config/dotenv.ts +55 -0
- package/src/config/env.ts +10 -0
- package/src/config/home-dir.ts +36 -0
- package/src/config/index.ts +5 -0
- package/src/config/layout.ts +52 -0
- package/src/config/limits.ts +56 -0
- package/src/config/ttl.ts +30 -0
- package/src/detect/harness.ts +73 -0
- package/src/detect/index.ts +1 -0
- package/src/detect/interfaces/types.ts +18 -0
- package/src/freshness/agent-evidence-record.ts +95 -0
- package/src/freshness/agent-evidence.ts +95 -0
- package/src/freshness/codex-spawn-evidence.ts +91 -0
- package/src/freshness/doc-helpers.ts +90 -0
- package/src/freshness/evidence-harvest-io.ts +72 -0
- package/src/freshness/evidence-harvest.ts +61 -0
- package/src/freshness/explore-tools.ts +95 -0
- package/src/freshness/index.ts +2 -0
- package/src/freshness/query-framework.ts +73 -0
- package/src/freshness/ref-evidence.ts +49 -0
- package/src/freshness/ref-journal.ts +98 -0
- package/src/freshness/trivial-edit-counter.ts +30 -0
- package/src/index.ts +11 -0
- package/src/init/index.ts +2 -0
- package/src/init/run.ts +32 -0
- package/src/init/templates.ts +75 -0
- package/src/memory/gitignore.ts +14 -0
- package/src/memory/index.ts +3 -0
- package/src/memory/registry.ts +39 -0
- package/src/memory/session-roots.ts +99 -0
- package/src/memory/state.ts +58 -0
- package/src/policy/apex-authorization.ts +100 -0
- package/src/policy/apex-gates.ts +91 -0
- package/src/policy/apex-target-steps.ts +73 -0
- package/src/policy/apex-target.ts +49 -0
- package/src/policy/apex-task-context.ts +81 -0
- package/src/policy/apex.ts +94 -0
- package/src/policy/cartographer/build-tree.ts +69 -0
- package/src/policy/cartographer/describe.ts +53 -0
- package/src/policy/cartographer/entry.ts +38 -0
- package/src/policy/cartographer/frontmatter.ts +48 -0
- package/src/policy/cartographer/indicators.ts +34 -0
- package/src/policy/claude-md-context.ts +66 -0
- package/src/policy/conventions/index.ts +11 -0
- package/src/policy/conventions/interfaces.ts +71 -0
- package/src/policy/conventions/langs.ts +53 -0
- package/src/policy/conventions/query.ts +49 -0
- package/src/policy/conventions/react-hooks.ts +18 -0
- package/src/policy/conventions/store-or-query.ts +21 -0
- package/src/policy/conventions/stores.ts +56 -0
- package/src/policy/conventions/strip.ts +87 -0
- package/src/policy/conventions/verdict.ts +38 -0
- package/src/policy/creation-intent.ts +11 -0
- package/src/policy/deny-loop.ts +88 -0
- package/src/policy/design/allowed-write.ts +28 -0
- package/src/policy/design/content-checks.ts +45 -0
- package/src/policy/design/corpus-fs.ts +21 -0
- package/src/policy/design/corpus-resolve-cache.ts +49 -0
- package/src/policy/design/corpus-resolve.ts +99 -0
- package/src/policy/design/corpus.ts +92 -0
- package/src/policy/design/design-system-rules.ts +45 -0
- package/src/policy/design/flag.ts +30 -0
- package/src/policy/design/gates-pipeline.ts +105 -0
- package/src/policy/design/gates.ts +87 -0
- package/src/policy/design/screenshot-tools.ts +24 -0
- package/src/policy/design/skill-evidence.ts +34 -0
- package/src/policy/design/skill-gate.ts +81 -0
- package/src/policy/design/skill-triggers.ts +51 -0
- package/src/policy/design/state.ts +92 -0
- package/src/policy/design/template-urls.ts +54 -0
- package/src/policy/design/transitions.ts +68 -0
- package/src/policy/detect-claude-md-project-type.ts +32 -0
- package/src/policy/detect-framework.ts +99 -0
- package/src/policy/detect-primitive-checks.ts +100 -0
- package/src/policy/detect-primitive-lib.ts +55 -0
- package/src/policy/detect-project.ts +99 -0
- package/src/policy/edit-outcome.ts +53 -0
- package/src/policy/evaluate.ts +81 -0
- package/src/policy/expert-agents.ts +60 -0
- package/src/policy/file-size-scope.ts +32 -0
- package/src/policy/file-size.ts +99 -0
- package/src/policy/framework-solid-exclude.ts +52 -0
- package/src/policy/framework-solid-extended.ts +93 -0
- package/src/policy/framework-solid-gates-systems.ts +99 -0
- package/src/policy/framework-solid-gates.ts +98 -0
- package/src/policy/framework-solid.ts +88 -0
- package/src/policy/gemini-mcp-gate.ts +83 -0
- package/src/policy/git-gates.ts +40 -0
- package/src/policy/guards/bash-command-anchor.ts +40 -0
- package/src/policy/guards/bash-write-patterns.ts +140 -0
- package/src/policy/guards/bash-write-redirects.ts +201 -0
- package/src/policy/guards/bash-write-safe-paths.ts +62 -0
- package/src/policy/guards/bash-write.ts +76 -0
- package/src/policy/guards/context.ts +12 -0
- package/src/policy/guards/index.ts +61 -0
- package/src/policy/guards/install.ts +22 -0
- package/src/policy/guards/interface-separation-ext.ts +41 -0
- package/src/policy/guards/interface-separation.ts +100 -0
- package/src/policy/guards/protected-path.ts +100 -0
- package/src/policy/guards/security.ts +97 -0
- package/src/policy/index.ts +19 -0
- package/src/policy/interfaces/types.ts +46 -0
- package/src/policy/js-gate-route.ts +51 -0
- package/src/policy/lessons/lesson-gate.ts +0 -0
- package/src/policy/lessons/trigger-index.ts +84 -0
- package/src/policy/lessons/types.ts +31 -0
- package/src/policy/module-layout.ts +31 -0
- package/src/policy/nearest-manifest.ts +75 -0
- package/src/policy/never-approval.ts +95 -0
- package/src/policy/patterns.ts +80 -0
- package/src/policy/seo/validate.ts +51 -0
- package/src/policy/shadcn-project.ts +22 -0
- package/src/policy/shadcn-skill-gate.ts +97 -0
- package/src/policy/shell-read-refs.ts +96 -0
- package/src/policy/skill-path.ts +46 -0
- package/src/policy/skill-patterns/laravel.ts +40 -0
- package/src/policy/skill-patterns/nextjs.ts +29 -0
- package/src/policy/skill-patterns/react.ts +27 -0
- package/src/policy/skill-patterns/shadcn-subskills.ts +33 -0
- package/src/policy/skill-patterns/shadcn.ts +66 -0
- package/src/policy/skill-patterns/swift.ts +30 -0
- package/src/policy/skill-patterns/tailwind.ts +40 -0
- package/src/policy/skill-source.ts +52 -0
- package/src/policy/skill-trigger-patterns.ts +33 -0
- package/src/policy/skill-triggers.ts +108 -0
- package/src/policy/tailwind-skill-gate.ts +63 -0
- package/src/policy/trivial-edits.ts +52 -0
- package/src/policy/verbosity.ts +39 -0
- package/src/prompt/index.ts +1 -0
- package/src/prompt/types.ts +36 -0
- package/src/refs/discover.ts +69 -0
- package/src/refs/frontmatter.ts +24 -0
- package/src/refs/index.ts +4 -0
- package/src/refs/loader.ts +59 -0
- package/src/refs/ref-key.ts +41 -0
- package/src/refs/router.ts +63 -0
- package/src/refs/types.ts +25 -0
- package/src/runtime/activity.ts +99 -0
- package/src/runtime/apply-patch-gate.ts +41 -0
- package/src/runtime/burst-window.ts +21 -0
- package/src/runtime/codex-shell-tool.ts +37 -0
- package/src/runtime/command-string.ts +37 -0
- package/src/runtime/confirm/codex-confirm.ts +126 -0
- package/src/runtime/confirm/codex-prompt-origin.ts +16 -0
- package/src/runtime/confirm/confirm-code.ts +33 -0
- package/src/runtime/confirm/confirm-gate.ts +65 -0
- package/src/runtime/confirm/confirm-irreversible.ts +32 -0
- package/src/runtime/confirm/confirm-pending.ts +34 -0
- package/src/runtime/confirm/confirm-state.ts +56 -0
- package/src/runtime/confirm/confirm-subagent.ts +112 -0
- package/src/runtime/confirm/confirm-submit.ts +38 -0
- package/src/runtime/core-guards-active.ts +84 -0
- package/src/runtime/core-guards-wired.ts +47 -0
- package/src/runtime/deny-loop-store.ts +94 -0
- package/src/runtime/deny-notice.ts +52 -0
- package/src/runtime/design-cache-resolve.ts +51 -0
- package/src/runtime/design-content-gate.ts +95 -0
- package/src/runtime/design-files-gate.ts +114 -0
- package/src/runtime/design-helpers.ts +93 -0
- package/src/runtime/design-lifecycle.ts +39 -0
- package/src/runtime/design-read-credit.ts +28 -0
- package/src/runtime/design.ts +116 -0
- package/src/runtime/dev-context.ts +43 -0
- package/src/runtime/dry-patterns.ts +32 -0
- package/src/runtime/dry.ts +96 -0
- package/src/runtime/fragment-registry.ts +33 -0
- package/src/runtime/framework-skill-gate.ts +79 -0
- package/src/runtime/fs-cleanup.ts +71 -0
- package/src/runtime/gate-apex.ts +81 -0
- package/src/runtime/gate-helpers.ts +52 -0
- package/src/runtime/gate-input.ts +26 -0
- package/src/runtime/gate.ts +128 -0
- package/src/runtime/handle-post.ts +104 -0
- package/src/runtime/handle-pre.ts +137 -0
- package/src/runtime/handle-scope-async.ts +29 -0
- package/src/runtime/handle-types.ts +27 -0
- package/src/runtime/handle.ts +197 -0
- package/src/runtime/home-state.ts +55 -0
- package/src/runtime/index.ts +18 -0
- package/src/runtime/inform.ts +28 -0
- package/src/runtime/inject-budget-recap.ts +47 -0
- package/src/runtime/inject-budget.ts +81 -0
- package/src/runtime/inject-context.ts +85 -0
- package/src/runtime/inject-dedup-exclusive.ts +98 -0
- package/src/runtime/inject-dedup.ts +89 -0
- package/src/runtime/is-agent-tool.ts +19 -0
- package/src/runtime/lifecycle/agent-files.ts +49 -0
- package/src/runtime/lifecycle/agent-memory.ts +82 -0
- package/src/runtime/lifecycle/agent-transcript.ts +80 -0
- package/src/runtime/lifecycle/aipilot/analytics.ts +99 -0
- package/src/runtime/lifecycle/aipilot/apex-task-store.ts +61 -0
- package/src/runtime/lifecycle/aipilot/cache-base.ts +48 -0
- package/src/runtime/lifecycle/aipilot/cache-doc.ts +100 -0
- package/src/runtime/lifecycle/aipilot/cache-lessons.ts +58 -0
- package/src/runtime/lifecycle/aipilot/cache-test.ts +70 -0
- package/src/runtime/lifecycle/aipilot/curate-lessons.ts +64 -0
- package/src/runtime/lifecycle/aipilot/dispatch-aipilot.ts +106 -0
- package/src/runtime/lifecycle/aipilot/doc-cache-gate.ts +69 -0
- package/src/runtime/lifecycle/aipilot/inject-apex.ts +98 -0
- package/src/runtime/lifecycle/aipilot/inject-doc.ts +62 -0
- package/src/runtime/lifecycle/aipilot/inject-explore.ts +64 -0
- package/src/runtime/lifecycle/aipilot/inject-lessons.ts +61 -0
- package/src/runtime/lifecycle/aipilot/inject-test.ts +48 -0
- package/src/runtime/lifecycle/aipilot/lesson-archive.ts +60 -0
- package/src/runtime/lifecycle/aipilot/lesson-inject.ts +98 -0
- package/src/runtime/lifecycle/aipilot/lesson-parse.ts +74 -0
- package/src/runtime/lifecycle/aipilot/lessons.ts +72 -0
- package/src/runtime/lifecycle/aipilot/promote-global-lessons.ts +92 -0
- package/src/runtime/lifecycle/aipilot/solid-compliance.ts +69 -0
- package/src/runtime/lifecycle/aipilot/solid-notice.ts +47 -0
- package/src/runtime/lifecycle/aipilot/solid-transcript.ts +60 -0
- package/src/runtime/lifecycle/aipilot/source-scan.ts +56 -0
- package/src/runtime/lifecycle/aipilot/sync-task.ts +75 -0
- package/src/runtime/lifecycle/aipilot/transcript.ts +88 -0
- package/src/runtime/lifecycle/aipilot/types.ts +72 -0
- package/src/runtime/lifecycle/auto-document-reads.ts +73 -0
- package/src/runtime/lifecycle/cartographer/detect.ts +57 -0
- package/src/runtime/lifecycle/cartographer/ecosystem-map.ts +56 -0
- package/src/runtime/lifecycle/cartographer/fs-util.ts +64 -0
- package/src/runtime/lifecycle/cartographer/merge.ts +51 -0
- package/src/runtime/lifecycle/cartographer/project-map.ts +49 -0
- package/src/runtime/lifecycle/cartographer/scan-hooks.ts +48 -0
- package/src/runtime/lifecycle/cartographer/scan.ts +81 -0
- package/src/runtime/lifecycle/cartographer/session-start.ts +33 -0
- package/src/runtime/lifecycle/cartographer/track-enrichment.ts +45 -0
- package/src/runtime/lifecycle/cartographer/write-plugin-map.ts +43 -0
- package/src/runtime/lifecycle/cartographer/write-tree.ts +44 -0
- package/src/runtime/lifecycle/changelog-research.ts +43 -0
- package/src/runtime/lifecycle/check-file-size.ts +61 -0
- package/src/runtime/lifecycle/codex-resync/fingerprint.ts +63 -0
- package/src/runtime/lifecycle/codex-resync/lock.ts +46 -0
- package/src/runtime/lifecycle/codex-resync/managed-destination.ts +39 -0
- package/src/runtime/lifecycle/codex-resync/materialize-agents.ts +57 -0
- package/src/runtime/lifecycle/codex-resync/plugin-files.ts +65 -0
- package/src/runtime/lifecycle/codex-resync/plugin-roots.ts +62 -0
- package/src/runtime/lifecycle/codex-resync/resync.ts +45 -0
- package/src/runtime/lifecycle/codex-resync/symlink-commands.ts +25 -0
- package/src/runtime/lifecycle/dispatch.ts +109 -0
- package/src/runtime/lifecycle/failure-lesson.ts +55 -0
- package/src/runtime/lifecycle/index.ts +34 -0
- package/src/runtime/lifecycle/inject-rules.ts +50 -0
- package/src/runtime/lifecycle/instructions-loaded.ts +22 -0
- package/src/runtime/lifecycle/kimi-rules-native.ts +44 -0
- package/src/runtime/lifecycle/lessons/dispatch.ts +88 -0
- package/src/runtime/lifecycle/lessons/reminder.ts +89 -0
- package/src/runtime/lifecycle/lessons/state.ts +23 -0
- package/src/runtime/lifecycle/memory/agent-lesson.ts +35 -0
- package/src/runtime/lifecycle/memory/capture-error.ts +41 -0
- package/src/runtime/lifecycle/memory/client.ts +65 -0
- package/src/runtime/lifecycle/memory/dispatch.ts +42 -0
- package/src/runtime/lifecycle/memory/recall.ts +30 -0
- package/src/runtime/lifecycle/memory/salience.ts +31 -0
- package/src/runtime/lifecycle/memory/state.ts +49 -0
- package/src/runtime/lifecycle/memory/track-ops.ts +15 -0
- package/src/runtime/lifecycle/post-compact.ts +38 -0
- package/src/runtime/lifecycle/post-edit-ts.ts +49 -0
- package/src/runtime/lifecycle/post-tracking.ts +40 -0
- package/src/runtime/lifecycle/pre-compact.ts +38 -0
- package/src/runtime/lifecycle/rules-root.ts +99 -0
- package/src/runtime/lifecycle/security/check-skill.ts +63 -0
- package/src/runtime/lifecycle/security/scan-patterns.ts +53 -0
- package/src/runtime/lifecycle/security/scan.ts +76 -0
- package/src/runtime/lifecycle/security/skill-state.ts +47 -0
- package/src/runtime/lifecycle/security/track-mcp.ts +29 -0
- package/src/runtime/lifecycle/security/track-skill-read.ts +31 -0
- package/src/runtime/lifecycle/seo/post-tool-use.ts +45 -0
- package/src/runtime/lifecycle/session-end.ts +17 -0
- package/src/runtime/lifecycle/session-start.ts +57 -0
- package/src/runtime/lifecycle/snapshot/board.ts +27 -0
- package/src/runtime/lifecycle/snapshot/format.ts +60 -0
- package/src/runtime/lifecycle/snapshot/git.ts +71 -0
- package/src/runtime/lifecycle/snapshot/index.ts +52 -0
- package/src/runtime/lifecycle/snapshot/version.ts +34 -0
- package/src/runtime/lifecycle/solid-detect.ts +56 -0
- package/src/runtime/lifecycle/stop-core.ts +35 -0
- package/src/runtime/lifecycle/subagent-cache.ts +61 -0
- package/src/runtime/lifecycle/task-completed.ts +94 -0
- package/src/runtime/lifecycle/teammate-idle-check.ts +63 -0
- package/src/runtime/lifecycle/teammate-idle.ts +28 -0
- package/src/runtime/lifecycle/tool-failure.ts +24 -0
- package/src/runtime/lifecycle/track-changes.ts +61 -0
- package/src/runtime/lifecycle/validate-solid.ts +70 -0
- package/src/runtime/lifecycle/validate-tailwind.ts +80 -0
- package/src/runtime/lifecycle-bridge.ts +74 -0
- package/src/runtime/mcp-key.ts +44 -0
- package/src/runtime/mcp-tool-name.ts +92 -0
- package/src/runtime/mcp.ts +91 -0
- package/src/runtime/modular.ts +77 -0
- package/src/runtime/normalize.ts +107 -0
- package/src/runtime/notices.ts +91 -0
- package/src/runtime/notification-sound.ts +49 -0
- package/src/runtime/notifications.ts +77 -0
- package/src/runtime/paths.ts +59 -0
- package/src/runtime/post-fanout.ts +41 -0
- package/src/runtime/post-outcome.ts +61 -0
- package/src/runtime/pre-allow.ts +97 -0
- package/src/runtime/precommit.ts +60 -0
- package/src/runtime/prompt-text.ts +38 -0
- package/src/runtime/receipt-capture.ts +34 -0
- package/src/runtime/record.ts +26 -0
- package/src/runtime/respond.ts +92 -0
- package/src/runtime/solid-file-size-gate.ts +58 -0
- package/src/runtime/solid-pre.ts +53 -0
- package/src/runtime/storage.ts +9 -0
- package/src/statusline/colors.ts +31 -0
- package/src/statusline/constants.ts +17 -0
- package/src/statusline/formatters.ts +54 -0
- package/src/statusline/index.ts +4 -0
- package/src/statusline/progress-bar.ts +46 -0
- package/src/tracking/codex-post-failure.ts +73 -0
- package/src/tracking/index.ts +2 -0
- package/src/tracking/integrity.ts +99 -0
- package/src/tracking/one-shot-dedup.ts +34 -0
- package/src/tracking/one-shot-failure.ts +42 -0
- package/src/tracking/one-shot-store.ts +95 -0
- package/src/tracking/one-shot.ts +93 -0
- package/src/tracking/receipts.ts +95 -0
- package/src/tracking/session-state.ts +94 -0
- package/src/tracking/store.ts +96 -0
- package/src/tracking/track-compact.ts +100 -0
- package/src/tracking/track-diff.ts +50 -0
- package/src/tracking/track-journal.ts +97 -0
- package/src/tracking/track-lock-sync.ts +83 -0
- package/src/tracking/track-lock.ts +67 -0
- package/src/util/compact-json.ts +23 -0
- package/src/util/index.ts +2 -0
- package/src/util/json-io.ts +47 -0
- package/src/util/project-root.ts +41 -0
- package/src/util/runtime-io.ts +85 -0
- package/src/util/semver.ts +30 -0
package/dist/runtime/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Prompt } from "../types-
|
|
1
|
+
import { t as Prompt } from "../types-Bh0jEF3_.mjs";
|
|
2
2
|
import { t as RefMeta } from "../types-CY5qT2X1.mjs";
|
|
3
3
|
import { t as AgentQuality } from "../session-state-D5gLr66m.mjs";
|
|
4
4
|
//#region src/runtime/paths.d.ts
|
|
@@ -124,6 +124,12 @@ declare const TRIVIAL_BUDGET = 4;
|
|
|
124
124
|
* {@link withDenyLoop} rewrite an identical retried deny (decision unchanged).
|
|
125
125
|
*/
|
|
126
126
|
declare function gate(input: GateInput): Promise<Prompt | null>;
|
|
127
|
+
/**
|
|
128
|
+
* Gate independent Cursor command candidates without merging their shell syntax.
|
|
129
|
+
* Stateful outcome bookkeeping runs once, against the command that decided the
|
|
130
|
+
* aggregate result. A single distinct candidate follows {@link gate} verbatim.
|
|
131
|
+
*/
|
|
132
|
+
declare function gateCommandCandidates(input: GateInput, candidates: readonly string[]): Promise<Prompt | null>;
|
|
127
133
|
//#endregion
|
|
128
134
|
//#region src/runtime/dry.d.ts
|
|
129
135
|
/** Extract long (>12 char) declared symbol names from new file content. */
|
|
@@ -153,14 +159,17 @@ declare function dryGate(tool: string, filePath: string, content: string | undef
|
|
|
153
159
|
declare function preCommitGate(tool: string, command: string | undefined, cwd: string | undefined): Prompt | null;
|
|
154
160
|
//#endregion
|
|
155
161
|
//#region src/runtime/normalize.d.ts
|
|
156
|
-
/** One file fanned out
|
|
162
|
+
/** One file/edit fanned out from Codex `apply_patch` or Cursor `afterFileEdit`. */
|
|
157
163
|
interface NormalizedFile {
|
|
158
164
|
filePath: string;
|
|
159
165
|
content: string;
|
|
166
|
+
oldString?: string;
|
|
160
167
|
op: "add" | "update" | "delete";
|
|
161
168
|
}
|
|
162
169
|
/** A hook event normalized across harnesses. */
|
|
163
170
|
interface NormalizedEvent {
|
|
171
|
+
/** Native event name when the adapter exposes one explicitly (Cursor). */
|
|
172
|
+
eventName?: string;
|
|
164
173
|
phase: "pre" | "post";
|
|
165
174
|
tool: string;
|
|
166
175
|
input: Record<string, unknown>;
|
|
@@ -170,22 +179,26 @@ interface NormalizedEvent {
|
|
|
170
179
|
/** Edit only: the tool_input.old_string being replaced — lets the file-size gate (policy/evaluate.ts + policy/edit-outcome.ts) compute the post-edit outcome instead of judging the stale on-disk count alone. Undefined for Write (no such field) and for cline/apply_patch (parsed separately, no equivalent field). */
|
|
171
180
|
oldString?: string;
|
|
172
181
|
command?: string;
|
|
182
|
+
/** Cursor-only independent command candidates from beforeMCPExecution. */
|
|
183
|
+
commandCandidates?: string[];
|
|
173
184
|
/** Subagent type, if the tool-use came from one (Explore/Plan are file-size-exempt). */
|
|
174
185
|
agentType?: string;
|
|
175
186
|
/** Harness-resolved permission mode (Claude emits it natively; Codex maps `AskForApproval::Never` to the same "bypassPermissions" string — see adapters/codex/permission-mode.ts). Generic field, Codex-only consumer today. */
|
|
176
187
|
permissionMode?: string;
|
|
188
|
+
/** Codex logical tool-use identity, shared by sibling hook callbacks. */
|
|
189
|
+
toolUseId?: string;
|
|
190
|
+
/** Harness-reported working directory used to scope Codex authorization. */
|
|
191
|
+
cwd?: string;
|
|
192
|
+
/** Validated Cursor multi-root workspace paths in wire order. */
|
|
193
|
+
workspaceRoots?: string[];
|
|
177
194
|
/**
|
|
178
|
-
* Per-file changes
|
|
179
|
-
* `
|
|
180
|
-
* entry's verdict so one violating hunk blocks the whole envelope. Left
|
|
181
|
-
* undefined for every other tool/harness (single-file `filePath`/`content`).
|
|
195
|
+
* Per-file changes for Codex `apply_patch` and per-edit changes for Cursor
|
|
196
|
+
* `afterFileEdit`; undefined for single-file events.
|
|
182
197
|
*/
|
|
183
198
|
files?: NormalizedFile[];
|
|
184
199
|
}
|
|
185
200
|
/**
|
|
186
|
-
* Normalize a
|
|
187
|
-
* `preToolUse`/`postToolUse` shape and the top-level `tool_name`/`tool_input`
|
|
188
|
-
* shape used by Claude, Codex, Gemini, and Cursor.
|
|
201
|
+
* Normalize a hook payload, including Cline nesting and native Cursor events.
|
|
189
202
|
*/
|
|
190
203
|
declare function normalizeEvent(id: string, payload: Record<string, unknown>): NormalizedEvent;
|
|
191
204
|
//#endregion
|
|
@@ -201,8 +214,8 @@ declare function normalizeEvent(id: string, payload: Record<string, unknown>): N
|
|
|
201
214
|
* - gemini-cli/cline: their real hook schemas have no interactive "ask"
|
|
202
215
|
* state (deny is the only blocking outcome), so `ask` and `inform` already
|
|
203
216
|
* both resolve to non-blocking context injection — unchanged.
|
|
204
|
-
* - cursor: `ask`
|
|
205
|
-
*
|
|
217
|
+
* - cursor: `ask` degrades to a native `permission:"deny"` because Cursor does
|
|
218
|
+
* not reliably apply `ask` on `preToolUse`; `inform` stays non-blocking.
|
|
206
219
|
* - hermes: delegated to the adapter's `toHermesResponse` — `block` ->
|
|
207
220
|
* `{decision:"block",reason}`; `ask`/`inform` degrade to non-blocking
|
|
208
221
|
* `{context}` (Hermes has no interactive "ask" state).
|
|
@@ -891,10 +904,18 @@ interface HandleOutcome {
|
|
|
891
904
|
//#endregion
|
|
892
905
|
//#region src/runtime/handle.d.ts
|
|
893
906
|
/**
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
*
|
|
897
|
-
*
|
|
907
|
+
* Run one hook and adapt every Cursor scope outcome at the common runtime exit.
|
|
908
|
+
* Other harnesses retain the core handler's stdout and exit status unchanged.
|
|
909
|
+
* Cursor's shared `additional_context` budget context (see
|
|
910
|
+
* `../adapters/cursor/context-budget.ts`) is assembled here too — this is
|
|
911
|
+
* the single point every Cursor stdout passes through exactly once, so it's
|
|
912
|
+
* also the single point that reserves from and records into the registry.
|
|
913
|
+
* With no `session_id`/`conversation_id` at all, `sessionId` is `""` — the
|
|
914
|
+
* registry key would degenerate to one bucket shared by every session-less
|
|
915
|
+
* call on the same (cwd, event) pair, so `budget` stays `undefined` instead
|
|
916
|
+
* (falls back to the flat per-response cap in `toCursorLifecycleResponse`,
|
|
917
|
+
* with zero registry I/O). `stateDir` honors `opts.home` (test-only OS home
|
|
918
|
+
* override, see `HandleOptions`) so tests never need the real `os.homedir()`.
|
|
898
919
|
*/
|
|
899
920
|
declare function handleHook(id: string, payload: Record<string, unknown>, opts: HandleOptions): Promise<HandleOutcome>;
|
|
900
921
|
//#endregion
|
|
@@ -923,4 +944,4 @@ interface PreContext {
|
|
|
923
944
|
*/
|
|
924
945
|
declare function handlePre(ctx: PreContext): Promise<HandleOutcome>;
|
|
925
946
|
//#endregion
|
|
926
|
-
export { Activity, DEFAULT_WINDOW_MS, DuplicationVerdict, type GateInput, type HandleOptions, type HandleOutcome, LifecycleInput, MCP_TTL_MS, McpIntercept, NormalizedEvent, NormalizedFile, PluginScope, PreContext, REQUIRED_AGENTS, SolidProfile, TRIVIAL_BUDGET, ToolEvent, WEBFETCH_TTL_MS, activityFor, aipilotPostToolUse, cacheQueryOf, cartoSessionStart, checkFileSize, claudeHome, claudeMdKey, cleanupSession, countFiles, countLoc, defaultStateDir, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dispatchMemory, dryGate, extractSymbols, fuseHarnessHome, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsArchiveFileFor, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, projectHash, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityAdvisoryForPatch, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateSolidGate, validateTailwind, validateTeammateOutput, writePluginMap, writeTree };
|
|
947
|
+
export { Activity, DEFAULT_WINDOW_MS, DuplicationVerdict, type GateInput, type HandleOptions, type HandleOutcome, LifecycleInput, MCP_TTL_MS, McpIntercept, NormalizedEvent, NormalizedFile, PluginScope, PreContext, REQUIRED_AGENTS, SolidProfile, TRIVIAL_BUDGET, ToolEvent, WEBFETCH_TTL_MS, activityFor, aipilotPostToolUse, cacheQueryOf, cartoSessionStart, checkFileSize, claudeHome, claudeMdKey, cleanupSession, countFiles, countLoc, defaultStateDir, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dispatchMemory, dryGate, extractSymbols, fuseHarnessHome, fusengineCache, gate, gateCommandCandidates, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsArchiveFileFor, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, projectHash, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityAdvisoryForPatch, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateSolidGate, validateTailwind, validateTeammateOutput, writePluginMap, writeTree };
|
package/dist/runtime/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as projectLayout } from "../layout-KWoE_Mqn.mjs";
|
|
2
2
|
import { a as sanitizeSessionId, c as sessionsDir, i as loadSessionState, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, s as sessionStatePath, t as claudeHome } from "../home-state-oUGFB4ds.mjs";
|
|
3
|
-
import { A as
|
|
3
|
+
import { A as trackWatchResearch, At as taskContext, B as writePluginMap, Bt as todayUtc, C as postEditContext, Ct as removeOldFiles, D as securityAdvisory, Dt as projectContext, E as dispatchMemory, Et as gitContext, F as aipilotPostToolUse, Ft as isoUtc, G as mergeLines, H as isProject, I as dispatchAipilot, It as loadSecurityState, J as listChildren, K as countFiles, L as dispatchLessons, Lt as saveSecurityState, M as trackSkillRead, Mt as projectHash, N as trackEnrichment, Nt as trackFile, O as securityAdvisoryForPatch, Ot as claudeMdKey, P as dispatchLifecycle, Pt as normalizeEvent, R as cartoSessionStart, Rt as securityStateDir, S as lifecycleStdout, St as purgeTtlTree, T as seoPostToolUseResponse, Tt as devContext, U as writeTree, V as generateProjectMap, W as loadEnriched, X as lessonsFileFor, Y as lessonsArchiveFileFor, Z as lessonsStateFileFor, _ as gateCommandCandidates, _t as injectRules, a as recordActivity, at as cleanupSession, b as dryGate, bt as sessionStartCore, c as MCP_TTL_MS, ct as validateTeammateOutput, d as isMcpTool, dt as validateTailwind, f as queryOf, ft as validateSolidGate, g as gate, gt as solidDetectStart, h as TRIVIAL_BUDGET, ht as detectSolidProfile, i as respond, it as validateRulesLoaded, j as trackMcpResearch, jt as defaultStateDir, k as postTrackingSideEffects, kt as promptSubmitContext, l as WEBFETCH_TTL_MS, lt as trackAgentMemory, m as REQUIRED_AGENTS, mt as countLoc, n as activityFor, nt as postEditTypescript, o as mcpPostStore, ot as saveApexState, p as DEFAULT_WINDOW_MS, pt as checkFileSize, q as getFileDesc, r as handlePre, rt as trackSessionChanges, s as mcpPreIntercept, st as logToolFailure, t as handleHook, u as cacheQueryOf, ut as subagentCacheContext, v as preCommitGate, vt as readRules, w as seoPostToolUse, wt as trimLogFile, x as extractSymbols, xt as pruneEmptyDirs, y as detectDuplication, yt as runSessionStartCleanups, z as generateEcosystemMap, zt as securityStatePath } from "../handle-BF1dZFjY.mjs";
|
|
4
4
|
//#region src/runtime/storage.ts
|
|
5
5
|
/**
|
|
6
6
|
* The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
|
|
@@ -10,4 +10,4 @@ function harnessStateDir(root) {
|
|
|
10
10
|
return projectLayout(root).stateDir;
|
|
11
11
|
}
|
|
12
12
|
//#endregion
|
|
13
|
-
export { DEFAULT_WINDOW_MS, MCP_TTL_MS, REQUIRED_AGENTS, TRIVIAL_BUDGET, WEBFETCH_TTL_MS, activityFor, aipilotPostToolUse, cacheQueryOf, cartoSessionStart, checkFileSize, claudeHome, claudeMdKey, cleanupSession, countFiles, countLoc, defaultStateDir, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dispatchMemory, dryGate, extractSymbols, fuseHarnessHome, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsArchiveFileFor, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, projectHash, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityAdvisoryForPatch, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateSolidGate, validateTailwind, validateTeammateOutput, writePluginMap, writeTree };
|
|
13
|
+
export { DEFAULT_WINDOW_MS, MCP_TTL_MS, REQUIRED_AGENTS, TRIVIAL_BUDGET, WEBFETCH_TTL_MS, activityFor, aipilotPostToolUse, cacheQueryOf, cartoSessionStart, checkFileSize, claudeHome, claudeMdKey, cleanupSession, countFiles, countLoc, defaultStateDir, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dispatchMemory, dryGate, extractSymbols, fuseHarnessHome, fusengineCache, gate, gateCommandCandidates, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsArchiveFileFor, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, projectHash, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityAdvisoryForPatch, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateSolidGate, validateTailwind, validateTeammateOutput, writePluginMap, writeTree };
|
|
@@ -8,6 +8,8 @@ type PromptKind = "ask" | "block" | "inform";
|
|
|
8
8
|
*/
|
|
9
9
|
interface Prompt {
|
|
10
10
|
kind: PromptKind;
|
|
11
|
+
/** Stable policy identifier for confirmation diagnostics. */
|
|
12
|
+
ruleId?: string;
|
|
11
13
|
/** Short title, e.g. "SOLID file-size limit". */
|
|
12
14
|
title: string;
|
|
13
15
|
/** Why this fired. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as resolveMaxLines, c as storeBudget, i as hookBudget } from "./limits-DG5pl-5s.mjs";
|
|
2
2
|
import { l as ttlLabel, t as HOME_DIR } from "./dotenv-BLBkBTww.mjs";
|
|
3
|
-
import { A as moduleAwarePath, S as isHooksPath, T as isStoresPath, _ as rolloutVerdict, at as
|
|
3
|
+
import { A as moduleAwarePath, S as isHooksPath, T as isStoresPath, _ as rolloutVerdict, at as maskCommentsOnly, it as maskCommentsAndStrings, nt as nearestManifestDir, ot as DEV_KEYWORDS, rt as projectCaps, x as isComponentsPath, y as declaresInterface } from "./evaluate-CMiIqHeH.mjs";
|
|
4
4
|
import { d as countFrameworkCodeLines, l as PLUGINS_DIR, u as SOLID_REF } from "./home-state-oUGFB4ds.mjs";
|
|
5
5
|
import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
|
|
6
6
|
import { t as routeReferences } from "./router-PKVNBHge.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.92",
|
|
4
4
|
"description": "Harness-agnostic toolkit for AI coding agents: runtime harness detection (Claude Code, Codex, Cursor, Cline, Gemini, Aider...), pure policy core (env config, project/framework detection, SOLID/file-size limits, APEX freshness, guard patterns, portable prompts), cache, project memory, ref routing, state/locks, statusline, per-harness adapters (Claude/Cursor/Cline/Gemini) and a cli-mode harness-check binary. Bun-native, with a built dist for Node + bundlers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -121,6 +121,7 @@
|
|
|
121
121
|
}
|
|
122
122
|
},
|
|
123
123
|
"files": [
|
|
124
|
+
"src/**/*.ts",
|
|
124
125
|
"dist",
|
|
125
126
|
"assets",
|
|
126
127
|
"README.md",
|
|
@@ -138,7 +139,7 @@
|
|
|
138
139
|
"test": "bun test",
|
|
139
140
|
"sim": "bun test test/sim/",
|
|
140
141
|
"typecheck": "tsc --noEmit",
|
|
141
|
-
"docs:api": "
|
|
142
|
+
"docs:api": "bun install --cwd tools/api-docs --frozen-lockfile && bun run --cwd tools/api-docs generate",
|
|
142
143
|
"build": "tsdown src/index.ts src/config/index.ts src/util/index.ts src/detect/index.ts src/policy/index.ts src/prompt/index.ts src/memory/index.ts src/cache/index.ts src/freshness/index.ts src/refs/index.ts src/statusline/index.ts src/cli/index.ts src/cli/bin.ts src/init/index.ts src/tracking/index.ts src/runtime/index.ts src/adapters/claude/index.ts src/adapters/codex/index.ts src/adapters/cursor/index.ts src/adapters/cline/index.ts src/adapters/gemini/index.ts src/adapters/hermes/index.ts src/adapters/kimi/index.ts --dts --format esm --clean --out-dir dist",
|
|
143
144
|
"prepublishOnly": "bun test && tsc --noEmit && bun run build"
|
|
144
145
|
},
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Claude Code adapter — the thin Claude-only shim over the portable policy core; reads the hook stdin payload and emits hookSpecificOutput responses. */
|
|
2
|
+
import { evaluate } from "../../policy/evaluate";
|
|
3
|
+
import { formatPrompt, type Prompt } from "../../prompt/types";
|
|
4
|
+
import { readStdin } from "../../util/runtime-io";
|
|
5
|
+
import { commandToString } from "../../runtime/command-string";
|
|
6
|
+
|
|
7
|
+
/** Subset of the Claude Code hook stdin payload we consume. */
|
|
8
|
+
export interface ClaudeHookInput {
|
|
9
|
+
hook_event_name?: string;
|
|
10
|
+
tool_name?: string;
|
|
11
|
+
tool_input?: { file_path?: string; content?: string; new_string?: string; command?: string | string[] };
|
|
12
|
+
cwd?: string;
|
|
13
|
+
/** Shared Claude/Codex hook field — Codex maps approval_policy=never to "bypassPermissions" (adapters/codex/permission-mode.ts). */ permission_mode?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Read & parse the Claude hook payload from stdin (empty object on bad input). */
|
|
17
|
+
export async function readClaudeInput(): Promise<ClaudeHookInput> {
|
|
18
|
+
const text = await readStdin();
|
|
19
|
+
if (!text.trim()) return {};
|
|
20
|
+
try {
|
|
21
|
+
const parsed: unknown = JSON.parse(text);
|
|
22
|
+
return typeof parsed === "object" && parsed !== null ? (parsed as ClaudeHookInput) : {};
|
|
23
|
+
} catch {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** A `deny` hook response for a given event. PreToolUse-only field. */
|
|
29
|
+
export function denyResponse(event: string, reason: string): string {
|
|
30
|
+
return JSON.stringify({
|
|
31
|
+
hookSpecificOutput: { hookEventName: event, permissionDecision: "deny", permissionDecisionReason: reason },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A PostToolUse (and Stop/UserPromptSubmit) `block` response: those events
|
|
37
|
+
* ignore `permissionDecision` (PreToolUse-only) and only honor the top-level
|
|
38
|
+
* `decision`/`reason` keys, which feed `reason` back to Claude.
|
|
39
|
+
*/
|
|
40
|
+
export function blockResponse(reason: string): string {
|
|
41
|
+
return JSON.stringify({ decision: "block", reason });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** An `additionalContext` injection response. */
|
|
45
|
+
export function contextResponse(event: string, text: string): string {
|
|
46
|
+
return JSON.stringify({ hookSpecificOutput: { hookEventName: event, additionalContext: text } });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** A raw `systemMessage` notice — shown to the user without blocking the tool. Mirrors the shared Python `hook_output.allow_pass`/`post_pass` convention. */
|
|
50
|
+
export function systemMessage(text: string): string {
|
|
51
|
+
return JSON.stringify({ systemMessage: text });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** An `inform` response with a user-visible notice (Python `allow_pass`/`post_pass` parity): a pure pass reuses {@link systemMessage} alone; with agent-facing `context` both channels merge in one JSON. */
|
|
55
|
+
export function informResponse(event: string, notice: string, context: string): string {
|
|
56
|
+
if (!context) return systemMessage(notice);
|
|
57
|
+
return JSON.stringify({ systemMessage: notice, hookSpecificOutput: { hookEventName: event, additionalContext: context } });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Attach a `systemMessage`, MERGING it with any already present (`\n`-joined) instead of overwriting — several producers may each call this on the same stdout in one hook invocation. */
|
|
61
|
+
export function attachSystemMessage(stdout: string, notice: string): string {
|
|
62
|
+
try {
|
|
63
|
+
const parsed = JSON.parse(stdout) as Record<string, unknown>, prev = typeof parsed.systemMessage === "string" ? parsed.systemMessage : "";
|
|
64
|
+
return JSON.stringify({ ...parsed, systemMessage: prev ? `${prev}\n${notice}` : notice });
|
|
65
|
+
} catch { return systemMessage(notice); }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Render a portable {@link Prompt} as a Claude Code hook response: `block` → deny, `ask` → interactive `permissionDecision`, `inform` → `additionalContext` (+ `systemMessage` when `userMessage` is set). */
|
|
69
|
+
export function toClaudeResponse(event: string, prompt: Prompt): string {
|
|
70
|
+
const reason = formatPrompt(prompt);
|
|
71
|
+
if (prompt.kind === "block") return denyResponse(event, reason);
|
|
72
|
+
if (prompt.kind === "ask") {
|
|
73
|
+
return JSON.stringify({ hookSpecificOutput: { hookEventName: event, permissionDecision: "ask", permissionDecisionReason: reason } });
|
|
74
|
+
}
|
|
75
|
+
if (prompt.userMessage) return informResponse(event, prompt.userMessage, prompt.reason ? reason : "");
|
|
76
|
+
return contextResponse(event, reason);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Run the bundled policy over a Claude payload and return the native response string (deny/ask/additionalContext), or null to allow. */
|
|
80
|
+
export function guard(input: ClaudeHookInput): string | null {
|
|
81
|
+
const result = evaluate({
|
|
82
|
+
tool: input.tool_name ?? "Write",
|
|
83
|
+
filePath: input.tool_input?.file_path,
|
|
84
|
+
content: input.tool_input?.content ?? input.tool_input?.new_string,
|
|
85
|
+
command: commandToString(input.tool_input?.command),
|
|
86
|
+
});
|
|
87
|
+
if (result.decision === "allow" || !result.prompt) return null;
|
|
88
|
+
return toClaudeResponse(input.hook_event_name ?? "PreToolUse", result.prompt);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** @deprecated use {@link guard}. Kept for back-compat. */
|
|
92
|
+
export const fileSizeGuard: typeof guard = guard;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cline adapter (hook-mode). Schema per docs.cline.bot / .clinerules/hooks (2026):
|
|
3
|
+
* `PreToolUse` blocks via `{ cancel: true }`; it cannot modify tool parameters.
|
|
4
|
+
*/
|
|
5
|
+
import { evaluate } from "../../policy/evaluate";
|
|
6
|
+
import { formatPrompt } from "../../prompt/types";
|
|
7
|
+
|
|
8
|
+
/** `PreToolUse` stdin payload (subset). */
|
|
9
|
+
export interface ClineHookInput {
|
|
10
|
+
hookName?: string;
|
|
11
|
+
preToolUse?: {
|
|
12
|
+
toolName?: string;
|
|
13
|
+
parameters?: { path?: string; content?: string; command?: string };
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Hook stdout response. */
|
|
18
|
+
export interface ClineResponse {
|
|
19
|
+
cancel?: boolean;
|
|
20
|
+
errorMessage?: string;
|
|
21
|
+
contextModification?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Evaluate a tool use; cancel on a hard block, otherwise inject context. */
|
|
25
|
+
export function preToolUse(input: ClineHookInput): ClineResponse {
|
|
26
|
+
const t = input.preToolUse;
|
|
27
|
+
const r = evaluate({
|
|
28
|
+
tool: t?.toolName ?? "write_to_file",
|
|
29
|
+
filePath: t?.parameters?.path,
|
|
30
|
+
content: t?.parameters?.content,
|
|
31
|
+
command: t?.parameters?.command,
|
|
32
|
+
});
|
|
33
|
+
if (r.decision === "allow" || !r.prompt) return {};
|
|
34
|
+
const msg = formatPrompt(r.prompt);
|
|
35
|
+
return r.prompt.kind === "block" ? { cancel: true, errorMessage: msg } : { contextModification: msg };
|
|
36
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for Codex's freeform `apply_patch` tool payload — the platform's PRIMARY
|
|
3
|
+
* edit primitive. The PreToolUse hook delivers `tool_name: "apply_patch"` with
|
|
4
|
+
* `tool_input: { command: <raw patch text> }` (verified in the Codex source:
|
|
5
|
+
* `core/src/tools/handlers/apply_patch.rs::pre_tool_use_payload`, which emits
|
|
6
|
+
* `json!({ "command": <freeform patch> })`). The grammar is the official
|
|
7
|
+
* apply-patch Lark spec (`apply-patch/src/parser.rs`): a single patch envelope
|
|
8
|
+
* can carry MULTIPLE files.
|
|
9
|
+
*
|
|
10
|
+
* Content precision (for the file-size / DRY gates that key off `content`):
|
|
11
|
+
* - Add File: EXACT — every `+` line is the new file verbatim.
|
|
12
|
+
* - Update File: APPROXIMATE — only the hunk "new side" (context ` ` + added `+`
|
|
13
|
+
* lines) is reconstructed, not the full post-edit file. It is a lower bound on
|
|
14
|
+
* the file's size (callers pair it with the on-disk count for oversized-file
|
|
15
|
+
* edits), never the exact result.
|
|
16
|
+
* - Delete File: no content (empty).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** One file touched by an apply_patch envelope. */
|
|
20
|
+
export interface PatchedFile {
|
|
21
|
+
path: string;
|
|
22
|
+
content: string;
|
|
23
|
+
op: "add" | "update" | "delete";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const BEGIN = "*** Begin Patch";
|
|
27
|
+
const END = "*** End Patch";
|
|
28
|
+
const ADD = "*** Add File: ";
|
|
29
|
+
const DEL = "*** Delete File: ";
|
|
30
|
+
const UPD = "*** Update File: ";
|
|
31
|
+
const MOVE = "*** Move to: ";
|
|
32
|
+
const EOF = "*** End of File";
|
|
33
|
+
const ENV = "*** Environment ID: ";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Parse a Codex freeform patch into its per-file changes. Lenient on whitespace
|
|
37
|
+
* around structural markers (as Codex's own parser is); returns `[]` when no
|
|
38
|
+
* recognizable hunk is present (malformed input fails open, not closed).
|
|
39
|
+
* @param text - Raw patch body from `tool_input.command`.
|
|
40
|
+
* @returns One {@link PatchedFile} per Add/Update/Delete hunk, in order.
|
|
41
|
+
*/
|
|
42
|
+
export function parseApplyPatch(text: string): PatchedFile[] {
|
|
43
|
+
const files: PatchedFile[] = [];
|
|
44
|
+
let cur: PatchedFile | null = null;
|
|
45
|
+
let buf: string[] = [];
|
|
46
|
+
const flush = (): void => {
|
|
47
|
+
if (cur) {
|
|
48
|
+
cur.content = buf.join("\n");
|
|
49
|
+
files.push(cur);
|
|
50
|
+
}
|
|
51
|
+
cur = null;
|
|
52
|
+
buf = [];
|
|
53
|
+
};
|
|
54
|
+
for (const line of text.split("\n")) {
|
|
55
|
+
const marker = line.trimStart();
|
|
56
|
+
if (marker === BEGIN || marker.startsWith(ENV)) continue;
|
|
57
|
+
if (marker === END) {
|
|
58
|
+
flush();
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (marker.startsWith(ADD)) {
|
|
62
|
+
flush();
|
|
63
|
+
cur = { path: marker.slice(ADD.length).trim(), content: "", op: "add" };
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (marker.startsWith(DEL)) {
|
|
67
|
+
flush();
|
|
68
|
+
files.push({ path: marker.slice(DEL.length).trim(), content: "", op: "delete" });
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (marker.startsWith(UPD)) {
|
|
72
|
+
flush();
|
|
73
|
+
cur = { path: marker.slice(UPD.length).trim(), content: "", op: "update" };
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (marker.startsWith(MOVE)) {
|
|
77
|
+
if (cur) cur.path = marker.slice(MOVE.length).trim();
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (marker === EOF || !cur) continue;
|
|
81
|
+
if (cur.op === "add") {
|
|
82
|
+
if (line.startsWith("+")) buf.push(line.slice(1));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// Update hunk: keep the "new side" (added `+` + context ` `), drop removed `-`
|
|
86
|
+
// and `@@` chunk headers.
|
|
87
|
+
if (line.startsWith("@@")) continue;
|
|
88
|
+
if (line.startsWith("+")) buf.push(line.slice(1));
|
|
89
|
+
else if (line.startsWith("-")) continue;
|
|
90
|
+
else buf.push(line.startsWith(" ") ? line.slice(1) : line);
|
|
91
|
+
}
|
|
92
|
+
flush();
|
|
93
|
+
return files;
|
|
94
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Codex CLI adapter (hook-mode). Codex's `PreToolUse` hook (since 2026)
|
|
3
|
+
* uses the SAME envelope as Claude Code — `tool_name`/`tool_input` in,
|
|
4
|
+
* `hookSpecificOutput.permissionDecision` out — so it shares Claude's readers.
|
|
5
|
+
* Config lives at `.codex/hooks.json`.
|
|
6
|
+
*
|
|
7
|
+
* Two Codex-specific quirks this adapter closes (audit 2026-07-06):
|
|
8
|
+
* 1. `apply_patch` is Codex's PRIMARY edit primitive; its payload is a freeform
|
|
9
|
+
* patch in `tool_input.command`, with NO `file_path`/`content`. Claude's guard
|
|
10
|
+
* keyed off those fields, so the SOLID/DRY gates saw NOTHING (enforcement 0%).
|
|
11
|
+
* Here the patch is parsed and each file is judged (one violating hunk denies).
|
|
12
|
+
* 2. Codex parses but NEVER honors `permissionDecision: "ask"` (deny-only) — an
|
|
13
|
+
* `ask` silently fails open (verified: `pre_tool_use.rs` test
|
|
14
|
+
* `unsupported_permission_decision_fails_open`). Every `ask` is downgraded to
|
|
15
|
+
* an explicit deny.
|
|
16
|
+
*/
|
|
17
|
+
import { evaluate } from "../../policy/evaluate";
|
|
18
|
+
import { countLines } from "../../policy/file-size";
|
|
19
|
+
import { formatPrompt, type Prompt } from "../../prompt/types";
|
|
20
|
+
import { parseApplyPatch } from "./apply-patch";
|
|
21
|
+
import { commandToString } from "../../runtime/command-string";
|
|
22
|
+
import { canonicalizeCodexShellTool } from "../../runtime/codex-shell-tool";
|
|
23
|
+
import { canonicalizeMcpToolName } from "../../runtime/mcp-tool-name";
|
|
24
|
+
import { contextResponse, denyResponse, informResponse, type ClaudeHookInput } from "../claude";
|
|
25
|
+
import { isBypassPermissions } from "./permission-mode";
|
|
26
|
+
|
|
27
|
+
export { readClaudeInput as readCodexInput, denyResponse, contextResponse, informResponse, type ClaudeHookInput as CodexHookInput } from "../claude";
|
|
28
|
+
|
|
29
|
+
const ASK_PREFIX = "[downgraded from ask — Codex has no interactive approval]";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Render a portable {@link Prompt} as a Codex hook response, `ask` → explicit deny.
|
|
33
|
+
* NOTE: the REAL wired route is `harness hook codex` → handleHook → respond.ts
|
|
34
|
+
* (source of truth for the ask→deny downgrade); this thin export exists for
|
|
35
|
+
* direct package consumers and is kept aligned so it never silently diverges.
|
|
36
|
+
*/
|
|
37
|
+
export function toCodexResponse(prompt: Prompt): string {
|
|
38
|
+
const message = formatPrompt(prompt);
|
|
39
|
+
if (prompt.kind === "inform") {
|
|
40
|
+
return prompt.userMessage ? informResponse("PreToolUse", prompt.userMessage, prompt.reason ? message : "") : contextResponse("PreToolUse", message);
|
|
41
|
+
}
|
|
42
|
+
if (prompt.kind === "ask") return denyResponse("PreToolUse", `${ASK_PREFIX}\n${message}`);
|
|
43
|
+
return denyResponse("PreToolUse", message);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** OR the per-file SOLID verdict of an `apply_patch` payload — first block wins. */
|
|
47
|
+
function applyPatchPrompt(command: string): Prompt | null {
|
|
48
|
+
for (const f of parseApplyPatch(command)) {
|
|
49
|
+
if (f.op === "delete") continue;
|
|
50
|
+
const tool = f.op === "add" ? "Write" : "Edit";
|
|
51
|
+
const r = evaluate({ tool, filePath: f.path, content: f.content, existingLines: countLines(f.content) });
|
|
52
|
+
if (r.decision !== "allow" && r.prompt) return r.prompt;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Portable single-tool verdict for non-`apply_patch` Codex tools. */
|
|
58
|
+
function resolvePrompt(input: ClaudeHookInput): Prompt | null {
|
|
59
|
+
const i = input.tool_input;
|
|
60
|
+
const r = evaluate({
|
|
61
|
+
// Code Mode-wrapped exec_command surfaces its raw function-tool name here
|
|
62
|
+
// instead of "Bash" (see codex-shell-tool.ts) — canonicalize so the SOLID/
|
|
63
|
+
// protected-path/bash-write guards recognize it like a native Bash call.
|
|
64
|
+
tool: canonicalizeCodexShellTool("codex", canonicalizeMcpToolName("codex", input.tool_name ?? "Write")),
|
|
65
|
+
filePath: i?.file_path,
|
|
66
|
+
content: i?.content ?? i?.new_string,
|
|
67
|
+
command: commandToString(i?.command),
|
|
68
|
+
neverApproval: isBypassPermissions(input.permission_mode),
|
|
69
|
+
});
|
|
70
|
+
return r.decision === "allow" || !r.prompt ? null : r.prompt;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Run the bundled policy over a Codex payload and return the native response
|
|
75
|
+
* string (deny/additionalContext), or null to allow. `apply_patch` is fanned
|
|
76
|
+
* into per-file checks; every other tool routes through the portable policy.
|
|
77
|
+
*/
|
|
78
|
+
export function guard(input: ClaudeHookInput): string | null {
|
|
79
|
+
const prompt =
|
|
80
|
+
input.tool_name === "apply_patch"
|
|
81
|
+
? applyPatchPrompt(commandToString(input.tool_input?.command) ?? "")
|
|
82
|
+
: resolvePrompt(input);
|
|
83
|
+
return prompt ? toCodexResponse(prompt) : null;
|
|
84
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex maps `AskForApproval::Never` -> `permission_mode: "bypassPermissions"`
|
|
3
|
+
* in its hook payload (codex-rs/core/src/hook_runtime.rs::hook_permission_mode)
|
|
4
|
+
* — the only value that isolates `never`; the other three approval policies
|
|
5
|
+
* (`untrusted`, `on-failure`, `on-request`) all collapse to `"default"`.
|
|
6
|
+
* Verified at openai/codex@342e4d4b, hook_runtime.rs run_pre_tool_use_hooks +
|
|
7
|
+
* pre_tool_use.rs PreToolUseRequest. Undocumented implementation detail, not
|
|
8
|
+
* a public contract — see the mapping-regression test that pins this string.
|
|
9
|
+
* @param permissionMode - The payload's `permission_mode` field, if present.
|
|
10
|
+
* @returns True only on an EXACT match — fail-closed. A near-miss
|
|
11
|
+
* (`"BypassPermissions"`, `"bypassPermissions "`, or a substring match) must
|
|
12
|
+
* never accidentally grant the neverApproval exemption.
|
|
13
|
+
*/
|
|
14
|
+
export function isBypassPermissions(permissionMode: string | undefined): boolean {
|
|
15
|
+
return permissionMode === "bypassPermissions";
|
|
16
|
+
}
|