@fusengine/harness 0.1.90 → 0.1.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-C43gA-Pr.mjs} +701 -134
- 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-BjG6unTj.mjs +317 -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 +27 -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.ts +46 -0
- package/src/adapters/cursor/events.ts +38 -0
- package/src/adapters/cursor/index.ts +43 -0
- package/src/adapters/cursor/interfaces/types.ts +88 -0
- package/src/adapters/cursor/native-response.ts +158 -0
- package/src/adapters/cursor/normalize.ts +123 -0
- package/src/adapters/cursor/respond.ts +123 -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 +116 -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 +100 -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 +51 -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 +83 -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
|
@@ -3,11 +3,11 @@ import { a as harnessHome, c as resolveTtlSec } from "./dotenv-BLBkBTww.mjs";
|
|
|
3
3
|
import { r as projectLayout } from "./layout-KWoE_Mqn.mjs";
|
|
4
4
|
import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
|
|
5
5
|
import { t as detectHarness } from "./harness-BMuLJ9lm.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { D as isVendorPath, G as computeEditResultLines, K as isFileSizeScoped, V as shellOutputRedirects, Y as GIT_BLOCKED, b as interfaceDeclLevel, ct as detectProjectType$1, et as matchPatterns, g as conventionsMode, it as maskCommentsAndStrings, n as FAIL_CLOSED, q as resolveSolidRefFramework, st as detectModularArchitecture, t as evaluate, tt as detectFramework, ut as requiredArchSkill } from "./evaluate-CMiIqHeH.mjs";
|
|
7
7
|
import { a as sanitizeSessionId, c as sessionsDir, d as countFrameworkCodeLines, f as countLines, i as loadSessionState, l as PLUGINS_DIR, n as fuseHarnessHome, o as saveSessionState, p as evaluateFileSize, r as fusengineCache, t as claudeHome } from "./home-state-oUGFB4ds.mjs";
|
|
8
8
|
import { a as writeJsonFile, i as readJsonFile, r as hashText, t as atomicWrite } from "./json-io-DisYd2fb.mjs";
|
|
9
9
|
import { r as isDocConsulted } from "./doc-helpers-CWZegVdR.mjs";
|
|
10
|
-
import { D as frameworkSolidGate, F as isExcludedSwiftPath, G as evaluateApex, H as PRE_AUTH_GATES, P as isExcludedJsPath, R as capVerbosity, S as parseField, T as usesTailwindUtilities, V as POST_AUTH_GATES, W as docConsultedGate, b as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, g as buildClaudeMdContext, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, p as apexAgentSteps, r as descFromText, s as parseEntry, t as isHtmlLike, v as apexDocName, w as skillTriggerGate, y as harnessHomeSegment, z as detectCreationIntent } from "./validate-
|
|
10
|
+
import { D as frameworkSolidGate, F as isExcludedSwiftPath, G as evaluateApex, H as PRE_AUTH_GATES, P as isExcludedJsPath, R as capVerbosity, S as parseField, T as usesTailwindUtilities, V as POST_AUTH_GATES, W as docConsultedGate, b as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, g as buildClaudeMdContext, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, p as apexAgentSteps, r as descFromText, s as parseEntry, t as isHtmlLike, v as apexDocName, w as skillTriggerGate, y as harnessHomeSegment, z as detectCreationIntent } from "./validate-KjZ1X9tH.mjs";
|
|
11
11
|
import { n as findMarketplacePlugins, r as readPluginMeta, t as resolveSkillPath } from "./skill-path-DVML3zfp.mjs";
|
|
12
12
|
import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
|
|
13
13
|
import { a as nowStamp, l as throttleMs, n as readRoots, o as readState, s as setStateField, t as addRoot } from "./registry-IhHk2KlT.mjs";
|
|
@@ -15,9 +15,11 @@ import { d as loadIndex, i as cacheLookupMeta, n as webfetchCacheWrite, o as cac
|
|
|
15
15
|
import { t as loadRefs } from "./loader-AGz4nK7d.mjs";
|
|
16
16
|
import { C as apexAuthorizationGate, S as trivialCount, _ as recordBrainstormRequired, a as journalLogPath, b as recordTarget, c as appendEvent, d as signTrack, f as verifyTrack, g as recordAgent, h as emptyTrack, i as withTrack, l as withTrackLockSync, m as agentsFresh, o as readTrackSync, p as writeLastNonce, r as trackJournalEnabled, s as diffTrackEvents, t as loadTrack, u as LOCK_FAILED, v as recordDoc, x as recordTrivialEdit, y as recordRefRead } from "./store-5-ZPKb0u.mjs";
|
|
17
17
|
import { i as parseApplyPatch, n as canonicalizeMcpToolName, r as canonicalizeCodexShellTool, t as isBypassPermissions } from "./permission-mode-B-SFyR0X.mjs";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { r as
|
|
18
|
+
import { t as commandToString } from "./command-string-CALMTnwN.mjs";
|
|
19
|
+
import { n as cursorProjectCwd, r as cursorEventContract, t as extractCursorEvent } from "./normalize-BjG6unTj.mjs";
|
|
20
|
+
import { d as collectFiles, f as pathExists, g as writeText, h as spawnCapture, i as denyResponse, l as systemMessage, m as sleep, n as blockResponse, p as readText$1, r as contextResponse, s as informResponse, t as attachSystemMessage } from "./claude-Ckv2_TgP.mjs";
|
|
21
|
+
import { i as toKimiResponse, n as kimiDenyResponse } from "./kimi-G2wcSh5-.mjs";
|
|
22
|
+
import { r as toHermesResponse } from "./hermes-B9-p_3IF.mjs";
|
|
21
23
|
import { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
22
24
|
import { appendFileSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, rmdirSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
23
25
|
import { homedir } from "node:os";
|
|
@@ -69,9 +71,7 @@ function str(v) {
|
|
|
69
71
|
return typeof v === "string" ? v : void 0;
|
|
70
72
|
}
|
|
71
73
|
/**
|
|
72
|
-
* Normalize a
|
|
73
|
-
* `preToolUse`/`postToolUse` shape and the top-level `tool_name`/`tool_input`
|
|
74
|
-
* shape used by Claude, Codex, Gemini, and Cursor.
|
|
74
|
+
* Normalize a hook payload, including Cline nesting and native Cursor events.
|
|
75
75
|
*/
|
|
76
76
|
function normalizeEvent(id, payload) {
|
|
77
77
|
if (id === "cline") {
|
|
@@ -88,6 +88,12 @@ function normalizeEvent(id, payload) {
|
|
|
88
88
|
command: str(params.command)
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
|
+
if (id === "cursor") return {
|
|
92
|
+
...extractCursorEvent(payload),
|
|
93
|
+
sessionId: str(payload.session_id) ?? str(payload.conversation_id) ?? "",
|
|
94
|
+
agentType: str(payload.agent_type),
|
|
95
|
+
permissionMode: str(payload.permission_mode)
|
|
96
|
+
};
|
|
91
97
|
const event = str(payload.hook_event_name) ?? "";
|
|
92
98
|
const input = payload.tool_input ?? payload;
|
|
93
99
|
const tool = canonicalizeCodexShellTool(id, canonicalizeMcpToolName(id, str(payload.tool_name) ?? ""));
|
|
@@ -97,7 +103,9 @@ function normalizeEvent(id, payload) {
|
|
|
97
103
|
input,
|
|
98
104
|
sessionId: str(payload.session_id) ?? str(payload.conversation_id) ?? "",
|
|
99
105
|
agentType: str(payload.agent_type) ?? str(input.subagent_type),
|
|
100
|
-
permissionMode: str(payload.permission_mode)
|
|
106
|
+
permissionMode: str(payload.permission_mode),
|
|
107
|
+
toolUseId: str(payload.tool_use_id),
|
|
108
|
+
cwd: str(payload.cwd)
|
|
101
109
|
};
|
|
102
110
|
if (tool === "apply_patch") {
|
|
103
111
|
const files = parseApplyPatch(str(input.command) ?? str(payload.command) ?? "").map((f) => ({
|
|
@@ -3064,7 +3072,7 @@ function lessonsStateFileFor(root) {
|
|
|
3064
3072
|
//#endregion
|
|
3065
3073
|
//#region src/tracking/one-shot-store.ts
|
|
3066
3074
|
/** A fresh, empty state — always spread (`{ ...EMPTY }`) so the const is never shared. */
|
|
3067
|
-
const EMPTY = {
|
|
3075
|
+
const EMPTY$1 = {
|
|
3068
3076
|
gates: {},
|
|
3069
3077
|
firstTry: 0,
|
|
3070
3078
|
corrected: 0,
|
|
@@ -3076,7 +3084,7 @@ const EMPTY = {
|
|
|
3076
3084
|
* gates/pending older than `windowMs`. Keeps the "7d" window honest, bounds size.
|
|
3077
3085
|
*/
|
|
3078
3086
|
function pruneState(s, now, windowMs) {
|
|
3079
|
-
if (now - s.updatedAt >= windowMs) return { ...EMPTY };
|
|
3087
|
+
if (now - s.updatedAt >= windowMs) return { ...EMPTY$1 };
|
|
3080
3088
|
const gates = {};
|
|
3081
3089
|
for (const [k, g] of Object.entries(s.gates)) if (now - g.lastTs < windowMs) gates[k] = g;
|
|
3082
3090
|
const pending = {};
|
|
@@ -3309,16 +3317,16 @@ const SIDECAR$1 = "one-shot.json";
|
|
|
3309
3317
|
/** Retention window: 7 days. Aggregates and pending denies older than this are pruned. */
|
|
3310
3318
|
const WINDOW_MS = 10080 * 60 * 1e3;
|
|
3311
3319
|
/** Load the state, or a fresh copy when missing/corrupt. */
|
|
3312
|
-
function loadState(path) {
|
|
3320
|
+
function loadState$1(path) {
|
|
3313
3321
|
try {
|
|
3314
|
-
if (!existsSync(path)) return { ...EMPTY };
|
|
3322
|
+
if (!existsSync(path)) return { ...EMPTY$1 };
|
|
3315
3323
|
const d = JSON.parse(readFileSync(path, "utf8"));
|
|
3316
3324
|
return d && typeof d === "object" && !Array.isArray(d) ? {
|
|
3317
|
-
...EMPTY,
|
|
3325
|
+
...EMPTY$1,
|
|
3318
3326
|
...d
|
|
3319
|
-
} : { ...EMPTY };
|
|
3327
|
+
} : { ...EMPTY$1 };
|
|
3320
3328
|
} catch {
|
|
3321
|
-
return { ...EMPTY };
|
|
3329
|
+
return { ...EMPTY$1 };
|
|
3322
3330
|
}
|
|
3323
3331
|
}
|
|
3324
3332
|
/**
|
|
@@ -3341,7 +3349,7 @@ function recordOneShot(prompt, input, opts) {
|
|
|
3341
3349
|
});
|
|
3342
3350
|
if (!burstFirst(op, prompt ? `deny:${prompt.title}` : "allow", opts)) return;
|
|
3343
3351
|
const path = join(opts.dir, SIDECAR$1);
|
|
3344
|
-
let s = pruneState(loadState(path), opts.now, WINDOW_MS);
|
|
3352
|
+
let s = pruneState(loadState$1(path), opts.now, WINDOW_MS);
|
|
3345
3353
|
s = prompt ? applyDeny(s, prompt.title, op, opts.now) : applyAllow(s, op, opts.now, input.content != null || input.command != null);
|
|
3346
3354
|
atomicWrite(path, JSON.stringify(s));
|
|
3347
3355
|
} catch {}
|
|
@@ -3356,7 +3364,7 @@ function recordOneShot(prompt, input, opts) {
|
|
|
3356
3364
|
*/
|
|
3357
3365
|
function oneShotSummary(cwd) {
|
|
3358
3366
|
try {
|
|
3359
|
-
return formatSummary(pruneState(loadState(join(defaultStateDir(cwd), SIDECAR$1)), Date.now(), WINDOW_MS));
|
|
3367
|
+
return formatSummary(pruneState(loadState$1(join(defaultStateDir(cwd), SIDECAR$1)), Date.now(), WINDOW_MS));
|
|
3360
3368
|
} catch {
|
|
3361
3369
|
return "";
|
|
3362
3370
|
}
|
|
@@ -3401,7 +3409,7 @@ function recordFailure(tool, opts) {
|
|
|
3401
3409
|
try {
|
|
3402
3410
|
if (!burstFirst(`fail:${tool}`, "failure", opts)) return;
|
|
3403
3411
|
const path = join(opts.dir, SIDECAR$1);
|
|
3404
|
-
const next = applyFailure(pruneState(loadState(path), opts.now, WINDOW_MS), tool, opts.now);
|
|
3412
|
+
const next = applyFailure(pruneState(loadState$1(path), opts.now, WINDOW_MS), tool, opts.now);
|
|
3405
3413
|
atomicWrite(path, JSON.stringify(next));
|
|
3406
3414
|
} catch {}
|
|
3407
3415
|
}
|
|
@@ -6646,13 +6654,281 @@ async function autoDocumentRead(filePath, now = Date.now(), id = "claude-code")
|
|
|
6646
6654
|
return systemMessage(`📖 [${docType}] ${fname} logged`);
|
|
6647
6655
|
}
|
|
6648
6656
|
//#endregion
|
|
6657
|
+
//#region src/adapters/cursor/native-response.ts
|
|
6658
|
+
const stringValue = (value) => typeof value === "string";
|
|
6659
|
+
const booleanValue = (value) => typeof value === "boolean";
|
|
6660
|
+
const plainRecord = (value) => {
|
|
6661
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
6662
|
+
try {
|
|
6663
|
+
const prototype = Object.getPrototypeOf(value);
|
|
6664
|
+
return prototype === Object.prototype || prototype === null;
|
|
6665
|
+
} catch {
|
|
6666
|
+
return false;
|
|
6667
|
+
}
|
|
6668
|
+
};
|
|
6669
|
+
function jsonChildren(value) {
|
|
6670
|
+
const keys = Reflect.ownKeys(value);
|
|
6671
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
6672
|
+
if (Array.isArray(value)) {
|
|
6673
|
+
if (Object.getPrototypeOf(value) !== Array.prototype) return null;
|
|
6674
|
+
const length = descriptors.length;
|
|
6675
|
+
if (!length || !("value" in length) || !Number.isSafeInteger(length.value) || length.value < 0) return null;
|
|
6676
|
+
if (keys.length !== length.value + 1 || keys.some((key) => typeof key === "symbol")) return null;
|
|
6677
|
+
const children = [];
|
|
6678
|
+
for (let index = 0; index < length.value; index += 1) {
|
|
6679
|
+
const descriptor = descriptors[String(index)];
|
|
6680
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) return null;
|
|
6681
|
+
children.push(descriptor.value);
|
|
6682
|
+
}
|
|
6683
|
+
return children;
|
|
6684
|
+
}
|
|
6685
|
+
if (!plainRecord(value) || keys.some((key) => typeof key === "symbol")) return null;
|
|
6686
|
+
const children = [];
|
|
6687
|
+
for (const key of keys) {
|
|
6688
|
+
const descriptor = descriptors[key];
|
|
6689
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) return null;
|
|
6690
|
+
children.push(descriptor.value);
|
|
6691
|
+
}
|
|
6692
|
+
return children;
|
|
6693
|
+
}
|
|
6694
|
+
function jsonValue(root) {
|
|
6695
|
+
const active = /* @__PURE__ */ new WeakSet();
|
|
6696
|
+
const stack = [{ value: root }];
|
|
6697
|
+
while (stack.length > 0) {
|
|
6698
|
+
const frame = stack.pop();
|
|
6699
|
+
if (frame.leave) {
|
|
6700
|
+
active.delete(frame.value);
|
|
6701
|
+
continue;
|
|
6702
|
+
}
|
|
6703
|
+
const { value } = frame;
|
|
6704
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") continue;
|
|
6705
|
+
if (typeof value === "number") {
|
|
6706
|
+
if (!Number.isFinite(value)) return false;
|
|
6707
|
+
continue;
|
|
6708
|
+
}
|
|
6709
|
+
if (typeof value !== "object" || active.has(value)) return false;
|
|
6710
|
+
let children;
|
|
6711
|
+
try {
|
|
6712
|
+
children = jsonChildren(value);
|
|
6713
|
+
} catch {
|
|
6714
|
+
return false;
|
|
6715
|
+
}
|
|
6716
|
+
if (!children) return false;
|
|
6717
|
+
active.add(value);
|
|
6718
|
+
stack.push({
|
|
6719
|
+
value,
|
|
6720
|
+
leave: true
|
|
6721
|
+
});
|
|
6722
|
+
for (let index = children.length - 1; index >= 0; index -= 1) stack.push({ value: children[index] });
|
|
6723
|
+
}
|
|
6724
|
+
return true;
|
|
6725
|
+
}
|
|
6726
|
+
const recordValue = (value) => plainRecord(value) && jsonValue(value);
|
|
6727
|
+
const stringRecord = (value) => {
|
|
6728
|
+
if (!recordValue(value)) return false;
|
|
6729
|
+
try {
|
|
6730
|
+
return Object.values(Object.getOwnPropertyDescriptors(value)).every((descriptor) => "value" in descriptor && typeof descriptor.value === "string");
|
|
6731
|
+
} catch {
|
|
6732
|
+
return false;
|
|
6733
|
+
}
|
|
6734
|
+
};
|
|
6735
|
+
const stringArray = (value) => Array.isArray(value) && value.every(stringValue);
|
|
6736
|
+
const permission = (...values) => (value) => typeof value === "string" && values.includes(value);
|
|
6737
|
+
const EMPTY = { fields: {} };
|
|
6738
|
+
const FOLLOWUP = { fields: { followup_message: stringValue } };
|
|
6739
|
+
const PERMISSION_ASK = {
|
|
6740
|
+
fields: {
|
|
6741
|
+
permission: permission("allow", "deny", "ask"),
|
|
6742
|
+
user_message: stringValue,
|
|
6743
|
+
agent_message: stringValue
|
|
6744
|
+
},
|
|
6745
|
+
required: ["permission"]
|
|
6746
|
+
};
|
|
6747
|
+
const NATIVE_SCHEMAS = {
|
|
6748
|
+
sessionStart: { fields: {
|
|
6749
|
+
env: stringRecord,
|
|
6750
|
+
additional_context: stringValue,
|
|
6751
|
+
continue: booleanValue,
|
|
6752
|
+
user_message: stringValue
|
|
6753
|
+
} },
|
|
6754
|
+
sessionEnd: EMPTY,
|
|
6755
|
+
beforeSubmitPrompt: {
|
|
6756
|
+
fields: {
|
|
6757
|
+
continue: booleanValue,
|
|
6758
|
+
user_message: stringValue
|
|
6759
|
+
},
|
|
6760
|
+
required: ["continue"]
|
|
6761
|
+
},
|
|
6762
|
+
preCompact: { fields: { user_message: stringValue } },
|
|
6763
|
+
subagentStart: {
|
|
6764
|
+
fields: {
|
|
6765
|
+
permission: permission("allow", "deny"),
|
|
6766
|
+
user_message: stringValue
|
|
6767
|
+
},
|
|
6768
|
+
required: ["permission"]
|
|
6769
|
+
},
|
|
6770
|
+
subagentStop: FOLLOWUP,
|
|
6771
|
+
preToolUse: {
|
|
6772
|
+
fields: {
|
|
6773
|
+
...PERMISSION_ASK.fields,
|
|
6774
|
+
updated_input: recordValue
|
|
6775
|
+
},
|
|
6776
|
+
required: ["permission"]
|
|
6777
|
+
},
|
|
6778
|
+
postToolUse: { fields: {
|
|
6779
|
+
updated_mcp_tool_output: recordValue,
|
|
6780
|
+
additional_context: stringValue
|
|
6781
|
+
} },
|
|
6782
|
+
postToolUseFailure: EMPTY,
|
|
6783
|
+
beforeShellExecution: PERMISSION_ASK,
|
|
6784
|
+
afterShellExecution: EMPTY,
|
|
6785
|
+
beforeMCPExecution: PERMISSION_ASK,
|
|
6786
|
+
afterMCPExecution: EMPTY,
|
|
6787
|
+
beforeReadFile: {
|
|
6788
|
+
fields: {
|
|
6789
|
+
permission: permission("allow", "deny"),
|
|
6790
|
+
user_message: stringValue
|
|
6791
|
+
},
|
|
6792
|
+
required: ["permission"]
|
|
6793
|
+
},
|
|
6794
|
+
afterFileEdit: EMPTY,
|
|
6795
|
+
beforeTabFileRead: {
|
|
6796
|
+
fields: { permission: permission("allow", "deny") },
|
|
6797
|
+
required: ["permission"]
|
|
6798
|
+
},
|
|
6799
|
+
afterTabFileEdit: EMPTY,
|
|
6800
|
+
afterAgentResponse: EMPTY,
|
|
6801
|
+
afterAgentThought: EMPTY,
|
|
6802
|
+
stop: FOLLOWUP,
|
|
6803
|
+
workspaceOpen: { fields: { pluginPaths: stringArray } }
|
|
6804
|
+
};
|
|
6805
|
+
function isNativeCursorResponse(value, eventName) {
|
|
6806
|
+
try {
|
|
6807
|
+
if (!recordValue(value)) return false;
|
|
6808
|
+
const schema = NATIVE_SCHEMAS[eventName];
|
|
6809
|
+
if (!schema) return false;
|
|
6810
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
6811
|
+
if (schema.required?.some((field) => !Object.hasOwn(descriptors, field))) return false;
|
|
6812
|
+
return Reflect.ownKeys(descriptors).every((field) => {
|
|
6813
|
+
if (typeof field !== "string") return false;
|
|
6814
|
+
const descriptor = descriptors[field];
|
|
6815
|
+
if (!Object.hasOwn(schema.fields, field)) return false;
|
|
6816
|
+
const validate = schema.fields[field];
|
|
6817
|
+
return descriptor?.enumerable === true && "value" in descriptor && validate !== void 0 && validate(descriptor.value);
|
|
6818
|
+
});
|
|
6819
|
+
} catch {
|
|
6820
|
+
return false;
|
|
6821
|
+
}
|
|
6822
|
+
}
|
|
6823
|
+
/** Preserve raw stdout only when JSON.parse proves a documented native Cursor response. */
|
|
6824
|
+
function parseNativeCursorStdout(stdout, eventName) {
|
|
6825
|
+
if (typeof stdout !== "string") return null;
|
|
6826
|
+
try {
|
|
6827
|
+
return isNativeCursorResponse(JSON.parse(stdout), eventName) ? stdout : null;
|
|
6828
|
+
} catch {
|
|
6829
|
+
return null;
|
|
6830
|
+
}
|
|
6831
|
+
}
|
|
6832
|
+
//#endregion
|
|
6833
|
+
//#region src/adapters/cursor/respond.ts
|
|
6834
|
+
const AGENT_MESSAGE_EVENTS = /* @__PURE__ */ new Set([
|
|
6835
|
+
"preToolUse",
|
|
6836
|
+
"beforeShellExecution",
|
|
6837
|
+
"beforeMCPExecution"
|
|
6838
|
+
]);
|
|
6839
|
+
const USER_MESSAGE_EVENTS = /* @__PURE__ */ new Set([
|
|
6840
|
+
"preToolUse",
|
|
6841
|
+
"beforeShellExecution",
|
|
6842
|
+
"beforeMCPExecution",
|
|
6843
|
+
"beforeReadFile",
|
|
6844
|
+
"subagentStart"
|
|
6845
|
+
]);
|
|
6846
|
+
function permissionMessages(eventName, userMessage, agentMessage) {
|
|
6847
|
+
return {
|
|
6848
|
+
...userMessage && USER_MESSAGE_EVENTS.has(eventName) ? { user_message: userMessage } : {},
|
|
6849
|
+
...agentMessage && AGENT_MESSAGE_EVENTS.has(eventName) ? { agent_message: agentMessage } : {}
|
|
6850
|
+
};
|
|
6851
|
+
}
|
|
6852
|
+
function joinMessages(...values) {
|
|
6853
|
+
return values.filter((value) => typeof value === "string" && value.length > 0).join("\n");
|
|
6854
|
+
}
|
|
6855
|
+
function isRecord(value) {
|
|
6856
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6857
|
+
}
|
|
6858
|
+
/** Render a portable policy prompt using the native Cursor event contract. */
|
|
6859
|
+
function toCursorResponse(prompt, eventName) {
|
|
6860
|
+
const contract = cursorEventContract(eventName);
|
|
6861
|
+
const message = formatPrompt(prompt);
|
|
6862
|
+
if (!contract.known || contract.response === "neutral" || contract.response === "plugin-paths") return "{}";
|
|
6863
|
+
if (contract.response === "post-context" || contract.response === "session-context") return JSON.stringify({ additional_context: message });
|
|
6864
|
+
if (contract.response === "followup") return JSON.stringify({ followup_message: message });
|
|
6865
|
+
if (contract.response === "compact-notice") return JSON.stringify({ user_message: prompt.userMessage ?? message });
|
|
6866
|
+
if (contract.response === "submit-control") return JSON.stringify({
|
|
6867
|
+
continue: prompt.kind !== "block",
|
|
6868
|
+
user_message: prompt.userMessage ?? message
|
|
6869
|
+
});
|
|
6870
|
+
if (prompt.kind === "inform") return JSON.stringify({
|
|
6871
|
+
permission: "allow",
|
|
6872
|
+
...permissionMessages(eventName, prompt.userMessage, prompt.reason ? message : void 0)
|
|
6873
|
+
});
|
|
6874
|
+
const userMessage = prompt.kind === "ask" ? `[downgraded from ask — Cursor does not enforce approval for this event]\n${message}` : message;
|
|
6875
|
+
return JSON.stringify({
|
|
6876
|
+
permission: "deny",
|
|
6877
|
+
...permissionMessages(eventName, userMessage, userMessage)
|
|
6878
|
+
});
|
|
6879
|
+
}
|
|
6880
|
+
/** Convert a shared lifecycle handler's output to the native Cursor envelope. */
|
|
6881
|
+
function toCursorLifecycleResponse(stdout, eventName) {
|
|
6882
|
+
const contract = cursorEventContract(eventName);
|
|
6883
|
+
const native = parseNativeCursorStdout(stdout, eventName);
|
|
6884
|
+
if (native !== null) return native;
|
|
6885
|
+
let text = stdout;
|
|
6886
|
+
let decision;
|
|
6887
|
+
let userMessage = "";
|
|
6888
|
+
let agentMessage = "";
|
|
6889
|
+
let decisionMessage = "";
|
|
6890
|
+
let structured = false;
|
|
6891
|
+
try {
|
|
6892
|
+
const parsed = JSON.parse(stdout);
|
|
6893
|
+
const subagentAsk = eventName === "subagentStart" && isRecord(parsed) && Object.hasOwn(parsed, "permission") && parsed.permission === "ask";
|
|
6894
|
+
const shared = isRecord(parsed) ? parsed : {};
|
|
6895
|
+
structured = true;
|
|
6896
|
+
decision = shared.hookSpecificOutput?.permissionDecision ?? (subagentAsk ? "ask" : void 0);
|
|
6897
|
+
userMessage = shared.systemMessage ?? (subagentAsk && Object.hasOwn(shared, "user_message") && typeof shared.user_message === "string" ? shared.user_message : "");
|
|
6898
|
+
decisionMessage = joinMessages(shared.hookSpecificOutput?.permissionDecisionReason, shared.reason);
|
|
6899
|
+
agentMessage = joinMessages(shared.hookSpecificOutput?.additionalContext, decisionMessage);
|
|
6900
|
+
text = joinMessages(agentMessage, userMessage, shared.followup_message);
|
|
6901
|
+
} catch {
|
|
6902
|
+
text = stdout;
|
|
6903
|
+
}
|
|
6904
|
+
if (contract.response === "neutral") return "{}";
|
|
6905
|
+
if (!text) return contract.response === "permission" ? "{\"permission\":\"allow\"}" : "{}";
|
|
6906
|
+
if (contract.response === "session-context" || contract.response === "post-context") return JSON.stringify({ additional_context: text });
|
|
6907
|
+
if (contract.response === "permission") {
|
|
6908
|
+
const permission = decision === "deny" || decision === "ask" ? "deny" : "allow";
|
|
6909
|
+
const denied = permission === "deny";
|
|
6910
|
+
if (eventName === "subagentStart" && !denied) return "{\"permission\":\"allow\"}";
|
|
6911
|
+
return JSON.stringify({
|
|
6912
|
+
permission,
|
|
6913
|
+
...permissionMessages(eventName, userMessage || (denied ? decisionMessage || agentMessage : ""), agentMessage || (denied ? decisionMessage || userMessage : structured ? "" : text))
|
|
6914
|
+
});
|
|
6915
|
+
}
|
|
6916
|
+
if (contract.response === "followup") return JSON.stringify({ followup_message: text });
|
|
6917
|
+
if (contract.response === "compact-notice") return JSON.stringify({ user_message: text });
|
|
6918
|
+
if (contract.response === "submit-control") return JSON.stringify({
|
|
6919
|
+
continue: true,
|
|
6920
|
+
user_message: text
|
|
6921
|
+
});
|
|
6922
|
+
return "{}";
|
|
6923
|
+
}
|
|
6924
|
+
//#endregion
|
|
6649
6925
|
//#region src/runtime/lifecycle-bridge.ts
|
|
6650
6926
|
/** Raw event name from a payload (Cline lacks one; lifecycle is Claude-only). */
|
|
6651
6927
|
function rawEvent(payload) {
|
|
6652
6928
|
return typeof payload.hook_event_name === "string" ? payload.hook_event_name : "";
|
|
6653
6929
|
}
|
|
6654
6930
|
/** Extract the `additionalContext` body from a `contextResponse(...)` stdout string ("" when empty/unparseable). */
|
|
6655
|
-
function additionalContextOf(stdout) {
|
|
6931
|
+
function additionalContextOf$1(stdout) {
|
|
6656
6932
|
if (!stdout) return "";
|
|
6657
6933
|
try {
|
|
6658
6934
|
return JSON.parse(stdout).hookSpecificOutput?.additionalContext ?? "";
|
|
@@ -6673,14 +6949,30 @@ function additionalContextOf(stdout) {
|
|
|
6673
6949
|
* @returns The native stdout, or `null` when unhandled.
|
|
6674
6950
|
*/
|
|
6675
6951
|
function lifecycleStdout(payload, cwd, scope, now, id = "claude-code") {
|
|
6676
|
-
|
|
6677
|
-
|
|
6952
|
+
const wireEvent = rawEvent(payload);
|
|
6953
|
+
if (id !== "cursor") return dispatchLifecycle({
|
|
6954
|
+
event: wireEvent,
|
|
6678
6955
|
payload,
|
|
6679
6956
|
cwd,
|
|
6680
6957
|
scope,
|
|
6681
6958
|
now,
|
|
6682
6959
|
id
|
|
6683
6960
|
});
|
|
6961
|
+
const lifecycleEvent = cursorEventContract(wireEvent).lifecycle;
|
|
6962
|
+
if (lifecycleEvent === null) return null;
|
|
6963
|
+
const sessionId = typeof payload.session_id === "string" ? payload.session_id : payload.conversation_id;
|
|
6964
|
+
const stdout = dispatchLifecycle({
|
|
6965
|
+
event: lifecycleEvent,
|
|
6966
|
+
payload: {
|
|
6967
|
+
...payload,
|
|
6968
|
+
session_id: sessionId
|
|
6969
|
+
},
|
|
6970
|
+
cwd,
|
|
6971
|
+
scope,
|
|
6972
|
+
now,
|
|
6973
|
+
id
|
|
6974
|
+
});
|
|
6975
|
+
return stdout === null ? null : toCursorLifecycleResponse(stdout, wireEvent);
|
|
6684
6976
|
}
|
|
6685
6977
|
/**
|
|
6686
6978
|
* Post-edit additions for core-scope PostToolUse: auto-document a Read of a
|
|
@@ -6702,7 +6994,7 @@ async function postEditContext(scope, event, now, id = "claude-code") {
|
|
|
6702
6994
|
const sniper = trackSessionChanges(event.sessionId, event.filePath, void 0, now);
|
|
6703
6995
|
const lint = postEditTypescript(event.filePath);
|
|
6704
6996
|
if (!sniper || !lint) return sniper || lint;
|
|
6705
|
-
return contextResponse("PostToolUse", `${additionalContextOf(sniper)}\n\n${additionalContextOf(lint)}`);
|
|
6997
|
+
return contextResponse("PostToolUse", `${additionalContextOf$1(sniper)}\n\n${additionalContextOf$1(lint)}`);
|
|
6706
6998
|
}
|
|
6707
6999
|
//#endregion
|
|
6708
7000
|
//#region src/policy/trivial-edits.ts
|
|
@@ -7694,11 +7986,37 @@ const TRIVIAL_BUDGET = 4;
|
|
|
7694
7986
|
* {@link withDenyLoop} rewrite an identical retried deny (decision unchanged).
|
|
7695
7987
|
*/
|
|
7696
7988
|
async function gate(input) {
|
|
7697
|
-
|
|
7989
|
+
return finalizeGate(input, await runGates(input), input.command);
|
|
7990
|
+
}
|
|
7991
|
+
/**
|
|
7992
|
+
* Gate independent Cursor command candidates without merging their shell syntax.
|
|
7993
|
+
* Stateful outcome bookkeeping runs once, against the command that decided the
|
|
7994
|
+
* aggregate result. A single distinct candidate follows {@link gate} verbatim.
|
|
7995
|
+
*/
|
|
7996
|
+
async function gateCommandCandidates(input, candidates) {
|
|
7997
|
+
const distinct = [...new Set(candidates)];
|
|
7998
|
+
if (distinct.length <= 1) return gate(input);
|
|
7999
|
+
let decisive;
|
|
8000
|
+
for (const command of distinct) {
|
|
8001
|
+
const prompt = await runGates({
|
|
8002
|
+
...input,
|
|
8003
|
+
command
|
|
8004
|
+
});
|
|
8005
|
+
if (!prompt) continue;
|
|
8006
|
+
if (!decisive || promptRank(prompt) > promptRank(decisive.prompt)) decisive = {
|
|
8007
|
+
prompt,
|
|
8008
|
+
command
|
|
8009
|
+
};
|
|
8010
|
+
if (prompt.kind === "block") break;
|
|
8011
|
+
}
|
|
8012
|
+
return finalizeGate(input, decisive?.prompt ?? null, decisive?.command ?? input.command);
|
|
8013
|
+
}
|
|
8014
|
+
/** Persist one final gate outcome and apply deny-loop enrichment exactly once. */
|
|
8015
|
+
function finalizeGate(input, prompt, command) {
|
|
7698
8016
|
const op = {
|
|
7699
8017
|
filePath: input.filePath,
|
|
7700
8018
|
content: input.content,
|
|
7701
|
-
command
|
|
8019
|
+
command
|
|
7702
8020
|
};
|
|
7703
8021
|
const dir = dirname(input.trackFile);
|
|
7704
8022
|
recordOneShot(prompt, op, {
|
|
@@ -7713,6 +8031,10 @@ async function gate(input) {
|
|
|
7713
8031
|
sessionId: input.sessionId
|
|
7714
8032
|
});
|
|
7715
8033
|
}
|
|
8034
|
+
/** Higher numeric values dominate while equal values preserve wire order. */
|
|
8035
|
+
function promptRank(prompt) {
|
|
8036
|
+
return prompt.kind === "block" ? 3 : prompt.kind === "ask" ? 2 : 1;
|
|
8037
|
+
}
|
|
7716
8038
|
/** Stateless guards, then the trivial fast path, then the stateful APEX gates. */
|
|
7717
8039
|
async function runGates(input) {
|
|
7718
8040
|
const precommit = preCommitGate(input.tool, input.command, input.cwd);
|
|
@@ -7900,8 +8222,8 @@ async function recordActivity(file, activity) {
|
|
|
7900
8222
|
* - gemini-cli/cline: their real hook schemas have no interactive "ask"
|
|
7901
8223
|
* state (deny is the only blocking outcome), so `ask` and `inform` already
|
|
7902
8224
|
* both resolve to non-blocking context injection — unchanged.
|
|
7903
|
-
* - cursor: `ask`
|
|
7904
|
-
*
|
|
8225
|
+
* - cursor: `ask` degrades to a native `permission:"deny"` because Cursor does
|
|
8226
|
+
* not reliably apply `ask` on `preToolUse`; `inform` stays non-blocking.
|
|
7905
8227
|
* - hermes: delegated to the adapter's `toHermesResponse` — `block` ->
|
|
7906
8228
|
* `{decision:"block",reason}`; `ask`/`inform` degrade to non-blocking
|
|
7907
8229
|
* `{context}` (Hermes has no interactive "ask" state).
|
|
@@ -7955,25 +8277,7 @@ function respond(id, prompt, event = "PreToolUse") {
|
|
|
7955
8277
|
systemMessage: userMessage
|
|
7956
8278
|
});
|
|
7957
8279
|
return JSON.stringify({ hookSpecificOutput: { additionalContext: message } });
|
|
7958
|
-
case "cursor":
|
|
7959
|
-
if (kind === "inform") {
|
|
7960
|
-
if (userMessage) return JSON.stringify({
|
|
7961
|
-
permission: "allow",
|
|
7962
|
-
user_message: userMessage,
|
|
7963
|
-
...reason ? { agent_message: message } : {}
|
|
7964
|
-
});
|
|
7965
|
-
return JSON.stringify({
|
|
7966
|
-
permission: "allow",
|
|
7967
|
-
user_message: message,
|
|
7968
|
-
agent_message: message
|
|
7969
|
-
});
|
|
7970
|
-
}
|
|
7971
|
-
return JSON.stringify({
|
|
7972
|
-
permission: kind === "block" ? "deny" : "ask",
|
|
7973
|
-
continue: false,
|
|
7974
|
-
user_message: message,
|
|
7975
|
-
agent_message: message
|
|
7976
|
-
});
|
|
8280
|
+
case "cursor": return toCursorResponse(prompt, event === "PreToolUse" ? "preToolUse" : event);
|
|
7977
8281
|
case "hermes": return toHermesResponse(prompt);
|
|
7978
8282
|
case "kimi": return toKimiResponse(prompt);
|
|
7979
8283
|
case "cline":
|
|
@@ -8658,8 +8962,8 @@ function segments(command) {
|
|
|
8658
8962
|
}
|
|
8659
8963
|
/** Strip a redirection (`>`, `>>`, `<`, `2>`, `&>`, …) and everything after — its target is WRITTEN, not read. */
|
|
8660
8964
|
function beforeRedirect(segment) {
|
|
8661
|
-
const
|
|
8662
|
-
return
|
|
8965
|
+
const first = shellOutputRedirects(segment)[0];
|
|
8966
|
+
return first ? segment.slice(0, first.start) : segment;
|
|
8663
8967
|
}
|
|
8664
8968
|
/** Naive shell tokenizer: whitespace-split, stripping one matching layer of quotes per token. */
|
|
8665
8969
|
function tokenize(segment) {
|
|
@@ -9155,7 +9459,7 @@ async function allowOutcome(id, event, payload, mcpDir, cwd, evidence, corpusRoo
|
|
|
9155
9459
|
stdout: respond(id, userMessage ? {
|
|
9156
9460
|
...lesson,
|
|
9157
9461
|
userMessage
|
|
9158
|
-
} : lesson),
|
|
9462
|
+
} : lesson, event.eventName ?? "PreToolUse"),
|
|
9159
9463
|
exit: 0
|
|
9160
9464
|
};
|
|
9161
9465
|
}
|
|
@@ -9170,12 +9474,12 @@ async function allowOutcome(id, event, payload, mcpDir, cwd, evidence, corpusRoo
|
|
|
9170
9474
|
title: "APEX freshness",
|
|
9171
9475
|
reason: "",
|
|
9172
9476
|
userMessage
|
|
9173
|
-
}),
|
|
9477
|
+
}, event.eventName ?? "PreToolUse"),
|
|
9174
9478
|
exit: 0
|
|
9175
9479
|
};
|
|
9176
9480
|
}
|
|
9177
9481
|
return {
|
|
9178
|
-
stdout: notice ? respond(id, notice) : "",
|
|
9482
|
+
stdout: notice ? respond(id, notice, event.eventName ?? "PreToolUse") : "",
|
|
9179
9483
|
exit: 0
|
|
9180
9484
|
};
|
|
9181
9485
|
}
|
|
@@ -9316,7 +9620,7 @@ function getPendingDeny(sessionIdRaw, home = homedir()) {
|
|
|
9316
9620
|
//#endregion
|
|
9317
9621
|
//#region src/runtime/confirm/confirm-state.ts
|
|
9318
9622
|
/** Confirmation freshness window (G2) — 5 minutes, matches the validated prototype. */
|
|
9319
|
-
const TTL_MS = 300 * 1e3;
|
|
9623
|
+
const TTL_MS$1 = 300 * 1e3;
|
|
9320
9624
|
/**
|
|
9321
9625
|
* Pose a confirmation token for this session's pending action. No-op while
|
|
9322
9626
|
* {@link isSubagentActive} (G0, confirm-subagent.ts) — the sole gate that
|
|
@@ -9356,7 +9660,7 @@ function consumeConfirmToken(sessionIdRaw, hash, now, home = homedir()) {
|
|
|
9356
9660
|
if (!sid) return false;
|
|
9357
9661
|
const tok = loadSessionState(sid, home).confirmToken;
|
|
9358
9662
|
if (!tok || tok.hash !== hash) return false;
|
|
9359
|
-
if (now - tok.ts > TTL_MS) {
|
|
9663
|
+
if (now - tok.ts > TTL_MS$1) {
|
|
9360
9664
|
dropConfirmToken(sid, home);
|
|
9361
9665
|
return false;
|
|
9362
9666
|
}
|
|
@@ -9364,6 +9668,141 @@ function consumeConfirmToken(sessionIdRaw, hash, now, home = homedir()) {
|
|
|
9364
9668
|
return true;
|
|
9365
9669
|
}
|
|
9366
9670
|
//#endregion
|
|
9671
|
+
//#region src/runtime/confirm/codex-confirm.ts
|
|
9672
|
+
const TTL_MS = 300 * 1e3;
|
|
9673
|
+
const STATE_VERSION = 1;
|
|
9674
|
+
function statePath(sid, home) {
|
|
9675
|
+
return join(sessionsDir(home), `codex-confirm-${sid}.json`);
|
|
9676
|
+
}
|
|
9677
|
+
function lockDir(sid, home) {
|
|
9678
|
+
return join(sessionsDir(home), ".confirm-locks", sid);
|
|
9679
|
+
}
|
|
9680
|
+
function loadState(sid, home) {
|
|
9681
|
+
const path = statePath(sid, home);
|
|
9682
|
+
if (!existsSync(path)) return {};
|
|
9683
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
9684
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
9685
|
+
}
|
|
9686
|
+
function saveState(sid, state, home) {
|
|
9687
|
+
mkdirSync(sessionsDir(home), {
|
|
9688
|
+
recursive: true,
|
|
9689
|
+
mode: 448
|
|
9690
|
+
});
|
|
9691
|
+
atomicWrite(statePath(sid, home), JSON.stringify(state, null, 2));
|
|
9692
|
+
}
|
|
9693
|
+
/** Canonical identity of one Codex shell action and its display token. */
|
|
9694
|
+
function codexAction(tool, cwd, command, now) {
|
|
9695
|
+
const canonicalCommand = commandToString(command);
|
|
9696
|
+
if (!canonicalCommand) return null;
|
|
9697
|
+
const identity = JSON.stringify({
|
|
9698
|
+
version: STATE_VERSION,
|
|
9699
|
+
harness: "codex",
|
|
9700
|
+
tool,
|
|
9701
|
+
cwd: resolve(cwd),
|
|
9702
|
+
command: canonicalCommand
|
|
9703
|
+
});
|
|
9704
|
+
return {
|
|
9705
|
+
hash: hashForAction(identity),
|
|
9706
|
+
code: displayCodeForAction(identity),
|
|
9707
|
+
command: canonicalCommand,
|
|
9708
|
+
ts: now
|
|
9709
|
+
};
|
|
9710
|
+
}
|
|
9711
|
+
/** Atomically authorize or reject a Codex action, recording the current denial when needed. */
|
|
9712
|
+
function authorizeCodexAction(sessionIdRaw, action, toolUseId, now, home = homedir()) {
|
|
9713
|
+
const sid = sanitizeSessionId(sessionIdRaw);
|
|
9714
|
+
if (!sid) return {
|
|
9715
|
+
allow: false,
|
|
9716
|
+
reason: "state-io"
|
|
9717
|
+
};
|
|
9718
|
+
try {
|
|
9719
|
+
const result = withTrackLockSync(lockDir(sid, home), () => {
|
|
9720
|
+
const state = loadState(sid, home);
|
|
9721
|
+
const token = state.codexConfirmToken;
|
|
9722
|
+
const receipt = state.codexConfirmReceipt;
|
|
9723
|
+
const receiptExpired = receipt !== void 0 && now - receipt.ts > TTL_MS;
|
|
9724
|
+
if (!receiptExpired && receipt?.hash === action.hash && receipt.toolUseId === toolUseId && toolUseId) return { allow: true };
|
|
9725
|
+
let reason = "no-token";
|
|
9726
|
+
if (token) if (token.hash !== action.hash) reason = "mismatch";
|
|
9727
|
+
else if (now - token.ts > TTL_MS) reason = "expired";
|
|
9728
|
+
else if (!toolUseId) reason = "missing-tool-use-id";
|
|
9729
|
+
else {
|
|
9730
|
+
const { codexConfirmToken: _token, codexConfirmPending: _pending, ...rest } = state;
|
|
9731
|
+
saveState(sid, {
|
|
9732
|
+
...rest,
|
|
9733
|
+
codexConfirmReceipt: {
|
|
9734
|
+
...action,
|
|
9735
|
+
toolUseId
|
|
9736
|
+
}
|
|
9737
|
+
}, home);
|
|
9738
|
+
return { allow: true };
|
|
9739
|
+
}
|
|
9740
|
+
else if (receipt?.hash === action.hash) reason = receiptExpired ? "expired" : "already-consumed";
|
|
9741
|
+
if (reason === "missing-tool-use-id") return {
|
|
9742
|
+
allow: false,
|
|
9743
|
+
reason
|
|
9744
|
+
};
|
|
9745
|
+
const pending = state.codexConfirmPending;
|
|
9746
|
+
const stablePending = pending?.hash === action.hash ? pending : action;
|
|
9747
|
+
const { codexConfirmToken: _token, codexConfirmReceipt: _receipt, ...withoutReceipt } = state;
|
|
9748
|
+
const rest = receiptExpired ? withoutReceipt : {
|
|
9749
|
+
...withoutReceipt,
|
|
9750
|
+
codexConfirmReceipt: receipt
|
|
9751
|
+
};
|
|
9752
|
+
saveState(sid, {
|
|
9753
|
+
...rest,
|
|
9754
|
+
codexConfirmPending: stablePending
|
|
9755
|
+
}, home);
|
|
9756
|
+
return {
|
|
9757
|
+
allow: false,
|
|
9758
|
+
reason
|
|
9759
|
+
};
|
|
9760
|
+
});
|
|
9761
|
+
return result === LOCK_FAILED ? {
|
|
9762
|
+
allow: false,
|
|
9763
|
+
reason: "state-io"
|
|
9764
|
+
} : result;
|
|
9765
|
+
} catch {
|
|
9766
|
+
return {
|
|
9767
|
+
allow: false,
|
|
9768
|
+
reason: "state-io"
|
|
9769
|
+
};
|
|
9770
|
+
}
|
|
9771
|
+
}
|
|
9772
|
+
/**
|
|
9773
|
+
* Atomically arm the last Codex denial, consuming its pending record exactly once.
|
|
9774
|
+
* A classified root prompt may bypass G0; classified subagent/unknown prompts fail closed.
|
|
9775
|
+
*/
|
|
9776
|
+
function submitCodexConfirmation(sessionIdRaw, text, now, home = homedir(), origin) {
|
|
9777
|
+
const sid = sanitizeSessionId(sessionIdRaw);
|
|
9778
|
+
if (!sid) return;
|
|
9779
|
+
const refusal = /\b(non|no|stop|annule|cancel|abort|nope|laisse tomber|pas maintenant)\b/i.test(text);
|
|
9780
|
+
const typedCode = text.trim().match(/^confirm[ _-]*([0-9a-f]{4})$/i)?.[1];
|
|
9781
|
+
try {
|
|
9782
|
+
withTrackLockSync(lockDir(sid, home), () => {
|
|
9783
|
+
const state = loadState(sid, home);
|
|
9784
|
+
if (origin !== void 0 && origin !== "root") return;
|
|
9785
|
+
if (refusal) {
|
|
9786
|
+
const { codexConfirmPending: _pending, codexConfirmToken: _token, ...rest } = state;
|
|
9787
|
+
saveState(sid, rest, home);
|
|
9788
|
+
return;
|
|
9789
|
+
}
|
|
9790
|
+
if (!typedCode) return;
|
|
9791
|
+
if (origin === void 0 && isSubagentActive(sid, now, home)) return;
|
|
9792
|
+
const pending = state.codexConfirmPending;
|
|
9793
|
+
if (!pending || pending.code.toLowerCase() !== typedCode.toLowerCase()) return;
|
|
9794
|
+
const { codexConfirmPending: _pending, ...rest } = state;
|
|
9795
|
+
saveState(sid, {
|
|
9796
|
+
...rest,
|
|
9797
|
+
codexConfirmToken: {
|
|
9798
|
+
...pending,
|
|
9799
|
+
ts: now
|
|
9800
|
+
}
|
|
9801
|
+
}, home);
|
|
9802
|
+
});
|
|
9803
|
+
} catch {}
|
|
9804
|
+
}
|
|
9805
|
+
//#endregion
|
|
9367
9806
|
//#region src/runtime/confirm/confirm-gate.ts
|
|
9368
9807
|
/**
|
|
9369
9808
|
* Harnesses where `respond.ts` silently downgrades `kind: "ask"` to a hard
|
|
@@ -9387,9 +9826,23 @@ const DEGRADES_ASK_TO_DENY = /* @__PURE__ */ new Set(["codex", "kimi"]);
|
|
|
9387
9826
|
* @param now - Epoch ms.
|
|
9388
9827
|
* @param home - Test-only OS home override.
|
|
9389
9828
|
*/
|
|
9390
|
-
function confirmGate(id, prompt, command, sessionId, now, home) {
|
|
9829
|
+
function confirmGate(id, prompt, command, sessionId, now, home, codex) {
|
|
9391
9830
|
if (prompt.kind !== "ask" || !DEGRADES_ASK_TO_DENY.has(id) || !command || isIrreversible(command)) return null;
|
|
9392
9831
|
try {
|
|
9832
|
+
if (id === "codex" && codex) {
|
|
9833
|
+
const action = codexAction(codex.tool, codex.cwd, command, now);
|
|
9834
|
+
if (!action) return null;
|
|
9835
|
+
const verdict = authorizeCodexAction(sessionId, action, codex.toolUseId, now, home);
|
|
9836
|
+
if (verdict.allow) return verdict;
|
|
9837
|
+
const diagnostic = `rule ID: ${prompt.ruleId ?? "policy:ask"}\ncanonical command: ${action.command}\nexpected token: CONFIRM ${action.code}\nrejection: ${verdict.reason}`;
|
|
9838
|
+
return {
|
|
9839
|
+
allow: false,
|
|
9840
|
+
prompt: {
|
|
9841
|
+
...prompt,
|
|
9842
|
+
reason: `${prompt.reason}\nPour autoriser, réponds : CONFIRM ${action.code}\n${diagnostic}`
|
|
9843
|
+
}
|
|
9844
|
+
};
|
|
9845
|
+
}
|
|
9393
9846
|
const hash = hashForAction(command);
|
|
9394
9847
|
if (consumeConfirmToken(sessionId, hash, now, home)) return { allow: true };
|
|
9395
9848
|
const code = displayCodeForAction(command);
|
|
@@ -9430,9 +9883,19 @@ async function handlePre(ctx) {
|
|
|
9430
9883
|
}
|
|
9431
9884
|
const designBlock = designGate(payload, event, designCacheDir, opts.cwd, opts.corpusRoot);
|
|
9432
9885
|
if (designBlock) return {
|
|
9433
|
-
stdout: withDenyNotice(id, respond(id, designBlock), designBlock, event.sessionId, dirname(file), opts.now),
|
|
9886
|
+
stdout: withDenyNotice(id, respond(id, designBlock, event.eventName ?? "PreToolUse"), designBlock, event.sessionId, dirname(file), opts.now),
|
|
9434
9887
|
exit: 0
|
|
9435
9888
|
};
|
|
9889
|
+
if (id === "cursor" && (event.eventName === "beforeReadFile" || event.eventName === "beforeTabFileRead")) {
|
|
9890
|
+
const readPolicy = evaluate({
|
|
9891
|
+
tool: event.tool,
|
|
9892
|
+
filePath: event.filePath
|
|
9893
|
+
});
|
|
9894
|
+
return {
|
|
9895
|
+
stdout: readPolicy.prompt ? respond(id, readPolicy.prompt, event.eventName) : JSON.stringify({ permission: "allow" }),
|
|
9896
|
+
exit: 0
|
|
9897
|
+
};
|
|
9898
|
+
}
|
|
9436
9899
|
if (opts.scope === "security") return {
|
|
9437
9900
|
stdout: event.files?.length ? securityAdvisoryForPatch(event.files, opts.now) : securityAdvisory(event.tool, event.filePath ?? "", opts.now),
|
|
9438
9901
|
exit: 0
|
|
@@ -9448,11 +9911,12 @@ async function handlePre(ctx) {
|
|
|
9448
9911
|
if (event.files && event.files.length > 0) {
|
|
9449
9912
|
const patchPrompt = applyPatchGate(event.files, opts.cwd);
|
|
9450
9913
|
if (patchPrompt) return {
|
|
9451
|
-
stdout: withDenyNotice(id, respond(id, patchPrompt), patchPrompt, event.sessionId, dirname(file), opts.now),
|
|
9914
|
+
stdout: withDenyNotice(id, respond(id, patchPrompt, event.eventName ?? "PreToolUse"), patchPrompt, event.sessionId, dirname(file), opts.now),
|
|
9452
9915
|
exit: 0
|
|
9453
9916
|
};
|
|
9454
9917
|
}
|
|
9455
|
-
const
|
|
9918
|
+
const refs = opts.refsDir ? await loadRefs(opts.refsDir) : void 0;
|
|
9919
|
+
const gateInput = {
|
|
9456
9920
|
sessionId: event.sessionId,
|
|
9457
9921
|
framework,
|
|
9458
9922
|
tool: event.tool,
|
|
@@ -9460,7 +9924,7 @@ async function handlePre(ctx) {
|
|
|
9460
9924
|
content: event.content,
|
|
9461
9925
|
command: event.command,
|
|
9462
9926
|
cwd: opts.cwd,
|
|
9463
|
-
refs
|
|
9927
|
+
refs,
|
|
9464
9928
|
isReplaceAll: event.input.replace_all === true,
|
|
9465
9929
|
oldString: event.oldString,
|
|
9466
9930
|
agentType: event.agentType,
|
|
@@ -9470,9 +9934,14 @@ async function handlePre(ctx) {
|
|
|
9470
9934
|
trackFile: file,
|
|
9471
9935
|
transcriptPath: typeof payload.transcript_path === "string" ? payload.transcript_path : void 0,
|
|
9472
9936
|
neverApproval: id === "codex" && isBypassPermissions(event.permissionMode)
|
|
9473
|
-
}
|
|
9937
|
+
};
|
|
9938
|
+
const prompt = id === "cursor" && (event.commandCandidates?.length ?? 0) > 1 ? await gateCommandCandidates(gateInput, event.commandCandidates) : await gate(gateInput);
|
|
9474
9939
|
if (prompt) {
|
|
9475
|
-
const confirm = confirmGate(id, prompt, event.command, event.sessionId, opts.now, opts.home
|
|
9940
|
+
const confirm = confirmGate(id, prompt, event.command, event.sessionId, opts.now, opts.home, id === "codex" ? {
|
|
9941
|
+
tool: event.tool,
|
|
9942
|
+
cwd: event.cwd ?? opts.cwd,
|
|
9943
|
+
toolUseId: event.toolUseId
|
|
9944
|
+
} : void 0);
|
|
9476
9945
|
if (confirm?.allow) return allowOutcome(id, event, payload, designCacheDir, opts.cwd, {
|
|
9477
9946
|
trackFile: file,
|
|
9478
9947
|
windowMs: opts.windowMs,
|
|
@@ -9480,7 +9949,7 @@ async function handlePre(ctx) {
|
|
|
9480
9949
|
}, opts.corpusRoot);
|
|
9481
9950
|
const finalPrompt = confirm ? confirm.prompt : prompt;
|
|
9482
9951
|
return {
|
|
9483
|
-
stdout: withDenyNotice(id, respond(id, finalPrompt), finalPrompt, event.sessionId, dirname(file), opts.now),
|
|
9952
|
+
stdout: withDenyNotice(id, respond(id, finalPrompt, event.eventName ?? "PreToolUse"), finalPrompt, event.sessionId, dirname(file), opts.now),
|
|
9484
9953
|
exit: 0
|
|
9485
9954
|
};
|
|
9486
9955
|
}
|
|
@@ -9847,14 +10316,14 @@ function recordCodexPostFailure(tool, result, opts) {
|
|
|
9847
10316
|
//#endregion
|
|
9848
10317
|
//#region src/runtime/post-fanout.ts
|
|
9849
10318
|
/**
|
|
9850
|
-
* Fan
|
|
10319
|
+
* Fan Codex `apply_patch` or Cursor `afterFileEdit` `event.files` into one
|
|
9851
10320
|
* per-file event per touched file, so the per-file PostToolUse gates (SOLID
|
|
9852
10321
|
* size, Tailwind, tracking, post-edit context) see EACH file instead of the
|
|
9853
10322
|
* whole patch (whose own `filePath`/`content` are always undefined). `add`
|
|
9854
10323
|
* maps to `Write`, `update` to `Edit` (mirrors the Pre-phase `applyPatchGate`'s
|
|
9855
10324
|
* tool mapping); `delete`/`move` map to a tool none of those Write|Edit-gated
|
|
9856
10325
|
* checks recognize, so they no-op on it without special-casing each gate.
|
|
9857
|
-
* Returns `[event]` unchanged
|
|
10326
|
+
* Returns `[event]` unchanged when no per-file changes are present.
|
|
9858
10327
|
* @param event - The normalized PostToolUse event.
|
|
9859
10328
|
* @returns One event per touched file, or the original event.
|
|
9860
10329
|
*/
|
|
@@ -9864,7 +10333,8 @@ function fanOutFiles(event) {
|
|
|
9864
10333
|
...event,
|
|
9865
10334
|
tool: f.op === "add" ? "Write" : f.op === "update" ? "Edit" : "apply_patch:delete",
|
|
9866
10335
|
filePath: f.filePath,
|
|
9867
|
-
content: f.op === "delete" ? void 0 : f.content
|
|
10336
|
+
content: f.op === "delete" ? void 0 : f.content,
|
|
10337
|
+
oldString: f.oldString
|
|
9868
10338
|
}));
|
|
9869
10339
|
}
|
|
9870
10340
|
/**
|
|
@@ -9884,7 +10354,106 @@ function firstFileMatch(files, check) {
|
|
|
9884
10354
|
return "";
|
|
9885
10355
|
}
|
|
9886
10356
|
//#endregion
|
|
10357
|
+
//#region src/runtime/post-outcome.ts
|
|
10358
|
+
/** Extract the additional-context body from a Claude-shaped post response. */
|
|
10359
|
+
function additionalContextOf(stdout) {
|
|
10360
|
+
if (!stdout) return "";
|
|
10361
|
+
try {
|
|
10362
|
+
return JSON.parse(stdout).hookSpecificOutput?.additionalContext ?? "";
|
|
10363
|
+
} catch {
|
|
10364
|
+
return "";
|
|
10365
|
+
}
|
|
10366
|
+
}
|
|
10367
|
+
function cursorPostToolOutput(eventName, designWarn, userMessage, extra) {
|
|
10368
|
+
if (!/^postToolUse$/i.test(eventName)) return "";
|
|
10369
|
+
const context = [
|
|
10370
|
+
designWarn ? formatPrompt(designWarn) : "",
|
|
10371
|
+
designWarn?.userMessage,
|
|
10372
|
+
userMessage,
|
|
10373
|
+
additionalContextOf(extra)
|
|
10374
|
+
].filter(Boolean).join("\n");
|
|
10375
|
+
return context ? JSON.stringify({ additional_context: context }) : "";
|
|
10376
|
+
}
|
|
10377
|
+
/**
|
|
10378
|
+
* Assemble the final PostToolUse response after all side effects and deny paths.
|
|
10379
|
+
* @param input - Final assembly values captured at their original evaluation times.
|
|
10380
|
+
* @returns The native hook outcome.
|
|
10381
|
+
*/
|
|
10382
|
+
function postOutcome(input) {
|
|
10383
|
+
const { id, agentId, sessionId, now, cwd, activities, files, designCacheDir, designWarn, extra, cursorAfterFileEdit, cursorEventName } = input;
|
|
10384
|
+
const noticeLines = [];
|
|
10385
|
+
for (const f of files) {
|
|
10386
|
+
const notice = designPassNotice({
|
|
10387
|
+
agentId,
|
|
10388
|
+
tool: f.tool,
|
|
10389
|
+
filePath: f.filePath ?? "",
|
|
10390
|
+
content: f.content ?? "",
|
|
10391
|
+
url: "",
|
|
10392
|
+
phase: "post"
|
|
10393
|
+
}, designCacheDir);
|
|
10394
|
+
if (notice?.userMessage) noticeLines.push(notice.userMessage);
|
|
10395
|
+
}
|
|
10396
|
+
const notice = noticeLines.length ? {
|
|
10397
|
+
kind: "inform",
|
|
10398
|
+
title: "Design pipeline",
|
|
10399
|
+
reason: "",
|
|
10400
|
+
userMessage: noticeLines.join("\n")
|
|
10401
|
+
} : null;
|
|
10402
|
+
const refNotice = refCreditNoticeFor(activities, sessionId, now, defaultStateDir(cwd));
|
|
10403
|
+
const userMessage = [notice?.userMessage, refNotice].filter(Boolean).join("\n") || void 0;
|
|
10404
|
+
if (cursorAfterFileEdit) return {
|
|
10405
|
+
stdout: "{}",
|
|
10406
|
+
exit: 0
|
|
10407
|
+
};
|
|
10408
|
+
if (id === "cursor") return {
|
|
10409
|
+
stdout: cursorPostToolOutput(cursorEventName, designWarn, userMessage, extra),
|
|
10410
|
+
exit: 0
|
|
10411
|
+
};
|
|
10412
|
+
if (designWarn) return {
|
|
10413
|
+
stdout: respond(id, userMessage ? {
|
|
10414
|
+
...designWarn,
|
|
10415
|
+
userMessage
|
|
10416
|
+
} : designWarn, "PostToolUse"),
|
|
10417
|
+
exit: 0
|
|
10418
|
+
};
|
|
10419
|
+
if (!userMessage) return {
|
|
10420
|
+
stdout: extra,
|
|
10421
|
+
exit: 0
|
|
10422
|
+
};
|
|
10423
|
+
const withUserMessage = notice ? {
|
|
10424
|
+
...notice,
|
|
10425
|
+
userMessage
|
|
10426
|
+
} : {
|
|
10427
|
+
kind: "inform",
|
|
10428
|
+
title: "Compliance",
|
|
10429
|
+
reason: "",
|
|
10430
|
+
userMessage
|
|
10431
|
+
};
|
|
10432
|
+
if (!extra) return {
|
|
10433
|
+
stdout: respond(id, withUserMessage, "PostToolUse"),
|
|
10434
|
+
exit: 0
|
|
10435
|
+
};
|
|
10436
|
+
if (id === "claude-code" || id === "codex") return {
|
|
10437
|
+
stdout: attachSystemMessage(extra, userMessage),
|
|
10438
|
+
exit: 0
|
|
10439
|
+
};
|
|
10440
|
+
if (id === "kimi") return {
|
|
10441
|
+
stdout: respond(id, withUserMessage, "PostToolUse"),
|
|
10442
|
+
exit: 0
|
|
10443
|
+
};
|
|
10444
|
+
return {
|
|
10445
|
+
stdout: respond(id, withUserMessage, "PostToolUse") || extra,
|
|
10446
|
+
exit: 0
|
|
10447
|
+
};
|
|
10448
|
+
}
|
|
10449
|
+
//#endregion
|
|
9887
10450
|
//#region src/runtime/handle-post.ts
|
|
10451
|
+
function isCursorAfterFileEdit(id, payload) {
|
|
10452
|
+
if (id !== "cursor") return false;
|
|
10453
|
+
const hookEvent = typeof payload.hook_event_name === "string" ? payload.hook_event_name : "";
|
|
10454
|
+
if (hookEvent) return /^afterFileEdit$/i.test(hookEvent);
|
|
10455
|
+
return typeof payload.file_path === "string" && Array.isArray(payload.edits);
|
|
10456
|
+
}
|
|
9888
10457
|
/**
|
|
9889
10458
|
* Run the PostToolUse pipeline: store the MCP response, emit a design warning,
|
|
9890
10459
|
* record the activity into the session track, apply per-scope side-effects (SEO
|
|
@@ -9907,8 +10476,14 @@ function firstFileMatch(files, check) {
|
|
|
9907
10476
|
*/
|
|
9908
10477
|
async function handlePost(ctx) {
|
|
9909
10478
|
const { id, payload, event, framework, mcpDir, file, opts } = ctx;
|
|
10479
|
+
const cursorAfterFileEdit = isCursorAfterFileEdit(id, payload);
|
|
9910
10480
|
const designCacheDir = ctx.designCacheDir ?? mcpDir;
|
|
9911
|
-
|
|
10481
|
+
let response = payload.tool_response ?? payload.tool_output;
|
|
10482
|
+
if (id === "cursor" && /^afterMCPExecution$/i.test(event.eventName ?? "")) try {
|
|
10483
|
+
response = typeof payload.result_json === "string" ? JSON.parse(payload.result_json) : payload.result_json;
|
|
10484
|
+
} catch {
|
|
10485
|
+
response = void 0;
|
|
10486
|
+
}
|
|
9912
10487
|
mcpPostStore(event.tool, event.input, response, mcpDir);
|
|
9913
10488
|
const designWarn = designGate(payload, event, designCacheDir, opts.cwd, opts.corpusRoot);
|
|
9914
10489
|
const activities = activityFor({
|
|
@@ -9932,27 +10507,27 @@ async function handlePost(ctx) {
|
|
|
9932
10507
|
const files = fanOutFiles(event);
|
|
9933
10508
|
for (const f of files) postTrackingSideEffects(opts.scope ?? "core", f, f.input, opts.now, payload, opts.cwd);
|
|
9934
10509
|
const seoDeny = opts.scope === "seo" ? seoPostToolUseResponse(payload) : null;
|
|
9935
|
-
if (seoDeny) return {
|
|
10510
|
+
if (seoDeny && !cursorAfterFileEdit) return {
|
|
9936
10511
|
stdout: seoDeny,
|
|
9937
10512
|
exit: 0
|
|
9938
10513
|
};
|
|
9939
10514
|
if (opts.scope === "solid") {
|
|
9940
10515
|
const solidWarn = firstFileMatch(files, checkFileSize);
|
|
9941
|
-
if (solidWarn) return {
|
|
10516
|
+
if (solidWarn && !cursorAfterFileEdit) return {
|
|
9942
10517
|
stdout: solidWarn,
|
|
9943
10518
|
exit: 0
|
|
9944
10519
|
};
|
|
9945
10520
|
}
|
|
9946
10521
|
if (opts.scope === "tailwindcss") {
|
|
9947
10522
|
const tailwindWarn = firstFileMatch(files, validateTailwind);
|
|
9948
|
-
if (tailwindWarn) return {
|
|
10523
|
+
if (tailwindWarn && !cursorAfterFileEdit) return {
|
|
9949
10524
|
stdout: tailwindWarn,
|
|
9950
10525
|
exit: 0
|
|
9951
10526
|
};
|
|
9952
10527
|
}
|
|
9953
10528
|
if (opts.scope === "aipilot" && (event.tool === "TaskCreate" || event.tool === "TaskUpdate" || event.tool === "Write" || event.tool === "Edit")) {
|
|
9954
10529
|
const out = await aipilotPostToolUse(payload, opts.cwd, id);
|
|
9955
|
-
if (out) return {
|
|
10530
|
+
if (out && !cursorAfterFileEdit) return {
|
|
9956
10531
|
stdout: out,
|
|
9957
10532
|
exit: 0
|
|
9958
10533
|
};
|
|
@@ -9962,63 +10537,20 @@ async function handlePost(ctx) {
|
|
|
9962
10537
|
extra = await postEditContext(opts.scope ?? "core", f, opts.now, id);
|
|
9963
10538
|
if (extra) break;
|
|
9964
10539
|
}
|
|
9965
|
-
|
|
9966
|
-
|
|
9967
|
-
|
|
9968
|
-
|
|
9969
|
-
|
|
9970
|
-
|
|
9971
|
-
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
|
|
9977
|
-
|
|
9978
|
-
|
|
9979
|
-
kind: "inform",
|
|
9980
|
-
title: "Design pipeline",
|
|
9981
|
-
reason: "",
|
|
9982
|
-
userMessage: noticeLines.join("\n")
|
|
9983
|
-
} : null;
|
|
9984
|
-
const refNotice = refCreditNoticeFor(activities, event.sessionId, opts.now, defaultStateDir(opts.cwd));
|
|
9985
|
-
const userMessage = [notice?.userMessage, refNotice].filter(Boolean).join("\n") || void 0;
|
|
9986
|
-
if (designWarn) return {
|
|
9987
|
-
stdout: respond(id, userMessage ? {
|
|
9988
|
-
...designWarn,
|
|
9989
|
-
userMessage
|
|
9990
|
-
} : designWarn, "PostToolUse"),
|
|
9991
|
-
exit: 0
|
|
9992
|
-
};
|
|
9993
|
-
if (!userMessage) return {
|
|
9994
|
-
stdout: extra,
|
|
9995
|
-
exit: 0
|
|
9996
|
-
};
|
|
9997
|
-
const withUserMessage = notice ? {
|
|
9998
|
-
...notice,
|
|
9999
|
-
userMessage
|
|
10000
|
-
} : {
|
|
10001
|
-
kind: "inform",
|
|
10002
|
-
title: "Compliance",
|
|
10003
|
-
reason: "",
|
|
10004
|
-
userMessage
|
|
10005
|
-
};
|
|
10006
|
-
if (!extra) return {
|
|
10007
|
-
stdout: respond(id, withUserMessage, "PostToolUse"),
|
|
10008
|
-
exit: 0
|
|
10009
|
-
};
|
|
10010
|
-
if (id === "claude-code" || id === "codex") return {
|
|
10011
|
-
stdout: attachSystemMessage(extra, userMessage),
|
|
10012
|
-
exit: 0
|
|
10013
|
-
};
|
|
10014
|
-
if (id === "kimi") return {
|
|
10015
|
-
stdout: respond(id, withUserMessage, "PostToolUse"),
|
|
10016
|
-
exit: 0
|
|
10017
|
-
};
|
|
10018
|
-
return {
|
|
10019
|
-
stdout: respond(id, withUserMessage, "PostToolUse") || extra,
|
|
10020
|
-
exit: 0
|
|
10021
|
-
};
|
|
10540
|
+
return postOutcome({
|
|
10541
|
+
id,
|
|
10542
|
+
agentId: typeof payload.agent_id === "string" ? payload.agent_id : "",
|
|
10543
|
+
sessionId: event.sessionId,
|
|
10544
|
+
now: opts.now,
|
|
10545
|
+
cwd: opts.cwd,
|
|
10546
|
+
activities,
|
|
10547
|
+
files,
|
|
10548
|
+
designCacheDir,
|
|
10549
|
+
designWarn,
|
|
10550
|
+
extra,
|
|
10551
|
+
cursorAfterFileEdit,
|
|
10552
|
+
cursorEventName: typeof payload.hook_event_name === "string" ? payload.hook_event_name : ""
|
|
10553
|
+
});
|
|
10022
10554
|
}
|
|
10023
10555
|
//#endregion
|
|
10024
10556
|
//#region src/runtime/handle-scope-async.ts
|
|
@@ -10038,9 +10570,12 @@ async function handlePost(ctx) {
|
|
|
10038
10570
|
* @returns The native stdout when intercepted, or `null` to fall through.
|
|
10039
10571
|
*/
|
|
10040
10572
|
async function asyncScopeStdout(scope, event, payload, cwd, now, id = "claude-code") {
|
|
10041
|
-
|
|
10042
|
-
if (
|
|
10043
|
-
|
|
10573
|
+
const dispatchedEvent = id === "cursor" ? cursorEventContract(event).lifecycle : event;
|
|
10574
|
+
if (dispatchedEvent === null) return null;
|
|
10575
|
+
let stdout = null;
|
|
10576
|
+
if (scope === "aipilot") stdout = await dispatchAipilot(dispatchedEvent, payload, cwd, now, void 0, id);
|
|
10577
|
+
if (scope === "memory") stdout = await dispatchMemory(dispatchedEvent, payload, cwd, now);
|
|
10578
|
+
return id === "cursor" && stdout !== null ? toCursorLifecycleResponse(stdout, event) : stdout;
|
|
10044
10579
|
}
|
|
10045
10580
|
//#endregion
|
|
10046
10581
|
//#region src/runtime/design-cache-resolve.ts
|
|
@@ -10509,6 +11044,18 @@ function handleConfirmSubmit(sessionId, text, now, home) {
|
|
|
10509
11044
|
} catch {}
|
|
10510
11045
|
}
|
|
10511
11046
|
//#endregion
|
|
11047
|
+
//#region src/runtime/confirm/codex-prompt-origin.ts
|
|
11048
|
+
const AGENT_FIELDS = ["agent_id", "agent_type"];
|
|
11049
|
+
/**
|
|
11050
|
+
* Classify Codex prompt provenance from its optional agent metadata.
|
|
11051
|
+
* Missing metadata is the observed root shape; malformed metadata fails closed.
|
|
11052
|
+
*/
|
|
11053
|
+
function codexPromptOrigin(payload) {
|
|
11054
|
+
const present = AGENT_FIELDS.filter((field) => Object.hasOwn(payload, field));
|
|
11055
|
+
if (present.length === 0) return "root";
|
|
11056
|
+
return present.every((field) => typeof payload[field] === "string" && payload[field].trim().length > 0) ? "subagent" : "unknown";
|
|
11057
|
+
}
|
|
11058
|
+
//#endregion
|
|
10512
11059
|
//#region src/runtime/handle.ts
|
|
10513
11060
|
/** Raw Claude hook event name from a payload (empty when absent). */
|
|
10514
11061
|
function rawEventName(payload) {
|
|
@@ -10520,8 +11067,18 @@ function rawEventName(payload) {
|
|
|
10520
11067
|
* POST event it records the activity into the track. The loop that makes the
|
|
10521
11068
|
* package behave like the Claude plugin, on any harness.
|
|
10522
11069
|
*/
|
|
10523
|
-
async function
|
|
11070
|
+
async function handleHookCore(id, payload, opts) {
|
|
10524
11071
|
const event = normalizeEvent(id, payload);
|
|
11072
|
+
if (id === "cursor") {
|
|
11073
|
+
const cursorCwd = cursorProjectCwd(event.cwd, event.workspaceRoots ?? [], event.filePath, opts.cwd);
|
|
11074
|
+
if (cursorCwd !== opts.cwd) opts = {
|
|
11075
|
+
...opts,
|
|
11076
|
+
cwd: cursorCwd
|
|
11077
|
+
};
|
|
11078
|
+
}
|
|
11079
|
+
const rawPrompt = payload.prompt;
|
|
11080
|
+
const userPrompt = typeof rawPrompt === "string" || Array.isArray(rawPrompt) ? promptText(rawPrompt) : void 0;
|
|
11081
|
+
if (id === "codex" && rawEventName(payload) === "UserPromptSubmit" && userPrompt !== void 0) submitCodexConfirmation(event.sessionId, userPrompt, opts.now, opts.home, codexPromptOrigin(payload));
|
|
10525
11082
|
resetFragmentRegistry();
|
|
10526
11083
|
const layout = projectLayout(opts.cwd);
|
|
10527
11084
|
const file = trackFile(event.sessionId, defaultStateDir(opts.cwd));
|
|
@@ -10543,10 +11100,8 @@ async function handleHook(id, payload, opts) {
|
|
|
10543
11100
|
stdout: id === "claude-code" ? attachBudgetRecap(life, rawEventName(payload), event.sessionId, opts.cwd, opts.now) : life,
|
|
10544
11101
|
exit: 0
|
|
10545
11102
|
};
|
|
10546
|
-
const rawPrompt = payload.prompt;
|
|
10547
|
-
const userPrompt = typeof rawPrompt === "string" || Array.isArray(rawPrompt) ? promptText(rawPrompt) : void 0;
|
|
10548
11103
|
if (userPrompt !== void 0) {
|
|
10549
|
-
handleConfirmSubmit(event.sessionId, userPrompt, opts.now, opts.home);
|
|
11104
|
+
if (id !== "codex") handleConfirmSubmit(event.sessionId, userPrompt, opts.now, opts.home);
|
|
10550
11105
|
await withTrack(file, (track) => recordBrainstormRequired(track, detectCreationIntent(userPrompt)));
|
|
10551
11106
|
return {
|
|
10552
11107
|
stdout: promptSubmitContext(userPrompt, opts.cwd, id),
|
|
@@ -10574,5 +11129,17 @@ async function handleHook(id, payload, opts) {
|
|
|
10574
11129
|
opts
|
|
10575
11130
|
});
|
|
10576
11131
|
}
|
|
11132
|
+
/**
|
|
11133
|
+
* Run one hook and adapt every Cursor scope outcome at the common runtime exit.
|
|
11134
|
+
* Other harnesses retain the core handler's stdout and exit status unchanged.
|
|
11135
|
+
*/
|
|
11136
|
+
async function handleHook(id, payload, opts) {
|
|
11137
|
+
const outcome = await handleHookCore(id, payload, opts);
|
|
11138
|
+
if (id !== "cursor") return outcome;
|
|
11139
|
+
return {
|
|
11140
|
+
...outcome,
|
|
11141
|
+
stdout: toCursorLifecycleResponse(outcome.stdout, rawEventName(payload))
|
|
11142
|
+
};
|
|
11143
|
+
}
|
|
10577
11144
|
//#endregion
|
|
10578
|
-
export {
|
|
11145
|
+
export { runDoctor as $, trackWatchResearch as A, taskContext as At, writePluginMap as B, todayUtc as Bt, postEditContext as C, removeOldFiles as Ct, securityAdvisory as D, projectContext as Dt, dispatchMemory as E, gitContext as Et, aipilotPostToolUse as F, isoUtc as Ft, mergeLines as G, isProject as H, dispatchAipilot as I, loadSecurityState as It, listChildren as J, countFiles as K, dispatchLessons as L, saveSecurityState as Lt, trackSkillRead as M, projectHash$1 as Mt, trackEnrichment as N, trackFile as Nt, securityAdvisoryForPatch as O, claudeMdKey as Ot, dispatchLifecycle as P, normalizeEvent as Pt, notify as Q, cartoSessionStart as R, securityStateDir as Rt, lifecycleStdout as S, purgeTtlTree as St, seoPostToolUseResponse as T, devContext as Tt, writeTree as U, generateProjectMap as V, loadEnriched as W, lessonsFileFor as X, lessonsArchiveFileFor as Y, lessonsStateFileFor as Z, gateCommandCandidates as _, injectRules as _t, recordActivity as a, cleanupSession as at, dryGate as b, sessionStartCore as bt, MCP_TTL_MS as c, validateTeammateOutput as ct, isMcpTool as d, validateTailwind as dt, runningVersion as et, queryOf as f, validateSolidGate as ft, gate as g, solidDetectStart as gt, TRIVIAL_BUDGET as h, detectSolidProfile as ht, respond as i, validateRulesLoaded as it, trackMcpResearch as j, defaultStateDir as jt, postTrackingSideEffects as k, promptSubmitContext as kt, WEBFETCH_TTL_MS as l, trackAgentMemory as lt, REQUIRED_AGENTS as m, countLoc as mt, activityFor as n, postEditTypescript as nt, mcpPostStore as o, saveApexState as ot, DEFAULT_WINDOW_MS as p, checkFileSize as pt, getFileDesc as q, handlePre as r, trackSessionChanges as rt, mcpPreIntercept as s, logToolFailure as st, handleHook as t, versionBanner as tt, cacheQueryOf as u, subagentCacheContext as ut, preCommitGate as v, readRules as vt, seoPostToolUse as w, trimLogFile as wt, extractSymbols as x, pruneEmptyDirs as xt, detectDuplication as y, runSessionStartCleanups as yt, generateEcosystemMap as z, securityStatePath as zt };
|