@fusengine/harness 0.1.89 → 0.1.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +5 -4
- 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-DHhukRdh.mjs → handle-C43gA-Pr.mjs} +737 -150
- 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/permission-mode-B-SFyR0X.mjs +226 -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
- package/dist/permission-mode-B0MUl7FT.mjs +0 -136
package/dist/cli/bin.mjs
CHANGED
|
@@ -3,9 +3,10 @@ import { o as resolveStdinMaxBytes } from "../limits-DG5pl-5s.mjs";
|
|
|
3
3
|
import { c as resolveTtlSec, r as loadDotenv } from "../dotenv-BLBkBTww.mjs";
|
|
4
4
|
import { t as detectHarness } from "../harness-BMuLJ9lm.mjs";
|
|
5
5
|
import { t as claudeHome } from "../home-state-oUGFB4ds.mjs";
|
|
6
|
-
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-
|
|
7
|
-
import { n as writeInitFile, t as initFor } from "../run-
|
|
8
|
-
import { $ as
|
|
6
|
+
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-DkrzC0gb.mjs";
|
|
7
|
+
import { n as writeInitFile, t as initFor } from "../run-GHAMqcOn.mjs";
|
|
8
|
+
import { $ as runDoctor, Bt as todayUtc, Q as notify, et as runningVersion, i as respond, t as handleHook, tt as versionBanner } from "../handle-C43gA-Pr.mjs";
|
|
9
|
+
import { r as cursorEventContract } from "../normalize-BjG6unTj.mjs";
|
|
9
10
|
import { delimiter, join } from "node:path";
|
|
10
11
|
import { existsSync, mkdirSync, readFileSync, readSync, readdirSync, writeFileSync } from "node:fs";
|
|
11
12
|
import { homedir } from "node:os";
|
|
@@ -999,6 +1000,386 @@ function parseScope(scopeArg, err = (m) => process.stderr.write(m)) {
|
|
|
999
1000
|
return scopeArg !== void 0 && VALID_SCOPES.has(scopeArg) ? scopeArg : "core";
|
|
1000
1001
|
}
|
|
1001
1002
|
//#endregion
|
|
1003
|
+
//#region src/cli/json-primitive-scanner.ts
|
|
1004
|
+
/** Validate one JSON literal or number incrementally with constant state. */
|
|
1005
|
+
var JsonPrimitiveScanner = class {
|
|
1006
|
+
literal;
|
|
1007
|
+
literalIndex = 0;
|
|
1008
|
+
number;
|
|
1009
|
+
valid = true;
|
|
1010
|
+
constructor(firstByte) {
|
|
1011
|
+
if (firstByte === 116) {
|
|
1012
|
+
this.literal = "true";
|
|
1013
|
+
this.literalIndex = 1;
|
|
1014
|
+
} else if (firstByte === 102) {
|
|
1015
|
+
this.literal = "false";
|
|
1016
|
+
this.literalIndex = 1;
|
|
1017
|
+
} else if (firstByte === 110) {
|
|
1018
|
+
this.literal = "null";
|
|
1019
|
+
this.literalIndex = 1;
|
|
1020
|
+
} else if (firstByte === 45) this.number = "minus";
|
|
1021
|
+
else if (firstByte === 48) this.number = "zero";
|
|
1022
|
+
else if (isOneToNine(firstByte)) this.number = "integer";
|
|
1023
|
+
else this.valid = false;
|
|
1024
|
+
}
|
|
1025
|
+
/** Consume one non-delimiter byte and report whether the prefix stays valid. */
|
|
1026
|
+
write(byte) {
|
|
1027
|
+
if (!this.valid) return false;
|
|
1028
|
+
if (this.literal) {
|
|
1029
|
+
this.valid = this.literal.charCodeAt(this.literalIndex) === byte;
|
|
1030
|
+
this.literalIndex += 1;
|
|
1031
|
+
return this.valid && this.literalIndex <= this.literal.length;
|
|
1032
|
+
}
|
|
1033
|
+
this.valid = this.writeNumber(byte);
|
|
1034
|
+
return this.valid;
|
|
1035
|
+
}
|
|
1036
|
+
/** Return whether the accumulated primitive is complete JSON grammar. */
|
|
1037
|
+
finish() {
|
|
1038
|
+
if (!this.valid) return false;
|
|
1039
|
+
if (this.literal) return this.literalIndex === this.literal.length;
|
|
1040
|
+
return this.number === "zero" || this.number === "integer" || this.number === "fraction" || this.number === "exponent";
|
|
1041
|
+
}
|
|
1042
|
+
writeNumber(byte) {
|
|
1043
|
+
if (this.number === "minus") return this.digitAfter(byte, "zero", "integer");
|
|
1044
|
+
if (this.number === "zero") return this.afterInteger(byte, false);
|
|
1045
|
+
if (this.number === "integer") {
|
|
1046
|
+
if (isDigit(byte)) return true;
|
|
1047
|
+
return this.afterInteger(byte, true);
|
|
1048
|
+
}
|
|
1049
|
+
if (this.number === "dot") {
|
|
1050
|
+
if (!isDigit(byte)) return false;
|
|
1051
|
+
this.number = "fraction";
|
|
1052
|
+
return true;
|
|
1053
|
+
}
|
|
1054
|
+
if (this.number === "fraction") {
|
|
1055
|
+
if (isDigit(byte)) return true;
|
|
1056
|
+
return this.startExponent(byte);
|
|
1057
|
+
}
|
|
1058
|
+
if (this.number === "exponentMark") {
|
|
1059
|
+
if (byte === 43 || byte === 45) {
|
|
1060
|
+
this.number = "exponentSign";
|
|
1061
|
+
return true;
|
|
1062
|
+
}
|
|
1063
|
+
return this.digitAfter(byte, "exponent", "exponent");
|
|
1064
|
+
}
|
|
1065
|
+
if (this.number === "exponentSign") return this.digitAfter(byte, "exponent", "exponent");
|
|
1066
|
+
return this.number === "exponent" && isDigit(byte);
|
|
1067
|
+
}
|
|
1068
|
+
afterInteger(byte, digitAllowed) {
|
|
1069
|
+
if (digitAllowed && isDigit(byte)) return true;
|
|
1070
|
+
if (byte === 46) {
|
|
1071
|
+
this.number = "dot";
|
|
1072
|
+
return true;
|
|
1073
|
+
}
|
|
1074
|
+
return this.startExponent(byte);
|
|
1075
|
+
}
|
|
1076
|
+
startExponent(byte) {
|
|
1077
|
+
if (byte !== 101 && byte !== 69) return false;
|
|
1078
|
+
this.number = "exponentMark";
|
|
1079
|
+
return true;
|
|
1080
|
+
}
|
|
1081
|
+
digitAfter(byte, zero, nonzero) {
|
|
1082
|
+
if (byte === 48) {
|
|
1083
|
+
this.number = zero;
|
|
1084
|
+
return true;
|
|
1085
|
+
}
|
|
1086
|
+
if (isOneToNine(byte)) {
|
|
1087
|
+
this.number = nonzero;
|
|
1088
|
+
return true;
|
|
1089
|
+
}
|
|
1090
|
+
return false;
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
function isDigit(byte) {
|
|
1094
|
+
return byte >= 48 && byte <= 57;
|
|
1095
|
+
}
|
|
1096
|
+
function isOneToNine(byte) {
|
|
1097
|
+
return byte >= 49 && byte <= 57;
|
|
1098
|
+
}
|
|
1099
|
+
//#endregion
|
|
1100
|
+
//#region src/cli/cursor-event-scanner.ts
|
|
1101
|
+
/**
|
|
1102
|
+
* Fixed cardinality bounds used by the incremental Cursor JSON scanner.
|
|
1103
|
+
* `maxDepth` counts simultaneously open containers. Deeper valid JSON remains
|
|
1104
|
+
* indeterminate and the oversized Cursor path fails closed.
|
|
1105
|
+
*/
|
|
1106
|
+
const CURSOR_SCANNER_LIMITS = {
|
|
1107
|
+
tokenEntries: 256,
|
|
1108
|
+
maxDepth: 1024
|
|
1109
|
+
};
|
|
1110
|
+
/** Incrementally validates JSON and extracts the last top-level Cursor event name. */
|
|
1111
|
+
var CursorEventScanner = class {
|
|
1112
|
+
frames = [];
|
|
1113
|
+
mode = "normal";
|
|
1114
|
+
token = [];
|
|
1115
|
+
tokenOverflow = false;
|
|
1116
|
+
primitive;
|
|
1117
|
+
escaped = false;
|
|
1118
|
+
unicode = 0;
|
|
1119
|
+
rootStarted = false;
|
|
1120
|
+
rootComplete = false;
|
|
1121
|
+
invalid = false;
|
|
1122
|
+
event;
|
|
1123
|
+
/** Consume another raw JSON byte chunk without retaining the payload. */
|
|
1124
|
+
write(chunk) {
|
|
1125
|
+
for (const byte of chunk) this.consume(byte);
|
|
1126
|
+
}
|
|
1127
|
+
/** Return the event only when the complete stream is valid JSON. */
|
|
1128
|
+
finish() {
|
|
1129
|
+
if (this.mode === "primitive") this.endPrimitive();
|
|
1130
|
+
if (this.mode !== "normal" || this.frames.length > 0 || !this.rootComplete) this.invalid = true;
|
|
1131
|
+
return this.invalid ? void 0 : this.event;
|
|
1132
|
+
}
|
|
1133
|
+
consume(byte) {
|
|
1134
|
+
if (this.invalid) return;
|
|
1135
|
+
if (this.mode === "string") {
|
|
1136
|
+
this.stringByte(byte);
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
if (this.mode === "primitive") {
|
|
1140
|
+
if (!isDelimiter(byte)) {
|
|
1141
|
+
if (!this.primitive?.write(byte)) this.invalid = true;
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
this.endPrimitive();
|
|
1145
|
+
if (this.invalid) return;
|
|
1146
|
+
}
|
|
1147
|
+
if (isWhitespace(byte)) return;
|
|
1148
|
+
if (byte === 34) {
|
|
1149
|
+
this.startString();
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
if (byte === 123 || byte === 91) {
|
|
1153
|
+
this.startContainer(byte === 123 ? "object" : "array");
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (byte === 125 || byte === 93) {
|
|
1157
|
+
this.endContainer(byte === 125 ? "object" : "array");
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
if (byte === 58) {
|
|
1161
|
+
this.colon();
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
if (byte === 44) {
|
|
1165
|
+
this.comma();
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
if (isPrimitiveStart(byte)) {
|
|
1169
|
+
this.startPrimitive(byte);
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
this.invalid = true;
|
|
1173
|
+
}
|
|
1174
|
+
startString() {
|
|
1175
|
+
this.mode = "string";
|
|
1176
|
+
this.token = [34];
|
|
1177
|
+
this.tokenOverflow = false;
|
|
1178
|
+
this.escaped = false;
|
|
1179
|
+
this.unicode = 0;
|
|
1180
|
+
}
|
|
1181
|
+
startPrimitive(byte) {
|
|
1182
|
+
this.mode = "primitive";
|
|
1183
|
+
this.primitive = new JsonPrimitiveScanner(byte);
|
|
1184
|
+
}
|
|
1185
|
+
stringByte(byte) {
|
|
1186
|
+
this.pushToken(byte);
|
|
1187
|
+
if (this.unicode > 0) {
|
|
1188
|
+
if (!isHex(byte)) {
|
|
1189
|
+
this.invalid = true;
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
this.unicode -= 1;
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
if (this.escaped) {
|
|
1196
|
+
if (byte === 117) this.unicode = 4;
|
|
1197
|
+
else if (![
|
|
1198
|
+
34,
|
|
1199
|
+
92,
|
|
1200
|
+
47,
|
|
1201
|
+
98,
|
|
1202
|
+
102,
|
|
1203
|
+
110,
|
|
1204
|
+
114,
|
|
1205
|
+
116
|
|
1206
|
+
].includes(byte)) this.invalid = true;
|
|
1207
|
+
this.escaped = false;
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
if (byte === 92) {
|
|
1211
|
+
this.escaped = true;
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
if (byte < 32) {
|
|
1215
|
+
this.invalid = true;
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
if (byte !== 34) return;
|
|
1219
|
+
this.mode = "normal";
|
|
1220
|
+
const value = this.tokenOverflow ? void 0 : decodeString(this.token);
|
|
1221
|
+
if (value === null) {
|
|
1222
|
+
this.invalid = true;
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
this.acceptString(value);
|
|
1226
|
+
}
|
|
1227
|
+
acceptString(value) {
|
|
1228
|
+
const frame = this.frames.at(-1);
|
|
1229
|
+
if (frame?.kind === "object" && (frame.state === "key" || frame.state === "keyOrEnd")) {
|
|
1230
|
+
frame.key = value;
|
|
1231
|
+
frame.state = "colon";
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
this.acceptValue("string", value);
|
|
1235
|
+
}
|
|
1236
|
+
startContainer(kind) {
|
|
1237
|
+
this.acceptValue(kind);
|
|
1238
|
+
if (this.invalid) return;
|
|
1239
|
+
if (this.frames.length >= CURSOR_SCANNER_LIMITS.maxDepth) {
|
|
1240
|
+
this.invalid = true;
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
this.frames.push(kind === "object" ? {
|
|
1244
|
+
kind,
|
|
1245
|
+
state: "keyOrEnd"
|
|
1246
|
+
} : {
|
|
1247
|
+
kind,
|
|
1248
|
+
state: "valueOrEnd"
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
endContainer(kind) {
|
|
1252
|
+
const frame = this.frames.at(-1);
|
|
1253
|
+
if (!(frame?.kind === kind && (kind === "object" ? frame.state === "keyOrEnd" || frame.state === "commaOrEnd" : frame.state === "valueOrEnd" || frame.state === "commaOrEnd"))) {
|
|
1254
|
+
this.invalid = true;
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
this.frames.pop();
|
|
1258
|
+
if (this.frames.length === 0) this.rootComplete = true;
|
|
1259
|
+
}
|
|
1260
|
+
acceptValue(kind, value) {
|
|
1261
|
+
if (this.rootComplete) {
|
|
1262
|
+
this.invalid = true;
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
const frame = this.frames.at(-1);
|
|
1266
|
+
if (!frame) {
|
|
1267
|
+
if (this.rootStarted) {
|
|
1268
|
+
this.invalid = true;
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
this.rootStarted = true;
|
|
1272
|
+
if (kind === "string" || kind === "primitive") this.rootComplete = true;
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
if (!(frame.kind === "object" ? frame.state === "value" : frame.state === "value" || frame.state === "valueOrEnd")) {
|
|
1276
|
+
this.invalid = true;
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
if (frame.kind === "object") {
|
|
1280
|
+
if (this.frames.length === 1 && frame.key === "hook_event_name") this.event = kind === "string" ? value : void 0;
|
|
1281
|
+
frame.key = void 0;
|
|
1282
|
+
}
|
|
1283
|
+
frame.state = "commaOrEnd";
|
|
1284
|
+
}
|
|
1285
|
+
colon() {
|
|
1286
|
+
const frame = this.frames.at(-1);
|
|
1287
|
+
if (frame?.kind !== "object" || frame.state !== "colon") {
|
|
1288
|
+
this.invalid = true;
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
frame.state = "value";
|
|
1292
|
+
}
|
|
1293
|
+
comma() {
|
|
1294
|
+
const frame = this.frames.at(-1);
|
|
1295
|
+
if (!frame || frame.state !== "commaOrEnd") {
|
|
1296
|
+
this.invalid = true;
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
frame.state = frame.kind === "object" ? "key" : "value";
|
|
1300
|
+
}
|
|
1301
|
+
endPrimitive() {
|
|
1302
|
+
const valid = this.primitive?.finish() === true;
|
|
1303
|
+
this.mode = "normal";
|
|
1304
|
+
this.primitive = void 0;
|
|
1305
|
+
if (valid) this.acceptValue("primitive");
|
|
1306
|
+
else this.invalid = true;
|
|
1307
|
+
}
|
|
1308
|
+
pushToken(byte) {
|
|
1309
|
+
if (this.token.length < CURSOR_SCANNER_LIMITS.tokenEntries) this.token.push(byte);
|
|
1310
|
+
else this.tokenOverflow = true;
|
|
1311
|
+
}
|
|
1312
|
+
};
|
|
1313
|
+
function decodeString(bytes) {
|
|
1314
|
+
try {
|
|
1315
|
+
const value = JSON.parse(Buffer.from(bytes).toString("utf8"));
|
|
1316
|
+
return typeof value === "string" ? value : null;
|
|
1317
|
+
} catch {
|
|
1318
|
+
return null;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
function isWhitespace(byte) {
|
|
1322
|
+
return byte === 32 || byte === 9 || byte === 10 || byte === 13;
|
|
1323
|
+
}
|
|
1324
|
+
function isDelimiter(byte) {
|
|
1325
|
+
return isWhitespace(byte) || [
|
|
1326
|
+
44,
|
|
1327
|
+
93,
|
|
1328
|
+
125
|
|
1329
|
+
].includes(byte);
|
|
1330
|
+
}
|
|
1331
|
+
function isPrimitiveStart(byte) {
|
|
1332
|
+
return byte === 45 || byte === 116 || byte === 102 || byte === 110 || byte >= 48 && byte <= 57;
|
|
1333
|
+
}
|
|
1334
|
+
function isHex(byte) {
|
|
1335
|
+
return byte >= 48 && byte <= 57 || byte >= 65 && byte <= 70 || byte >= 97 && byte <= 102;
|
|
1336
|
+
}
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region src/cli/cursor-stdin-reader.ts
|
|
1339
|
+
const HEAD_BYTES$1 = 4096;
|
|
1340
|
+
const CHUNK_BYTES = 64 * 1024;
|
|
1341
|
+
/**
|
|
1342
|
+
* Read Cursor stdin through EOF for valid top-level event classification.
|
|
1343
|
+
* Cursor's host-configured execution timeout bounds an idle open pipe.
|
|
1344
|
+
*/
|
|
1345
|
+
function readCursorBounded(fd, maxBytes) {
|
|
1346
|
+
const chunk = Buffer.alloc(CHUNK_BYTES);
|
|
1347
|
+
const head = Buffer.alloc(HEAD_BYTES$1);
|
|
1348
|
+
const retained = Buffer.alloc(maxBytes);
|
|
1349
|
+
const scanner = new CursorEventScanner();
|
|
1350
|
+
let headLength = 0;
|
|
1351
|
+
let retainedLength = 0;
|
|
1352
|
+
let total = 0;
|
|
1353
|
+
let oversize = false;
|
|
1354
|
+
for (;;) {
|
|
1355
|
+
const length = readSync(fd, chunk, 0, CHUNK_BYTES, null);
|
|
1356
|
+
if (length === 0) break;
|
|
1357
|
+
const view = chunk.subarray(0, length);
|
|
1358
|
+
scanner.write(view);
|
|
1359
|
+
total += length;
|
|
1360
|
+
if (headLength < HEAD_BYTES$1) {
|
|
1361
|
+
const copied = Math.min(length, HEAD_BYTES$1 - headLength);
|
|
1362
|
+
view.copy(head, headLength, 0, copied);
|
|
1363
|
+
headLength += copied;
|
|
1364
|
+
}
|
|
1365
|
+
if (!oversize) {
|
|
1366
|
+
const copied = Math.min(length, Math.max(0, maxBytes - retainedLength));
|
|
1367
|
+
if (copied > 0) view.copy(retained, retainedLength, 0, copied);
|
|
1368
|
+
retainedLength += copied;
|
|
1369
|
+
if (total > maxBytes) oversize = true;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
if (!oversize) return {
|
|
1373
|
+
kind: "ok",
|
|
1374
|
+
text: retained.subarray(0, total).toString("utf8")
|
|
1375
|
+
};
|
|
1376
|
+
const event = scanner.finish();
|
|
1377
|
+
return {
|
|
1378
|
+
kind: "oversize",
|
|
1379
|
+
head: event ? JSON.stringify({ hook_event_name: event }) : head.subarray(0, headLength).toString("utf8")
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
//#endregion
|
|
1002
1383
|
//#region src/cli/hook-io.ts
|
|
1003
1384
|
/**
|
|
1004
1385
|
* Hook stdin reading + debug tracing for `harness hook` — extracted from
|
|
@@ -1006,22 +1387,34 @@ function parseScope(scopeArg, err = (m) => process.stderr.write(m)) {
|
|
|
1006
1387
|
* Tracing is stderr-only and active only when FUSE_HARNESS_DEBUG=1 AND
|
|
1007
1388
|
* CI=true (both set by test/sim/exec.ts; never in an interactive session).
|
|
1008
1389
|
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1390
|
+
* `resolveStdinMaxBytes` (default 16 MiB) caps retained payload content.
|
|
1391
|
+
* The legacy reader may also retain its overflow chunk; Cursor additionally
|
|
1392
|
+
* requests fixed scanner/chunk buffers while reading to EOF. Buffer alias views,
|
|
1393
|
+
* JS objects/strings, and RSS are runtime-dependent, so this is not a physical
|
|
1394
|
+
* memory guarantee. Unclassified oversized Cursor input fails closed.
|
|
1012
1395
|
*/
|
|
1013
1396
|
const hookDebug = process.env.FUSE_HARNESS_DEBUG === "1" && process.env.CI === "true";
|
|
1014
1397
|
/** stderr-only trace, no-op outside the debug flag combination above. */
|
|
1015
1398
|
function traceHook(label, data) {
|
|
1016
1399
|
if (hookDebug) process.stderr.write(`[hook-debug] ${label}: ${typeof data === "string" ? data : JSON.stringify(data)}\n`);
|
|
1017
1400
|
}
|
|
1401
|
+
const MALFORMED_STDIN = Symbol("cursor-malformed-stdin");
|
|
1018
1402
|
/** Type guard for the oversize variant (narrows the readStdin union). */
|
|
1019
1403
|
function isOversize(x) {
|
|
1020
1404
|
return typeof x === "object" && x !== null && x.kind === "oversize";
|
|
1021
1405
|
}
|
|
1022
|
-
/**
|
|
1406
|
+
/** Identify Cursor JSON parse failures without accepting a forgeable payload field. */
|
|
1407
|
+
function isMalformedCursorStdin(x) {
|
|
1408
|
+
return typeof x === "object" && x !== null && MALFORMED_STDIN in x;
|
|
1409
|
+
}
|
|
1410
|
+
/** First 4 KiB are the fallback diagnostic probe when no event key is found. */
|
|
1023
1411
|
const HEAD_BYTES = 4096;
|
|
1024
1412
|
const CHUNK = 64 * 1024;
|
|
1413
|
+
const CURSOR_MAX_STDIN_BYTES = 64 * 1024 * 1024;
|
|
1414
|
+
/** Resolve and clamp Cursor's stdin cap while preserving other harness limits. */
|
|
1415
|
+
function resolveCursorStdinMaxBytes(env = process.env) {
|
|
1416
|
+
return Math.min(CURSOR_MAX_STDIN_BYTES, resolveStdinMaxBytes(env));
|
|
1417
|
+
}
|
|
1025
1418
|
/**
|
|
1026
1419
|
* Read a file descriptor to EOF, bounded at `maxBytes` (+1 byte to detect
|
|
1027
1420
|
* the overflow). Injectable fd so tests never touch process stdin.
|
|
@@ -1048,9 +1441,10 @@ function readBounded(fd, maxBytes) {
|
|
|
1048
1441
|
text: Buffer.concat(parts).toString("utf8")
|
|
1049
1442
|
};
|
|
1050
1443
|
}
|
|
1051
|
-
/** Read
|
|
1052
|
-
async function readStdin() {
|
|
1053
|
-
const
|
|
1444
|
+
/** Read hook stdin; Cursor distinguishes malformed non-empty JSON from historical empty input. */
|
|
1445
|
+
async function readStdin(id) {
|
|
1446
|
+
const cap = id === "cursor" ? resolveCursorStdinMaxBytes() : resolveStdinMaxBytes();
|
|
1447
|
+
const read = id === "cursor" ? readCursorBounded(0, cap) : readBounded(0, cap);
|
|
1054
1448
|
if (read.kind === "oversize") return read;
|
|
1055
1449
|
const text = read.text.trim();
|
|
1056
1450
|
if (!text) return {};
|
|
@@ -1059,7 +1453,7 @@ async function readStdin() {
|
|
|
1059
1453
|
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
1060
1454
|
} catch (e) {
|
|
1061
1455
|
traceHook("stdin-parse-error", e instanceof Error ? e.message : String(e));
|
|
1062
|
-
return {};
|
|
1456
|
+
return id === "cursor" ? { [MALFORMED_STDIN]: true } : {};
|
|
1063
1457
|
}
|
|
1064
1458
|
}
|
|
1065
1459
|
/** Blockable hook events (fail-closed on oversize); others are observation-only. */
|
|
@@ -1076,13 +1470,31 @@ const BLOCKABLE = /* @__PURE__ */ new Set([
|
|
|
1076
1470
|
* @param head - The first bytes of the payload (event-name sniffing).
|
|
1077
1471
|
*/
|
|
1078
1472
|
function oversizeStdout(id, head) {
|
|
1079
|
-
const event =
|
|
1080
|
-
|
|
1473
|
+
const event = id === "cursor" ? probeEvent(head) : legacyProbeEvent(head);
|
|
1474
|
+
const maxBytes = id === "cursor" ? resolveCursorStdinMaxBytes() : resolveStdinMaxBytes();
|
|
1475
|
+
if (id === "cursor" && event) {
|
|
1476
|
+
const contract = cursorEventContract(event);
|
|
1477
|
+
if (!contract.known || !contract.blockable) return "{}";
|
|
1478
|
+
}
|
|
1479
|
+
if (id !== "cursor" && event && !BLOCKABLE.has(event)) return "";
|
|
1081
1480
|
return respond(id, {
|
|
1082
1481
|
kind: "block",
|
|
1083
1482
|
title: "Oversize hook payload",
|
|
1084
|
-
reason: `stdin payload exceeds ${
|
|
1085
|
-
});
|
|
1483
|
+
reason: `stdin payload exceeds ${maxBytes} bytes — denied uninspected`
|
|
1484
|
+
}, id === "cursor" ? event || "preToolUse" : "PreToolUse");
|
|
1485
|
+
}
|
|
1486
|
+
function legacyProbeEvent(head) {
|
|
1487
|
+
return /"hook_event_name"\s*:\s*"([^"]+)"/.exec(head)?.[1] ?? "";
|
|
1488
|
+
}
|
|
1489
|
+
function probeEvent(head) {
|
|
1490
|
+
try {
|
|
1491
|
+
const parsed = JSON.parse(head);
|
|
1492
|
+
if (typeof parsed !== "object" || parsed === null) return "";
|
|
1493
|
+
const event = parsed.hook_event_name;
|
|
1494
|
+
return typeof event === "string" ? event : "";
|
|
1495
|
+
} catch {
|
|
1496
|
+
return "";
|
|
1497
|
+
}
|
|
1086
1498
|
}
|
|
1087
1499
|
//#endregion
|
|
1088
1500
|
//#region src/cli/hook-sound.ts
|
|
@@ -1166,12 +1578,13 @@ if (cmd === "--version" || cmd === "-v") {
|
|
|
1166
1578
|
});
|
|
1167
1579
|
let outcome;
|
|
1168
1580
|
try {
|
|
1169
|
-
const stdin = await readStdin();
|
|
1581
|
+
const stdin = await readStdin(id);
|
|
1170
1582
|
if (isOversize(stdin)) {
|
|
1171
1583
|
const stdout = oversizeStdout(id, stdin.head);
|
|
1172
1584
|
if (stdout) process.stdout.write(stdout);
|
|
1173
1585
|
process.exit(0);
|
|
1174
1586
|
}
|
|
1587
|
+
if (isMalformedCursorStdin(stdin)) process.exit(1);
|
|
1175
1588
|
outcome = await handleHook(id, stdin, {
|
|
1176
1589
|
now: Date.now(),
|
|
1177
1590
|
cwd: process.cwd(),
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-
|
|
1
|
+
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-DkrzC0gb.mjs";
|
|
2
2
|
export { checkStaged, stagedContent, stagedFiles };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/runtime/command-string.ts
|
|
2
|
+
/** Shell basenames whose `-c`-style argv carries the real script in argv[2]. */
|
|
3
|
+
const SHELLS = /* @__PURE__ */ new Set([
|
|
4
|
+
"bash",
|
|
5
|
+
"sh",
|
|
6
|
+
"zsh",
|
|
7
|
+
"dash"
|
|
8
|
+
]);
|
|
9
|
+
/** True when `arg` is (a path to) a POSIX shell we know wraps a `-c` script. */
|
|
10
|
+
function isShell(arg) {
|
|
11
|
+
if (arg === void 0) return false;
|
|
12
|
+
const base = arg.slice(arg.lastIndexOf("/") + 1);
|
|
13
|
+
return SHELLS.has(base);
|
|
14
|
+
}
|
|
15
|
+
/** True for a shell command flag (`-c`, `-lc`, `-ic`, …) — anything ending in `c`. */
|
|
16
|
+
function isCommandFlag(arg) {
|
|
17
|
+
return arg !== void 0 && /^-[a-z]*c$/.test(arg);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Coerce a hook payload's `command` field to the shell string the guard chain
|
|
21
|
+
* expects. Harnesses disagree on the wire shape: Claude Code, Cursor, and Hermes
|
|
22
|
+
* send a plain string, but Codex CLI sends an argv ARRAY
|
|
23
|
+
* (`["bash", "-lc", "git commit -m x"]`). A naive `typeof === "string"` check
|
|
24
|
+
* dropped the array to `undefined`, blinding every `ctx.command` guard
|
|
25
|
+
* (destructive-git, mutators, install…) into a silent fail-open. This restores
|
|
26
|
+
* the script so the array and string payloads reach an identical verdict.
|
|
27
|
+
*
|
|
28
|
+
* @param v - Raw `command` value off the payload (string, argv array, or other).
|
|
29
|
+
* @returns A string as-is; a `[shell, -c|-lc, script]` argv reduced to its
|
|
30
|
+
* script; any other all-string array joined with spaces; and `undefined` for
|
|
31
|
+
* empty arrays, arrays holding non-strings, or any other type.
|
|
32
|
+
*/
|
|
33
|
+
function commandToString(v) {
|
|
34
|
+
if (typeof v === "string") return v;
|
|
35
|
+
if (!Array.isArray(v)) return void 0;
|
|
36
|
+
if (v.length === 0 || !v.every((e) => typeof e === "string")) return void 0;
|
|
37
|
+
const argv = v;
|
|
38
|
+
if (argv.length >= 3 && isShell(argv[0]) && isCommandFlag(argv[1])) return argv[2];
|
|
39
|
+
return argv.join(" ");
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { commandToString as t };
|