@ashx-j/lunr 0.2.24 → 0.2.26
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/CHANGELOG.md +24 -1
- package/dist/builtin-extensions/index.d.ts.map +1 -1
- package/dist/builtin-extensions/index.js +1 -0
- package/dist/builtin-extensions/index.js.map +1 -1
- package/dist/builtin-extensions/lunr-computer-use.d.ts +3 -0
- package/dist/builtin-extensions/lunr-computer-use.d.ts.map +1 -0
- package/dist/builtin-extensions/lunr-computer-use.js +179 -0
- package/dist/builtin-extensions/lunr-computer-use.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -4
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +8 -5
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +11 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +15 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.js +5 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +2 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +5 -3
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/core/computer-use/adapter.d.ts +28 -0
- package/dist/core/computer-use/adapter.d.ts.map +1 -0
- package/dist/core/computer-use/adapter.js +133 -0
- package/dist/core/computer-use/adapter.js.map +1 -0
- package/dist/core/computer-use/image.d.ts +27 -0
- package/dist/core/computer-use/image.d.ts.map +1 -0
- package/dist/core/computer-use/image.js +72 -0
- package/dist/core/computer-use/image.js.map +1 -0
- package/dist/core/computer-use/lease.d.ts +18 -0
- package/dist/core/computer-use/lease.d.ts.map +1 -0
- package/dist/core/computer-use/lease.js +129 -0
- package/dist/core/computer-use/lease.js.map +1 -0
- package/dist/core/computer-use/macos-runtime.d.ts +14 -0
- package/dist/core/computer-use/macos-runtime.d.ts.map +1 -0
- package/dist/core/computer-use/macos-runtime.js +148 -0
- package/dist/core/computer-use/macos-runtime.js.map +1 -0
- package/dist/core/computer-use/policy.d.ts +19 -0
- package/dist/core/computer-use/policy.d.ts.map +1 -0
- package/dist/core/computer-use/policy.js +67 -0
- package/dist/core/computer-use/policy.js.map +1 -0
- package/dist/core/computer-use/release.generated.d.ts +31 -0
- package/dist/core/computer-use/release.generated.d.ts.map +1 -0
- package/dist/core/computer-use/release.generated.js +36 -0
- package/dist/core/computer-use/release.generated.js.map +1 -0
- package/dist/core/computer-use/runtime.d.ts +13 -0
- package/dist/core/computer-use/runtime.d.ts.map +1 -0
- package/dist/core/computer-use/runtime.js +158 -0
- package/dist/core/computer-use/runtime.js.map +1 -0
- package/dist/core/computer-use/schemas.d.ts +100 -0
- package/dist/core/computer-use/schemas.d.ts.map +1 -0
- package/dist/core/computer-use/schemas.js +79 -0
- package/dist/core/computer-use/schemas.js.map +1 -0
- package/dist/core/computer-use/windows-desktop.d.ts +3 -0
- package/dist/core/computer-use/windows-desktop.d.ts.map +1 -0
- package/dist/core/computer-use/windows-desktop.js +48 -0
- package/dist/core/computer-use/windows-desktop.js.map +1 -0
- package/dist/core/computer-use/workflow.d.ts +38 -0
- package/dist/core/computer-use/workflow.d.ts.map +1 -0
- package/dist/core/computer-use/workflow.js +560 -0
- package/dist/core/computer-use/workflow.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +4 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/permissions.d.ts +1 -1
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +14 -3
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +9 -0
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +19 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/subagent-event-transport.d.ts +3 -0
- package/dist/core/subagent-event-transport.d.ts.map +1 -0
- package/dist/core/subagent-event-transport.js +61 -0
- package/dist/core/subagent-event-transport.js.map +1 -0
- package/dist/gateway/adapters/discord.d.ts.map +1 -1
- package/dist/gateway/adapters/discord.js +4 -9
- package/dist/gateway/adapters/discord.js.map +1 -1
- package/dist/gateway/adapters/telegram.d.ts.map +1 -1
- package/dist/gateway/adapters/telegram.js +7 -0
- package/dist/gateway/adapters/telegram.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts +4 -1
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +57 -17
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/approval.d.ts.map +1 -1
- package/dist/gateway/approval.js +3 -3
- package/dist/gateway/approval.js.map +1 -1
- package/dist/gateway/authz.d.ts +4 -4
- package/dist/gateway/authz.d.ts.map +1 -1
- package/dist/gateway/authz.js +8 -12
- package/dist/gateway/authz.js.map +1 -1
- package/dist/gateway/buttons.d.ts.map +1 -1
- package/dist/gateway/buttons.js +29 -19
- package/dist/gateway/buttons.js.map +1 -1
- package/dist/gateway/commands.d.ts +2 -0
- package/dist/gateway/commands.d.ts.map +1 -1
- package/dist/gateway/commands.js +35 -18
- package/dist/gateway/commands.js.map +1 -1
- package/dist/gateway/config.d.ts +1 -0
- package/dist/gateway/config.d.ts.map +1 -1
- package/dist/gateway/config.js +2 -0
- package/dist/gateway/config.js.map +1 -1
- package/dist/gateway/cron.d.ts +1 -1
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +22 -8
- package/dist/gateway/cron.js.map +1 -1
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js +26 -26
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/mobile-commands.d.ts.map +1 -1
- package/dist/gateway/mobile-commands.js +11 -11
- package/dist/gateway/mobile-commands.js.map +1 -1
- package/dist/gateway/presenter.d.ts +12 -1
- package/dist/gateway/presenter.d.ts.map +1 -1
- package/dist/gateway/presenter.js +148 -50
- package/dist/gateway/presenter.js.map +1 -1
- package/dist/gateway/router.d.ts +5 -5
- package/dist/gateway/router.d.ts.map +1 -1
- package/dist/gateway/router.js +95 -43
- package/dist/gateway/router.js.map +1 -1
- package/dist/gateway/service.d.ts.map +1 -1
- package/dist/gateway/service.js +13 -4
- package/dist/gateway/service.js.map +1 -1
- package/dist/gateway/setup.d.ts +5 -0
- package/dist/gateway/setup.d.ts.map +1 -1
- package/dist/gateway/setup.js +101 -43
- package/dist/gateway/setup.js.map +1 -1
- package/dist/gateway/stream.d.ts +6 -5
- package/dist/gateway/stream.d.ts.map +1 -1
- package/dist/gateway/stream.js +24 -11
- package/dist/gateway/stream.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +20 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +8 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +9 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/node-runtime/adapter-VFG7WNPX.js +17 -0
- package/dist/node-runtime/{agent-session-services-IEF7LQWD.js → agent-session-services-5YXS2PLF.js} +13 -10
- package/dist/node-runtime/{builtin-extensions-EBAWTH4M.js → builtin-extensions-I2HIFEMY.js} +3 -2
- package/dist/node-runtime/{chunk-K5AGHH57.js → chunk-2CFDTH5B.js} +7 -3
- package/dist/node-runtime/{chunk-VWCE2HSZ.js → chunk-2HMIRK7W.js} +4 -4
- package/dist/node-runtime/chunk-2IDTZAG5.js +1415 -0
- package/dist/node-runtime/{chunk-IGV54Q5V.js → chunk-3MISGG4S.js} +137 -76
- package/dist/node-runtime/chunk-4SBQAI4T.js +2185 -0
- package/dist/node-runtime/{chunk-WHLRAGUQ.js → chunk-5B5QN3ZQ.js} +16 -16
- package/dist/node-runtime/chunk-5B6VKFEV.js +180 -0
- package/dist/node-runtime/{chunk-AD6VXAO7.js → chunk-5Q4A37RB.js} +15 -104
- package/dist/node-runtime/{chunk-4TLO4PO2.js → chunk-7IQGBKBJ.js} +7 -1401
- package/dist/node-runtime/{chunk-R3K2F5GI.js → chunk-B4HP6ZWM.js} +2 -0
- package/dist/node-runtime/{chunk-OCVIXVTZ.js → chunk-D5UCKPBQ.js} +12 -1
- package/dist/node-runtime/chunk-DVQSHCVP.js +97 -0
- package/dist/node-runtime/{chunk-HFVZUPFJ.js → chunk-E75WFZ33.js} +2 -2
- package/dist/node-runtime/chunk-FY4A63RK.js +73 -0
- package/dist/node-runtime/{chunk-RORY2HMJ.js → chunk-I74LN5JG.js} +16 -1
- package/dist/node-runtime/chunk-IKU6Y7DL.js +287 -0
- package/dist/node-runtime/{chunk-QM43FEAE.js → chunk-L24TPBS4.js} +6 -5
- package/dist/node-runtime/{chunk-DE2JB6J5.js → chunk-LJTIVM7I.js} +7 -7
- package/dist/node-runtime/{chunk-DSIKTUPW.js → chunk-LWJXTA6Z.js} +274 -2433
- package/dist/node-runtime/{chunk-YVI6L6LU.js → chunk-P7XBVXGT.js} +36 -21
- package/dist/node-runtime/{chunk-OVX6X377.js → chunk-PTFBPO3C.js} +1 -1
- package/dist/node-runtime/{chunk-F4FLTQKV.js → chunk-RAK2QA2B.js} +186 -1529
- package/dist/node-runtime/{chunk-L3LX4SNR.js → chunk-RCR3XAQY.js} +36 -8
- package/dist/node-runtime/chunk-RGQAEOM5.js +81 -0
- package/dist/node-runtime/{chunk-UWPJL22I.js → chunk-SLVOAQOY.js} +15 -4
- package/dist/node-runtime/chunk-SN2KSMPQ.js +1364 -0
- package/dist/node-runtime/{chunk-FU6OODRZ.js → chunk-SPVDBUOS.js} +1 -1
- package/dist/node-runtime/{chunk-5Q3EHOHI.js → chunk-T4DA4XE7.js} +19 -17
- package/dist/node-runtime/chunk-U5F4IC7R.js +53 -0
- package/dist/node-runtime/{chunk-UP2XBVH5.js → chunk-UOEDI7RP.js} +1 -1
- package/dist/node-runtime/{chunk-Y73WPE6S.js → chunk-UVWCDQYF.js} +79 -44
- package/dist/node-runtime/{chunk-ZXSGTGJ6.js → chunk-WIF24I7G.js} +21 -5
- package/dist/node-runtime/{chunk-OF7PWMG4.js → chunk-X3PGBLQ7.js} +3 -87
- package/dist/node-runtime/chunk-XHIRAZ26.js +108 -0
- package/dist/node-runtime/{chunk-YDO2F2IA.js → chunk-YWOJIGFY.js} +1 -1
- package/dist/node-runtime/{command-7BG7VVTS.js → command-FSBU2EVZ.js} +5 -5
- package/dist/node-runtime/{commands-NZLSOHPE.js → commands-EMBQQVVT.js} +4 -2
- package/dist/node-runtime/{commands-QFDKNQTL.js → commands-NAAL7KNT.js} +7 -6
- package/dist/node-runtime/{config-RORQUQFG.js → config-D4QUPAHX.js} +1 -1
- package/dist/node-runtime/{direct-tool-executor-77GW4F5P.js → direct-tool-executor-4D7UXYU4.js} +7 -4
- package/dist/node-runtime/{gateway-TWR3N65G.js → gateway-DQM333YV.js} +140 -85
- package/dist/node-runtime/index.js +28 -21
- package/dist/node-runtime/{init-HS6NQXSK.js → init-P5AUV77I.js} +4 -2
- package/dist/node-runtime/{install-cli-VAP6KBFN.js → install-cli-NN4YAU44.js} +3 -3
- package/dist/node-runtime/{interactive-mode-6J5VZ2TT.js → interactive-mode-YOHZVMKX.js} +14 -11
- package/dist/node-runtime/{lunr-browser-J5ZZYVGM.js → lunr-browser-IR7TL3J7.js} +3 -3
- package/dist/node-runtime/lunr-computer-use-Y23CCDIJ.js +158 -0
- package/dist/node-runtime/{lunr-cron-CXOL37AL.js → lunr-cron-USHC4LXH.js} +9 -7
- package/dist/node-runtime/main.js +19 -15
- package/dist/node-runtime/{mcp-auth-flow-QIXHW6QN.js → mcp-auth-flow-QVLFVLEO.js} +2 -1
- package/dist/node-runtime/{mobile-commands-VTBM5DSZ.js → mobile-commands-O5LCHL32.js} +6 -5
- package/dist/node-runtime/{package-manager-cli-ZLW5DZXF.js → package-manager-cli-Q7BL6KZO.js} +12 -8
- package/dist/node-runtime/{pi-mcp-adapter-5UKBZP44.js → pi-mcp-adapter-3PHF4KZ4.js} +5 -5
- package/dist/node-runtime/{pi-subagents-XPCLLKIM.js → pi-subagents-7IBSSGEW.js} +27 -21
- package/dist/node-runtime/{print-mode-XSFM26EL.js → print-mode-XQ76CYMT.js} +2 -1
- package/dist/node-runtime/{proxy-modes-LGEUYD7R.js → proxy-modes-5FAPSZEZ.js} +7 -4
- package/dist/node-runtime/rpc-entry.js +19 -15
- package/dist/node-runtime/runtime-EFPPD2UW.js +21 -0
- package/dist/node-runtime/{runtime-bridges-QYXUX2TG.js → runtime-bridges-7WVCLI76.js} +6 -5
- package/dist/node-runtime/{service-ISSP6VHE.js → service-MDQIPQ26.js} +1 -1
- package/dist/node-runtime/{settings-manager-WCQDUVQB.js → settings-manager-DJDM5AHM.js} +5 -4
- package/dist/node-runtime/setup-PFBWRNUI.js +215 -0
- package/dist/node-runtime/{subagent-executor-OTNISDQU.js → subagent-executor-LPZ4BHWE.js} +32 -14
- package/dist/node-runtime/{update-cli-VBR2777K.js → update-cli-HNMOTNGX.js} +5 -4
- package/dist/node-runtime/workflow-OHPBEFO4.js +637 -0
- package/dist/utils/image-resize-core.d.ts +2 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-core.js +10 -0
- package/dist/utils/image-resize-core.js.map +1 -1
- package/docs/computer-use.md +362 -0
- package/docs/features.md +9 -7
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/install-lock/package-lock.json +3841 -0
- package/install-lock/package.json +18 -0
- package/native/computer-use/LICENSE.md +21 -0
- package/npm-shrinkwrap.json +3822 -0
- package/package.json +15 -9
- package/dist/node-runtime/setup-YRBKH2LD.js +0 -155
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunR: permission modes (YOLO / Auto / Read-only).\n *\n * Per-session only, with a configurable default for new sessions.\n *\n * - yolo: auto-approve tools; the agent may still ask questions.\n * - auto: fully autonomous; a system-prompt addendum steers the model to\n * self-decide, and rollback is force-enabled for the session.\n * - read-only: mutating tools are hard-blocked.\n *\n * The gate is wired into `agent-session.ts` `_installAgentToolHooks` before\n * the synchronous `_toolCallGates` loop. beforeToolCall is already async, so\n * awaiting the approval dialog is fine.\n *\n * State (mode + session-scoped approvals) is keyed by session id so\n * concurrent gateway chats do not share permission decisions.\n */\n\nimport { dirname, join, resolve } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport { effectiveLargeSubagentLaunchCountForTurn, LARGE_SUBAGENT_LAUNCH_THRESHOLD } from \"./large-subagent-launch.ts\";\nimport { isUserInstructionsPath } from \"./model-instructions.ts\";\nimport { readOnlyModeBlockReason } from \"./plan-mode.ts\";\n\n/** Shift+Tab cycle order. */\nexport const PERMISSION_MODES = [\"yolo\", \"auto\", \"read-only\"] as const;\nexport type PermissionMode = (typeof PERMISSION_MODES)[number];\n\nexport function nextPermissionMode(current: PermissionMode): PermissionMode {\n\tconst i = PERMISSION_MODES.indexOf(current);\n\treturn PERMISSION_MODES[(i + 1) % PERMISSION_MODES.length];\n}\n\n/** True when the session is read-only. */\nexport function isReadOnlyModeActive(sessionId?: string): boolean {\n\treturn getPermissionMode(sessionId) === \"read-only\";\n}\n\n/**\n * Destination mode when leaving a read-only planning session.\n * Explicit Shift+Tab or `/mode` picks do not use this.\n */\nexport function restorePermissionModeAfterPlan(\n\tprevious: PermissionMode | undefined,\n\tdefaultMode: PermissionMode,\n): PermissionMode {\n\tif (previous && previous !== \"read-only\") return previous;\n\treturn defaultMode;\n}\n\nexport interface ApprovalRequest {\n\ttoolName: string;\n\t/** \"large-subagent-launch\" or \"plan\" approval. */\n\taction: string;\n\tdetail: string;\n\t/** \"large-subagent-launch\" for aggregate child confirmation, \"plan\" for the\n\t * present_plan plan-approval prompt — the UI renders a dedicated dialog\n\t * for each instead of the generic tool dialog. */\n\tkind?: \"large-subagent-launch\" | \"plan\";\n}\n\nexport type ApprovalDecision = \"once\" | \"session\" | \"reject\";\n/** Handlers may return a bare decision string, a reject carrying user feedback\n * that becomes the block reason the model sees, or an approve carrying optional\n * feedback (plan approval with comments). */\nexport type ApprovalResponse =\n\t| ApprovalDecision\n\t| { decision: \"reject\"; feedback: string }\n\t| { decision: \"approve\"; feedback?: string };\n\n/** Read-only tools that never need approval. */\nconst READ_ONLY_TOOLS = new Set([\n\t\"read\",\n\t\"grep\",\n\t\"find\",\n\t\"ls\",\n\t\"web_search\",\n\t\"web_fetch\",\n\t\"fetch_content\",\n\t\"get_search_content\",\n\t\"sourcegraph\",\n\t\"repo_map\",\n\t\"symbol_outline\",\n\t\"read_block\",\n\t\"code_overview\",\n\t\"ast_search\",\n\t\"lsp_diagnostics\",\n\t\"lsp_hover\",\n\t\"lsp_definition\",\n\t\"lsp_references\",\n\t\"lsp_symbols\",\n\t\"lsp_code_actions\",\n\t\"lsp_completions\",\n\t\"lsp_rename\",\n\t\"memory_load\",\n\t\"subagent_wait\",\n\t\"subagent_supervisor\",\n\t\"intercom\",\n\t\"contact_supervisor\",\n\t\"present_plan\",\n\t\"structured_output\",\n]);\n\nexport const NO_HANDLER_REASON = \"Approval channel unavailable.\";\nexport const LARGE_SUBAGENT_LAUNCH_REJECT_REASON = \"Large subagent launch rejected by user.\";\nexport const NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON = \"Large subagent launch blocked: no approval channel available.\";\nconst LARGE_SUBAGENT_LAUNCH_ACTION = \"large-subagent-launch\";\n\ninterface PermissionContext {\n\tmode: PermissionMode;\n\tapprovals: Set<string>;\n}\n\nconst contexts = new Map<string, PermissionContext>();\nlet defaultContext: PermissionContext = { mode: \"yolo\", approvals: new Set() };\nlet approvalHandler: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined;\n/** One aggregate prompt covers every sibling SINGLE `subagent` on the same assistant message. */\nconst turnLargeLaunchDecisions = new WeakMap<object, { decision: ApprovalDecision; feedback?: string }>();\n\nfunction getContext(sessionId?: string): PermissionContext {\n\tif (!sessionId) return defaultContext;\n\treturn contexts.get(sessionId) ?? defaultContext;\n}\n\nexport function createPermissionContext(sessionId: string, mode: PermissionMode = defaultContext.mode): void {\n\tcontexts.set(sessionId, { mode, approvals: new Set() });\n}\n\nexport function deletePermissionContext(sessionId: string): void {\n\tcontexts.delete(sessionId);\n}\n\nexport function getPermissionMode(sessionId?: string): PermissionMode {\n\treturn getContext(sessionId).mode;\n}\n\nexport function setPermissionMode(mode: PermissionMode, sessionId?: string): void {\n\tgetContext(sessionId).mode = mode;\n}\n\nexport function resetPermissions(defaultMode: PermissionMode = \"yolo\", sessionId?: string): void {\n\tif (sessionId) {\n\t\tcontexts.set(sessionId, { mode: defaultMode, approvals: new Set() });\n\t} else {\n\t\tdefaultContext = { mode: defaultMode, approvals: new Set() };\n\t}\n}\n\nexport function registerApprovalHandler(fn: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined): void {\n\tapprovalHandler = fn;\n}\n\n/** Model-facing result texts for the present_plan tool. */\nexport const PLAN_APPROVED_TEXT = \"Plan approved — implement it now.\";\nexport const PLAN_DECLINED_TEXT = \"Plan declined — revise the plan and call present_plan again.\";\nexport const PLAN_PASS_THROUGH_TEXT = \"Plan presented. The user will review and reply.\";\n\n/** lunr: map an approval response to the model-facing present_plan result text. */\nexport function planApprovalResultText(resp: ApprovalResponse): string {\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (decision === \"reject\") {\n\t\treturn feedback\n\t\t\t? `Plan declined: ${feedback} — revise the plan and call present_plan again.`\n\t\t\t: PLAN_DECLINED_TEXT;\n\t}\n\treturn feedback ? `Plan approved with feedback: ${feedback} — implement it now.` : PLAN_APPROVED_TEXT;\n}\n\n/**\n * lunr: present_plan approval request. Unlike the aggregate launch gate\n * this fails OPEN when no approval handler is registered (or none is reachable,\n * e.g. a gateway turn without a chat context): headless sessions have no one to\n * show the dialog to, so the plan is presented and the user replies in chat\n * instead of deadlocking the turn. Everything else keeps fail-closed.\n */\nexport async function requestPlanApproval(summary: string): Promise<string> {\n\tif (!approvalHandler) return PLAN_PASS_THROUGH_TEXT;\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({ toolName: \"present_plan\", action: \"plan\", detail: summary, kind: \"plan\" });\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"approval request failed\";\n\t\tif (message === NO_HANDLER_REASON) return PLAN_PASS_THROUGH_TEXT;\n\t\treturn `Plan declined: ${message} — revise the plan and call present_plan again.`;\n\t}\n\treturn planApprovalResultText(resp);\n}\n\nexport function clearSessionApprovals(sessionId?: string): void {\n\tgetContext(sessionId).approvals.clear();\n}\n\n/** Test seam: remove every per-session context and restore the default. */\nexport function resetAllPermissionContexts(): void {\n\tcontexts.clear();\n\tdefaultContext = { mode: \"yolo\", approvals: new Set() };\n\tapprovalHandler = undefined;\n}\n\n/** Appended to the system prompt while auto mode is active. */\nexport const AUTO_MODE_ADDENDUM =\n\t\"You are running fully autonomously. Do not ask the user questions or wait for confirmation; make reasonable decisions and complete the task end-to-end.\";\n\nfunction resolvePath(cwd: string, p: unknown): string {\n\tif (typeof p !== \"string\") return \"\";\n\tif (!p) return \"\";\n\treturn resolve(cwd, p);\n}\n\nexport const GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON =\n\t\"The agents instruction tree is user-managed. The agent cannot change ~/.lunr/agent/agents/.\";\nexport const MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"Memory is model-managed through the memory tools. Do not directly change ~/.lunr/simple-memory/memory.md.\";\nexport const SETTINGS_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"lunR settings are user-managed through /settings. Do not directly change settings.json.\";\n\nfunction protectedFileWriteReason(toolName: string, input: Record<string, unknown>, cwd: string): string | undefined {\n\tif (toolName !== \"edit\" && toolName !== \"write\" && toolName !== \"code_rewrite\") return undefined;\n\tconst target = resolvePath(cwd, input.path);\n\tif (!target) return undefined;\n\tconst normalize = (path: string) => {\n\t\tconst normalized = resolve(path).replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n\t\treturn process.platform === \"win32\" ? normalized.toLowerCase() : normalized;\n\t};\n\tif (isUserInstructionsPath(target, getAgentDir())) {\n\t\treturn GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON;\n\t}\n\tif (normalize(target) === normalize(join(dirname(getAgentDir()), \"simple-memory\", \"memory.md\"))) {\n\t\treturn MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\tconst globalSettings = normalize(join(getAgentDir(), \"settings.json\"));\n\tconst projectSettings = normalize(join(cwd, CONFIG_DIR_NAME, \"settings.json\"));\n\tconst normalizedTarget = normalize(target);\n\tif (normalizedTarget === normalize(join(getAgentDir(), \"install-features.json\"))) {\n\t\treturn \"Optional features are user-managed through lunr features; Browser is managed in /settings. Do not change install-features.json directly.\";\n\t}\n\tif (normalizedTarget === globalSettings || normalizedTarget === projectSettings) {\n\t\treturn SETTINGS_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\treturn undefined;\n}\n\ninterface RequestedChildLaunch {\n\tdescription: string;\n\tpermissions: \"full\" | \"read-only\";\n}\n\nfunction collectRequestedChildLaunches(value: unknown, launches: RequestedChildLaunch[]): void {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return;\n\tconst input = value as Record<string, unknown>;\n\tif (typeof input.task === \"string\" && input.task.trim()) {\n\t\tlaunches.push({\n\t\t\tdescription:\n\t\t\t\ttypeof input.description === \"string\" && input.description.trim()\n\t\t\t\t\t? input.description.trim()\n\t\t\t\t\t: input.task.trim(),\n\t\t\tpermissions: input.permissions === \"read-only\" ? \"read-only\" : \"full\",\n\t\t});\n\t\treturn;\n\t}\n\tfor (const key of [\"tasks\", \"chain\", \"parallel\"] as const) {\n\t\tconst children = input[key];\n\t\tif (Array.isArray(children)) {\n\t\t\tfor (const child of children) collectRequestedChildLaunches(child, launches);\n\t\t} else if (key === \"parallel\") {\n\t\t\tcollectRequestedChildLaunches(children, launches);\n\t\t}\n\t}\n}\n\nfunction getRequestedChildLaunches(input: Record<string, unknown>): RequestedChildLaunch[] {\n\tconst launches: RequestedChildLaunch[] = [];\n\tcollectRequestedChildLaunches(input, launches);\n\treturn launches;\n}\n\nexport interface GateOptions {\n\t/** Global preference for aggregate confirmation. Defaults to enabled. */\n\tconfirmLargeSubagentLaunches?: boolean;\n\t/** Assistant message that issued this tool call. Same-turn sibling SINGLE\n\t * `subagent` calls count toward the aggregate threshold. */\n\tassistantMessage?: {\n\t\tcontent?: ReadonlyArray<{ type?: string; name?: string; arguments?: unknown }>;\n\t};\n}\n\nfunction firstTaskText(value: unknown): string {\n\tif (typeof value === \"string\" && value.trim()) return sanitizeDetail(value);\n\treturn \"\";\n}\n\n/** First task text of a parallel fan-out or sibling SINGLE, used as the dialog summary. */\nfunction largeLaunchTaskSummary(\n\tinput: Record<string, unknown>,\n\tassistantMessage?: GateOptions[\"assistantMessage\"],\n): string {\n\tif (Array.isArray(input.tasks)) {\n\t\tfor (const task of input.tasks) {\n\t\t\tconst text = task && typeof task === \"object\" ? firstTaskText((task as { task?: unknown }).task) : \"\";\n\t\t\tif (text) return text;\n\t\t}\n\t}\n\tconst own = firstTaskText(input.task);\n\tif (own) return own;\n\tfor (const block of assistantMessage?.content ?? []) {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") continue;\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\tconst text = firstTaskText(args?.task);\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n/**\n * Aggregate launch gate. A launch above LARGE_SUBAGENT_LAUNCH_THRESHOLD\n * parallel subagents in one `tasks`/`chain.parallel` call, or that many same-turn\n * SINGLE `subagent` calls) requires user approval in yolo mode; auto\n * mode runs it unconditionally.\n * Fail-closed without an approval handler.\n */\nasync function gateLargeSubagentLaunch(\n\tinput: Record<string, unknown>,\n\tctx: PermissionContext,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tif (ctx.mode === \"auto\") return undefined;\n\tif (options?.confirmLargeSubagentLaunches === false) return undefined;\n\tconst count = effectiveLargeSubagentLaunchCountForTurn(input, options?.assistantMessage);\n\tif (count <= LARGE_SUBAGENT_LAUNCH_THRESHOLD) return undefined;\n\tif (ctx.approvals.has(LARGE_SUBAGENT_LAUNCH_ACTION)) return undefined;\n\n\tconst turnKey = options?.assistantMessage;\n\tconst cached = turnKey ? turnLargeLaunchDecisions.get(turnKey) : undefined;\n\tif (cached) {\n\t\tif (cached.decision === \"reject\") {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: cached.feedback\n\t\t\t\t\t? `${LARGE_SUBAGENT_LAUNCH_REJECT_REASON} ${cached.feedback}`\n\t\t\t\t\t: LARGE_SUBAGENT_LAUNCH_REJECT_REASON,\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tif (!approvalHandler) {\n\t\treturn { block: true, reason: NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON };\n\t}\n\n\tconst summary = largeLaunchTaskSummary(input, options?.assistantMessage);\n\tconst siblingLaunches = (options?.assistantMessage?.content ?? []).flatMap((block) => {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") return [];\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\treturn args ? getRequestedChildLaunches(args) : [];\n\t});\n\tconst launches = siblingLaunches.length > 0 ? siblingLaunches : getRequestedChildLaunches(input);\n\tconst launchSummary = launches\n\t\t.map((launch) => `${launch.description}\\npermissions: ${launch.permissions}`)\n\t\t.join(\"\\n\");\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({\n\t\t\ttoolName: \"subagent\",\n\t\t\taction: LARGE_SUBAGENT_LAUNCH_ACTION,\n\t\t\tdetail: `large subagent launch (${count} children)${launchSummary || summary ? `\\n${launchSummary || summary}` : \"\"}`,\n\t\t\tkind: \"large-subagent-launch\",\n\t\t});\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON;\n\t\treturn { block: true, reason: message };\n\t}\n\n\tconst rawDecision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst decision: ApprovalDecision = rawDecision === \"approve\" ? \"once\" : rawDecision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (turnKey) {\n\t\tturnLargeLaunchDecisions.set(turnKey, { decision, ...(feedback ? { feedback } : {}) });\n\t}\n\tif (decision === \"session\") {\n\t\tctx.approvals.add(LARGE_SUBAGENT_LAUNCH_ACTION);\n\t\treturn undefined;\n\t}\n\tif (decision === \"reject\") {\n\t\treturn {\n\t\t\tblock: true,\n\t\t\treason: feedback ? `${LARGE_SUBAGENT_LAUNCH_REJECT_REASON} ${feedback}` : LARGE_SUBAGENT_LAUNCH_REJECT_REASON,\n\t\t};\n\t}\n\treturn undefined;\n}\n\nfunction sanitizeDetail(value: unknown): string {\n\tconst text = String(value ?? \"\").trim();\n\treturn text.length > 200 ? `${text.slice(0, 200)}…` : text;\n}\n\n/**\n * Returns a block result when the tool call should be blocked, else undefined.\n * Read-only tools always pass. YOLO and Auto pass mutating tools. Read-only\n * mode hard-blocks mutating tools without prompting.\n */\nexport async function gateToolCall(\n\ttoolName: string,\n\tinput: Record<string, unknown>,\n\tcwd: string,\n\tsessionId?: string,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tconst ctx = getContext(sessionId);\n\tconst protectedWriteReason = protectedFileWriteReason(toolName, input, cwd);\n\tif (protectedWriteReason) {\n\t\treturn { block: true, reason: protectedWriteReason };\n\t}\n\tif (READ_ONLY_TOOLS.has(toolName)) return undefined;\n\n\tif (ctx.mode === \"read-only\") {\n\t\tconst reason = readOnlyModeBlockReason(toolName, input);\n\t\tif (reason) return { block: true, reason };\n\t\tif (toolName === \"mcp\") {\n\t\t\tif (input.tool || input.connect || (input.action && input.action !== \"ui-messages\")) {\n\t\t\t\treturn { block: true, reason: \"Read-only mode blocks MCP tool calls, connections, and authentication.\" };\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tif (toolName === \"subagent\") {\n\t\t\tconst action = input.action;\n\t\t\tif (\n\t\t\t\tgetRequestedChildLaunches(input).some((child) => child.permissions === \"full\") ||\n\t\t\t\taction === \"resume\" ||\n\t\t\t\taction === \"steer\" ||\n\t\t\t\taction === \"append-step\" ||\n\t\t\t\taction === \"schedule\" ||\n\t\t\t\taction === \"schedule-cancel\"\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\treason: \"Read-only mode cannot launch full-access children or change running children.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tif (toolName === \"bash\" || toolName === \"browser\" || toolName === \"code_rewrite\") return undefined;\n\t\treturn { block: true, reason: `Read-only mode cannot verify that ${toolName} is safe.` };\n\t}\n\tif (toolName === \"subagent\") {\n\t\tconst launchResult = await gateLargeSubagentLaunch(input, ctx, options);\n\t\tif (launchResult) return launchResult;\n\t}\n\treturn undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunR: permission modes (YOLO / Auto / Read-only).\n *\n * Per-session only, with a configurable default for new sessions.\n *\n * - yolo: auto-approve tools; the agent may still ask questions.\n * - auto: fully autonomous; a system-prompt addendum steers the model to\n * self-decide, and rollback is force-enabled for the session.\n * - read-only: mutating tools are hard-blocked.\n *\n * The gate is wired into `agent-session.ts` `_installAgentToolHooks` before\n * the synchronous `_toolCallGates` loop. beforeToolCall is already async, so\n * awaiting the approval dialog is fine.\n *\n * State (mode + session-scoped approvals) is keyed by session id so\n * concurrent gateway chats do not share permission decisions.\n */\n\nimport { dirname, join, resolve } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport { computerPolicy } from \"./computer-use/policy.ts\";\nimport { effectiveLargeSubagentLaunchCountForTurn, LARGE_SUBAGENT_LAUNCH_THRESHOLD } from \"./large-subagent-launch.ts\";\nimport { isUserInstructionsPath } from \"./model-instructions.ts\";\nimport { readOnlyModeBlockReason } from \"./plan-mode.ts\";\n\n/** Shift+Tab cycle order. */\nexport const PERMISSION_MODES = [\"yolo\", \"auto\", \"read-only\"] as const;\nexport type PermissionMode = (typeof PERMISSION_MODES)[number];\n\nexport function nextPermissionMode(current: PermissionMode): PermissionMode {\n\tconst i = PERMISSION_MODES.indexOf(current);\n\treturn PERMISSION_MODES[(i + 1) % PERMISSION_MODES.length];\n}\n\n/** True when the session is read-only. */\nexport function isReadOnlyModeActive(sessionId?: string): boolean {\n\treturn getPermissionMode(sessionId) === \"read-only\";\n}\n\n/**\n * Destination mode when leaving a read-only planning session.\n * Explicit Shift+Tab or `/mode` picks do not use this.\n */\nexport function restorePermissionModeAfterPlan(\n\tprevious: PermissionMode | undefined,\n\tdefaultMode: PermissionMode,\n): PermissionMode {\n\tif (previous && previous !== \"read-only\") return previous;\n\treturn defaultMode;\n}\n\nexport interface ApprovalRequest {\n\ttoolName: string;\n\t/** \"large-subagent-launch\" or \"plan\" approval. */\n\taction: string;\n\tdetail: string;\n\t/** \"large-subagent-launch\" for aggregate child confirmation, \"plan\" for the\n\t * present_plan plan-approval prompt — the UI renders a dedicated dialog\n\t * for each instead of the generic tool dialog. */\n\tkind?: \"large-subagent-launch\" | \"plan\";\n}\n\nexport type ApprovalDecision = \"once\" | \"session\" | \"reject\";\n/** Handlers may return a bare decision string, a reject carrying user feedback\n * that becomes the block reason the model sees, or an approve carrying optional\n * feedback (plan approval with comments). */\nexport type ApprovalResponse =\n\t| ApprovalDecision\n\t| { decision: \"reject\"; feedback: string }\n\t| { decision: \"approve\"; feedback?: string };\n\n/** Read-only tools that never need approval. */\nconst READ_ONLY_TOOLS = new Set([\n\t\"read\",\n\t\"grep\",\n\t\"find\",\n\t\"ls\",\n\t\"web_search\",\n\t\"web_fetch\",\n\t\"fetch_content\",\n\t\"get_search_content\",\n\t\"sourcegraph\",\n\t\"repo_map\",\n\t\"symbol_outline\",\n\t\"read_block\",\n\t\"code_overview\",\n\t\"ast_search\",\n\t\"lsp_diagnostics\",\n\t\"lsp_hover\",\n\t\"lsp_definition\",\n\t\"lsp_references\",\n\t\"lsp_symbols\",\n\t\"lsp_code_actions\",\n\t\"lsp_completions\",\n\t\"lsp_rename\",\n\t\"memory_load\",\n\t\"subagent_wait\",\n\t\"subagent_supervisor\",\n\t\"intercom\",\n\t\"contact_supervisor\",\n\t\"present_plan\",\n\t\"structured_output\",\n]);\n\nexport const NO_HANDLER_REASON = \"Approval channel unavailable.\";\nexport const LARGE_SUBAGENT_LAUNCH_REJECT_REASON = \"Large subagent launch rejected by user.\";\nexport const NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON = \"Large subagent launch blocked: no approval channel available.\";\nconst LARGE_SUBAGENT_LAUNCH_ACTION = \"large-subagent-launch\";\n\ninterface PermissionContext {\n\tallowApprovals?: boolean;\n\tmode: PermissionMode;\n\tapprovals: Set<string>;\n}\n\nconst contexts = new Map<string, PermissionContext>();\nlet defaultContext: PermissionContext = { mode: \"yolo\", approvals: new Set() };\nlet approvalHandler: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined;\n/** One aggregate prompt covers every sibling SINGLE `subagent` on the same assistant message. */\nconst turnLargeLaunchDecisions = new WeakMap<object, { decision: ApprovalDecision; feedback?: string }>();\n\nfunction getContext(sessionId?: string): PermissionContext {\n\tif (!sessionId) return defaultContext;\n\treturn contexts.get(sessionId) ?? defaultContext;\n}\n\nexport function createPermissionContext(\n\tsessionId: string,\n\tmode: PermissionMode = defaultContext.mode,\n\tallowApprovals = true,\n): void {\n\tcontexts.set(sessionId, { mode, allowApprovals, approvals: new Set() });\n}\n\nexport function deletePermissionContext(sessionId: string): void {\n\tcontexts.delete(sessionId);\n}\n\nexport function getPermissionMode(sessionId?: string): PermissionMode {\n\treturn getContext(sessionId).mode;\n}\n\nexport function setPermissionMode(mode: PermissionMode, sessionId?: string): void {\n\tgetContext(sessionId).mode = mode;\n}\n\nexport function resetPermissions(defaultMode: PermissionMode = \"yolo\", sessionId?: string): void {\n\tif (sessionId) {\n\t\tcontexts.set(sessionId, { mode: defaultMode, approvals: new Set() });\n\t} else {\n\t\tdefaultContext = { mode: defaultMode, approvals: new Set() };\n\t}\n}\n\nexport function registerApprovalHandler(fn: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined): void {\n\tapprovalHandler = fn;\n}\n\n/** Model-facing result texts for the present_plan tool. */\nexport const PLAN_APPROVED_TEXT = \"Plan approved — implement it now.\";\nexport const PLAN_DECLINED_TEXT = \"Plan declined — revise the plan and call present_plan again.\";\nexport const PLAN_PASS_THROUGH_TEXT = \"Plan presented. The user will review and reply.\";\n\n/** lunr: map an approval response to the model-facing present_plan result text. */\nexport function planApprovalResultText(resp: ApprovalResponse): string {\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (decision === \"reject\") {\n\t\treturn feedback\n\t\t\t? `Plan declined: ${feedback} — revise the plan and call present_plan again.`\n\t\t\t: PLAN_DECLINED_TEXT;\n\t}\n\treturn feedback ? `Plan approved with feedback: ${feedback} — implement it now.` : PLAN_APPROVED_TEXT;\n}\n\n/**\n * lunr: present_plan approval request. Unlike the aggregate launch gate\n * this fails OPEN when no approval handler is registered (or none is reachable,\n * e.g. a gateway turn without a chat context): headless sessions have no one to\n * show the dialog to, so the plan is presented and the user replies in chat\n * instead of deadlocking the turn. Everything else keeps fail-closed.\n */\nexport async function requestPlanApproval(summary: string): Promise<string> {\n\tif (!approvalHandler) return PLAN_PASS_THROUGH_TEXT;\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({ toolName: \"present_plan\", action: \"plan\", detail: summary, kind: \"plan\" });\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"approval request failed\";\n\t\tif (message === NO_HANDLER_REASON) return PLAN_PASS_THROUGH_TEXT;\n\t\treturn `Plan declined: ${message} — revise the plan and call present_plan again.`;\n\t}\n\treturn planApprovalResultText(resp);\n}\n\nexport function clearSessionApprovals(sessionId?: string): void {\n\tgetContext(sessionId).approvals.clear();\n}\n\n/** Test seam: remove every per-session context and restore the default. */\nexport function resetAllPermissionContexts(): void {\n\tcontexts.clear();\n\tdefaultContext = { mode: \"yolo\", approvals: new Set() };\n\tapprovalHandler = undefined;\n}\n\n/** Appended to the system prompt while auto mode is active. */\nexport const AUTO_MODE_ADDENDUM =\n\t\"You are running fully autonomously. Do not ask the user questions or wait for confirmation; make reasonable decisions and complete the task end-to-end.\";\n\nfunction resolvePath(cwd: string, p: unknown): string {\n\tif (typeof p !== \"string\") return \"\";\n\tif (!p) return \"\";\n\treturn resolve(cwd, p);\n}\n\nexport const GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON =\n\t\"The agents instruction tree is user-managed. The agent cannot change ~/.lunr/agent/agents/.\";\nexport const MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"Memory is model-managed through the memory tools. Do not directly change ~/.lunr/simple-memory/memory.md.\";\nexport const SETTINGS_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"lunR settings are user-managed through /settings. Do not directly change settings.json.\";\n\nfunction protectedFileWriteReason(toolName: string, input: Record<string, unknown>, cwd: string): string | undefined {\n\tif (toolName !== \"edit\" && toolName !== \"write\" && toolName !== \"code_rewrite\") return undefined;\n\tconst target = resolvePath(cwd, input.path);\n\tif (!target) return undefined;\n\tconst normalize = (path: string) => {\n\t\tconst normalized = resolve(path).replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n\t\treturn process.platform === \"win32\" ? normalized.toLowerCase() : normalized;\n\t};\n\tif (isUserInstructionsPath(target, getAgentDir())) {\n\t\treturn GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON;\n\t}\n\tif (normalize(target) === normalize(join(dirname(getAgentDir()), \"simple-memory\", \"memory.md\"))) {\n\t\treturn MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\tconst globalSettings = normalize(join(getAgentDir(), \"settings.json\"));\n\tconst projectSettings = normalize(join(cwd, CONFIG_DIR_NAME, \"settings.json\"));\n\tconst normalizedTarget = normalize(target);\n\tif (normalizedTarget === normalize(join(getAgentDir(), \"install-features.json\"))) {\n\t\treturn \"Optional features are user-managed through lunr features; Browser is managed in /settings. Do not change install-features.json directly.\";\n\t}\n\tif (normalizedTarget === globalSettings || normalizedTarget === projectSettings) {\n\t\treturn SETTINGS_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\treturn undefined;\n}\n\ninterface RequestedChildLaunch {\n\tdescription: string;\n\tpermissions: \"full\" | \"read-only\";\n}\n\nfunction collectRequestedChildLaunches(value: unknown, launches: RequestedChildLaunch[]): void {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return;\n\tconst input = value as Record<string, unknown>;\n\tif (typeof input.task === \"string\" && input.task.trim()) {\n\t\tlaunches.push({\n\t\t\tdescription:\n\t\t\t\ttypeof input.description === \"string\" && input.description.trim()\n\t\t\t\t\t? input.description.trim()\n\t\t\t\t\t: input.task.trim(),\n\t\t\tpermissions: input.permissions === \"read-only\" ? \"read-only\" : \"full\",\n\t\t});\n\t\treturn;\n\t}\n\tfor (const key of [\"tasks\", \"chain\", \"parallel\"] as const) {\n\t\tconst children = input[key];\n\t\tif (Array.isArray(children)) {\n\t\t\tfor (const child of children) collectRequestedChildLaunches(child, launches);\n\t\t} else if (key === \"parallel\") {\n\t\t\tcollectRequestedChildLaunches(children, launches);\n\t\t}\n\t}\n}\n\nfunction getRequestedChildLaunches(input: Record<string, unknown>): RequestedChildLaunch[] {\n\tconst launches: RequestedChildLaunch[] = [];\n\tcollectRequestedChildLaunches(input, launches);\n\treturn launches;\n}\n\nexport interface GateOptions {\n\t/** Global preference for aggregate confirmation. Defaults to enabled. */\n\tconfirmLargeSubagentLaunches?: boolean;\n\t/** Assistant message that issued this tool call. Same-turn sibling SINGLE\n\t * `subagent` calls count toward the aggregate threshold. */\n\tassistantMessage?: {\n\t\tcontent?: ReadonlyArray<{ type?: string; name?: string; arguments?: unknown }>;\n\t};\n}\n\nfunction firstTaskText(value: unknown): string {\n\tif (typeof value === \"string\" && value.trim()) return sanitizeDetail(value);\n\treturn \"\";\n}\n\n/** First task text of a parallel fan-out or sibling SINGLE, used as the dialog summary. */\nfunction largeLaunchTaskSummary(\n\tinput: Record<string, unknown>,\n\tassistantMessage?: GateOptions[\"assistantMessage\"],\n): string {\n\tif (Array.isArray(input.tasks)) {\n\t\tfor (const task of input.tasks) {\n\t\t\tconst text = task && typeof task === \"object\" ? firstTaskText((task as { task?: unknown }).task) : \"\";\n\t\t\tif (text) return text;\n\t\t}\n\t}\n\tconst own = firstTaskText(input.task);\n\tif (own) return own;\n\tfor (const block of assistantMessage?.content ?? []) {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") continue;\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\tconst text = firstTaskText(args?.task);\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n/**\n * Aggregate launch gate. A launch above LARGE_SUBAGENT_LAUNCH_THRESHOLD\n * parallel subagents in one `tasks`/`chain.parallel` call, or that many same-turn\n * SINGLE `subagent` calls) requires user approval in yolo mode; auto\n * mode runs it unconditionally.\n * Fail-closed without an approval handler.\n */\nasync function gateLargeSubagentLaunch(\n\tinput: Record<string, unknown>,\n\tctx: PermissionContext,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tif (ctx.mode === \"auto\") return undefined;\n\tif (options?.confirmLargeSubagentLaunches === false) return undefined;\n\tconst count = effectiveLargeSubagentLaunchCountForTurn(input, options?.assistantMessage);\n\tif (count <= LARGE_SUBAGENT_LAUNCH_THRESHOLD) return undefined;\n\tif (ctx.approvals.has(LARGE_SUBAGENT_LAUNCH_ACTION)) return undefined;\n\n\tconst turnKey = options?.assistantMessage;\n\tconst cached = turnKey ? turnLargeLaunchDecisions.get(turnKey) : undefined;\n\tif (cached) {\n\t\tif (cached.decision === \"reject\") {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: cached.feedback\n\t\t\t\t\t? `${LARGE_SUBAGENT_LAUNCH_REJECT_REASON} ${cached.feedback}`\n\t\t\t\t\t: LARGE_SUBAGENT_LAUNCH_REJECT_REASON,\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tif (!approvalHandler || ctx.allowApprovals === false) {\n\t\treturn { block: true, reason: NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON };\n\t}\n\n\tconst summary = largeLaunchTaskSummary(input, options?.assistantMessage);\n\tconst siblingLaunches = (options?.assistantMessage?.content ?? []).flatMap((block) => {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") return [];\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\treturn args ? getRequestedChildLaunches(args) : [];\n\t});\n\tconst launches = siblingLaunches.length > 0 ? siblingLaunches : getRequestedChildLaunches(input);\n\tconst launchSummary = launches\n\t\t.map((launch) => `${launch.description}\\npermissions: ${launch.permissions}`)\n\t\t.join(\"\\n\");\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({\n\t\t\ttoolName: \"subagent\",\n\t\t\taction: LARGE_SUBAGENT_LAUNCH_ACTION,\n\t\t\tdetail: `large subagent launch (${count} children)${launchSummary || summary ? `\\n${launchSummary || summary}` : \"\"}`,\n\t\t\tkind: \"large-subagent-launch\",\n\t\t});\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON;\n\t\treturn { block: true, reason: message };\n\t}\n\n\tconst rawDecision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst decision: ApprovalDecision = rawDecision === \"approve\" ? \"once\" : rawDecision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (turnKey) {\n\t\tturnLargeLaunchDecisions.set(turnKey, { decision, ...(feedback ? { feedback } : {}) });\n\t}\n\tif (decision === \"session\") {\n\t\tctx.approvals.add(LARGE_SUBAGENT_LAUNCH_ACTION);\n\t\treturn undefined;\n\t}\n\tif (decision === \"reject\") {\n\t\treturn {\n\t\t\tblock: true,\n\t\t\treason: feedback ? `${LARGE_SUBAGENT_LAUNCH_REJECT_REASON} ${feedback}` : LARGE_SUBAGENT_LAUNCH_REJECT_REASON,\n\t\t};\n\t}\n\treturn undefined;\n}\n\nfunction sanitizeDetail(value: unknown): string {\n\tconst text = String(value ?? \"\").trim();\n\treturn text.length > 200 ? `${text.slice(0, 200)}…` : text;\n}\n\n/**\n * Returns a block result when the tool call should be blocked, else undefined.\n * Read-only tools always pass. YOLO and Auto pass mutating tools. Read-only\n * mode hard-blocks mutating tools without prompting.\n */\nexport async function gateToolCall(\n\ttoolName: string,\n\tinput: Record<string, unknown>,\n\tcwd: string,\n\tsessionId?: string,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tconst ctx = getContext(sessionId);\n\tif (toolName.startsWith(\"computer_\")) {\n\t\ttry {\n\t\t\tcomputerPolicy(toolName, input);\n\t\t} catch (error) {\n\t\t\treturn { block: true, reason: String(error) };\n\t\t}\n\t}\n\tconst protectedWriteReason = protectedFileWriteReason(toolName, input, cwd);\n\tif (protectedWriteReason) {\n\t\treturn { block: true, reason: protectedWriteReason };\n\t}\n\tif (READ_ONLY_TOOLS.has(toolName)) return undefined;\n\n\tif (ctx.mode === \"read-only\") {\n\t\tconst reason = readOnlyModeBlockReason(toolName, input);\n\t\tif (reason) return { block: true, reason };\n\t\tif (toolName === \"mcp\") {\n\t\t\tif (input.tool || input.connect || (input.action && input.action !== \"ui-messages\")) {\n\t\t\t\treturn { block: true, reason: \"Read-only mode blocks MCP tool calls, connections, and authentication.\" };\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tif (toolName === \"subagent\") {\n\t\t\tconst action = input.action;\n\t\t\tif (\n\t\t\t\tgetRequestedChildLaunches(input).some((child) => child.permissions === \"full\") ||\n\t\t\t\taction === \"resume\" ||\n\t\t\t\taction === \"steer\" ||\n\t\t\t\taction === \"append-step\" ||\n\t\t\t\taction === \"schedule\" ||\n\t\t\t\taction === \"schedule-cancel\"\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\treason: \"Read-only mode cannot launch full-access children or change running children.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tif (toolName.startsWith(\"computer_\")) return undefined;\n\t\tif (toolName === \"bash\" || toolName === \"browser\" || toolName === \"code_rewrite\") return undefined;\n\t\treturn { block: true, reason: `Read-only mode cannot verify that ${toolName} is safe.` };\n\t}\n\tif (toolName === \"subagent\") {\n\t\tconst launchResult = await gateLargeSubagentLaunch(input, ctx, options);\n\t\tif (launchResult) return launchResult;\n\t}\n\treturn undefined;\n}\n"]}
|
package/dist/core/permissions.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { dirname, join, resolve } from "node:path";
|
|
19
19
|
import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
|
|
20
|
+
import { computerPolicy } from "./computer-use/policy.js";
|
|
20
21
|
import { effectiveLargeSubagentLaunchCountForTurn, LARGE_SUBAGENT_LAUNCH_THRESHOLD } from "./large-subagent-launch.js";
|
|
21
22
|
import { isUserInstructionsPath } from "./model-instructions.js";
|
|
22
23
|
import { readOnlyModeBlockReason } from "./plan-mode.js";
|
|
@@ -85,8 +86,8 @@ function getContext(sessionId) {
|
|
|
85
86
|
return defaultContext;
|
|
86
87
|
return contexts.get(sessionId) ?? defaultContext;
|
|
87
88
|
}
|
|
88
|
-
export function createPermissionContext(sessionId, mode = defaultContext.mode) {
|
|
89
|
-
contexts.set(sessionId, { mode, approvals: new Set() });
|
|
89
|
+
export function createPermissionContext(sessionId, mode = defaultContext.mode, allowApprovals = true) {
|
|
90
|
+
contexts.set(sessionId, { mode, allowApprovals, approvals: new Set() });
|
|
90
91
|
}
|
|
91
92
|
export function deletePermissionContext(sessionId) {
|
|
92
93
|
contexts.delete(sessionId);
|
|
@@ -281,7 +282,7 @@ async function gateLargeSubagentLaunch(input, ctx, options) {
|
|
|
281
282
|
}
|
|
282
283
|
return undefined;
|
|
283
284
|
}
|
|
284
|
-
if (!approvalHandler) {
|
|
285
|
+
if (!approvalHandler || ctx.allowApprovals === false) {
|
|
285
286
|
return { block: true, reason: NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON };
|
|
286
287
|
}
|
|
287
288
|
const summary = largeLaunchTaskSummary(input, options?.assistantMessage);
|
|
@@ -339,6 +340,14 @@ function sanitizeDetail(value) {
|
|
|
339
340
|
*/
|
|
340
341
|
export async function gateToolCall(toolName, input, cwd, sessionId, options) {
|
|
341
342
|
const ctx = getContext(sessionId);
|
|
343
|
+
if (toolName.startsWith("computer_")) {
|
|
344
|
+
try {
|
|
345
|
+
computerPolicy(toolName, input);
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
return { block: true, reason: String(error) };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
342
351
|
const protectedWriteReason = protectedFileWriteReason(toolName, input, cwd);
|
|
343
352
|
if (protectedWriteReason) {
|
|
344
353
|
return { block: true, reason: protectedWriteReason };
|
|
@@ -370,6 +379,8 @@ export async function gateToolCall(toolName, input, cwd, sessionId, options) {
|
|
|
370
379
|
}
|
|
371
380
|
return undefined;
|
|
372
381
|
}
|
|
382
|
+
if (toolName.startsWith("computer_"))
|
|
383
|
+
return undefined;
|
|
373
384
|
if (toolName === "bash" || toolName === "browser" || toolName === "code_rewrite")
|
|
374
385
|
return undefined;
|
|
375
386
|
return { block: true, reason: `Read-only mode cannot verify that ${toolName} is safe.` };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,wCAAwC,EAAE,+BAA+B,EAAE,MAAM,4BAA4B,CAAC;AACvH,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,6BAA6B;AAC7B,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAU,CAAC;AAGvE,MAAM,UAAU,kBAAkB,CAAC,OAAuB,EAAkB;IAC3E,MAAM,CAAC,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAAA,CAC3D;AAED,0CAA0C;AAC1C,MAAM,UAAU,oBAAoB,CAAC,SAAkB,EAAW;IACjE,OAAO,iBAAiB,CAAC,SAAS,CAAC,KAAK,WAAW,CAAC;AAAA,CACpD;AAED;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAC7C,QAAoC,EACpC,WAA2B,EACV;IACjB,IAAI,QAAQ,IAAI,QAAQ,KAAK,WAAW;QAAE,OAAO,QAAQ,CAAC;IAC1D,OAAO,WAAW,CAAC;AAAA,CACnB;AAsBD,gDAAgD;AAChD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC/B,MAAM;IACN,MAAM;IACN,MAAM;IACN,IAAI;IACJ,YAAY;IACZ,WAAW;IACX,eAAe;IACf,oBAAoB;IACpB,aAAa;IACb,UAAU;IACV,gBAAgB;IAChB,YAAY;IACZ,eAAe;IACf,YAAY;IACZ,iBAAiB;IACjB,WAAW;IACX,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,kBAAkB;IAClB,iBAAiB;IACjB,YAAY;IACZ,aAAa;IACb,eAAe;IACf,qBAAqB;IACrB,UAAU;IACV,oBAAoB;IACpB,cAAc;IACd,mBAAmB;CACnB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,+BAA+B,CAAC;AACjE,MAAM,CAAC,MAAM,mCAAmC,GAAG,yCAAyC,CAAC;AAC7F,MAAM,CAAC,MAAM,uCAAuC,GAAG,+DAA+D,CAAC;AACvH,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAO7D,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;AACtD,IAAI,cAAc,GAAsB,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;AAC/E,IAAI,eAAkF,CAAC;AACvF,iGAAiG;AACjG,MAAM,wBAAwB,GAAG,IAAI,OAAO,EAA6D,CAAC;AAE1G,SAAS,UAAU,CAAC,SAAkB,EAAqB;IAC1D,IAAI,CAAC,SAAS;QAAE,OAAO,cAAc,CAAC;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,cAAc,CAAC;AAAA,CACjD;AAED,MAAM,UAAU,uBAAuB,CAAC,SAAiB,EAAE,IAAI,GAAmB,cAAc,CAAC,IAAI,EAAQ;IAC5G,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;AAAA,CACxD;AAED,MAAM,UAAU,uBAAuB,CAAC,SAAiB,EAAQ;IAChE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAAA,CAC3B;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAkB,EAAkB;IACrE,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;AAAA,CAClC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAoB,EAAE,SAAkB,EAAQ;IACjF,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;AAAA,CAClC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAW,GAAmB,MAAM,EAAE,SAAkB,EAAQ;IAChG,IAAI,SAAS,EAAE,CAAC;QACf,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACP,cAAc,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IAC9D,CAAC;AAAA,CACD;AAED,MAAM,UAAU,uBAAuB,CAAC,EAAqE,EAAQ;IACpH,eAAe,GAAG,EAAE,CAAC;AAAA,CACrB;AAED,2DAA2D;AAC3D,MAAM,CAAC,MAAM,kBAAkB,GAAG,qCAAmC,CAAC;AACtE,MAAM,CAAC,MAAM,kBAAkB,GAAG,gEAA8D,CAAC;AACjG,MAAM,CAAC,MAAM,sBAAsB,GAAG,iDAAiD,CAAC;AAExF,mFAAmF;AACnF,MAAM,UAAU,sBAAsB,CAAC,IAAsB,EAAU;IACtE,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IACjE,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC9E,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,QAAQ;YACd,CAAC,CAAC,kBAAkB,QAAQ,mDAAiD;YAC7E,CAAC,CAAC,kBAAkB,CAAC;IACvB,CAAC;IACD,OAAO,QAAQ,CAAC,CAAC,CAAC,gCAAgC,QAAQ,wBAAsB,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAAA,CACtG;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAmB;IAC3E,IAAI,CAAC,eAAe;QAAE,OAAO,sBAAsB,CAAC;IACpD,IAAI,IAAsB,CAAC;IAC3B,IAAI,CAAC;QACJ,IAAI,GAAG,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3G,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC;QAC/E,IAAI,OAAO,KAAK,iBAAiB;YAAE,OAAO,sBAAsB,CAAC;QACjE,OAAO,kBAAkB,OAAO,mDAAiD,CAAC;IACnF,CAAC;IACD,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC;AAAA,CACpC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAkB,EAAQ;IAC/D,UAAU,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;AAAA,CACxC;AAED,2EAA2E;AAC3E,MAAM,UAAU,0BAA0B,GAAS;IAClD,QAAQ,CAAC,KAAK,EAAE,CAAC;IACjB,cAAc,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IACxD,eAAe,GAAG,SAAS,CAAC;AAAA,CAC5B;AAED,+DAA+D;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAC9B,yJAAyJ,CAAC;AAE3J,SAAS,WAAW,CAAC,GAAW,EAAE,CAAU,EAAU;IACrD,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACrC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAClB,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AAAA,CACvB;AAED,MAAM,CAAC,MAAM,qCAAqC,GACjD,6FAA6F,CAAC;AAC/F,MAAM,CAAC,MAAM,qCAAqC,GACjD,2GAA2G,CAAC;AAC7G,MAAM,CAAC,MAAM,uCAAuC,GACnD,yFAAyF,CAAC;AAE3F,SAAS,wBAAwB,CAAC,QAAgB,EAAE,KAA8B,EAAE,GAAW,EAAsB;IACpH,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,cAAc;QAAE,OAAO,SAAS,CAAC;IACjG,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC;QACnC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACxE,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;IAAA,CAC5E,CAAC;IACF,IAAI,sBAAsB,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;QACnD,OAAO,qCAAqC,CAAC;IAC9C,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QACjG,OAAO,qCAAqC,CAAC;IAC9C,CAAC;IACD,MAAM,cAAc,GAAG,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;IACvE,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;IAC/E,MAAM,gBAAgB,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,gBAAgB,KAAK,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC;QAClF,OAAO,0IAA0I,CAAC;IACnJ,CAAC;IACD,IAAI,gBAAgB,KAAK,cAAc,IAAI,gBAAgB,KAAK,eAAe,EAAE,CAAC;QACjF,OAAO,uCAAuC,CAAC;IAChD,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAOD,SAAS,6BAA6B,CAAC,KAAc,EAAE,QAAgC,EAAQ;IAC9F,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO;IACxE,MAAM,KAAK,GAAG,KAAgC,CAAC;IAC/C,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACzD,QAAQ,CAAC,IAAI,CAAC;YACb,WAAW,EACV,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE;gBAChE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE;gBAC1B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE;YACrB,WAAW,EAAE,KAAK,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM;SACrE,CAAC,CAAC;QACH,OAAO;IACR,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAU,EAAE,CAAC;QAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,KAAK,MAAM,KAAK,IAAI,QAAQ;gBAAE,6BAA6B,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC9E,CAAC;aAAM,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YAC/B,6BAA6B,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACnD,CAAC;IACF,CAAC;AAAA,CACD;AAED,SAAS,yBAAyB,CAAC,KAA8B,EAA0B;IAC1F,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,6BAA6B,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC;AAAA,CAChB;AAYD,SAAS,aAAa,CAAC,KAAc,EAAU;IAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;IAC5E,OAAO,EAAE,CAAC;AAAA,CACV;AAED,2FAA2F;AAC3F,SAAS,sBAAsB,CAC9B,KAA8B,EAC9B,gBAAkD,EACzC;IACT,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAE,IAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtG,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAC;QACvB,CAAC;IACF,CAAC;IACD,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IACpB,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC;QACrD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;YAAE,SAAS;QACrE,MAAM,IAAI,GACT,KAAK,CAAC,SAAS,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;YACxF,CAAC,CAAE,KAAK,CAAC,SAAqC;YAC9C,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACvC,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACvB,CAAC;IACD,OAAO,EAAE,CAAC;AAAA,CACV;AAED;;;;;;GAMG;AACH,KAAK,UAAU,uBAAuB,CACrC,KAA8B,EAC9B,GAAsB,EACtB,OAAqB,EACkC;IACvD,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,OAAO,EAAE,4BAA4B,KAAK,KAAK;QAAE,OAAO,SAAS,CAAC;IACtE,MAAM,KAAK,GAAG,wCAAwC,CAAC,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;IACzF,IAAI,KAAK,IAAI,+BAA+B;QAAE,OAAO,SAAS,CAAC;IAC/D,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,4BAA4B,CAAC;QAAE,OAAO,SAAS,CAAC;IAEtE,MAAM,OAAO,GAAG,OAAO,EAAE,gBAAgB,CAAC;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,IAAI,MAAM,EAAE,CAAC;QACZ,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO;gBACN,KAAK,EAAE,IAAI;gBACX,MAAM,EAAE,MAAM,CAAC,QAAQ;oBACtB,CAAC,CAAC,GAAG,mCAAmC,IAAI,MAAM,CAAC,QAAQ,EAAE;oBAC7D,CAAC,CAAC,mCAAmC;aACtC,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,eAAe,EAAE,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,uCAAuC,EAAE,CAAC;IACzE,CAAC;IAED,MAAM,OAAO,GAAG,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;IACzE,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACrF,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,EAAE,CAAC;QACtE,MAAM,IAAI,GACT,KAAK,CAAC,SAAS,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;YACxF,CAAC,CAAE,KAAK,CAAC,SAAqC;YAC9C,CAAC,CAAC,SAAS,CAAC;QACd,OAAO,IAAI,CAAC,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAAA,CACnD,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACjG,MAAM,aAAa,GAAG,QAAQ;SAC5B,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,WAAW,kBAAkB,MAAM,CAAC,WAAW,EAAE,CAAC;SAC5E,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,IAAI,IAAsB,CAAC;IAC3B,IAAI,CAAC;QACJ,IAAI,GAAG,MAAM,eAAe,CAAC;YAC5B,QAAQ,EAAE,UAAU;YACpB,MAAM,EAAE,4BAA4B;YACpC,MAAM,EAAE,0BAA0B,KAAK,aAAa,aAAa,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,aAAa,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;YACrH,IAAI,EAAE,uBAAuB;SAC7B,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,uCAAuC,CAAC;QAC7F,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IACpE,MAAM,QAAQ,GAAqB,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;IACpF,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC9E,IAAI,OAAO,EAAE,CAAC;QACb,wBAAwB,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAChD,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO;YACN,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,mCAAmC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,mCAAmC;SAC7G,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,cAAc,CAAC,KAAc,EAAU;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAAA,CAC3D;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,QAAgB,EAChB,KAA8B,EAC9B,GAAW,EACX,SAAkB,EAClB,OAAqB,EACkC;IACvD,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,oBAAoB,GAAG,wBAAwB,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAC5E,IAAI,oBAAoB,EAAE,CAAC;QAC1B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IACtD,CAAC;IACD,IAAI,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAEpD,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,uBAAuB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACxD,IAAI,MAAM;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC3C,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;YACxB,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa,CAAC,EAAE,CAAC;gBACrF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,wEAAwE,EAAE,CAAC;YAC1G,CAAC;YACD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YAC5B,IACC,yBAAyB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,KAAK,MAAM,CAAC;gBAC9E,MAAM,KAAK,QAAQ;gBACnB,MAAM,KAAK,OAAO;gBAClB,MAAM,KAAK,aAAa;gBACxB,MAAM,KAAK,UAAU;gBACrB,MAAM,KAAK,iBAAiB,EAC3B,CAAC;gBACF,OAAO;oBACN,KAAK,EAAE,IAAI;oBACX,MAAM,EAAE,+EAA+E;iBACvF,CAAC;YACH,CAAC;YACD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,cAAc;YAAE,OAAO,SAAS,CAAC;QACnG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,qCAAqC,QAAQ,WAAW,EAAE,CAAC;IAC1F,CAAC;IACD,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,MAAM,uBAAuB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QACxE,IAAI,YAAY;YAAE,OAAO,YAAY,CAAC;IACvC,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB","sourcesContent":["/**\n * lunR: permission modes (YOLO / Auto / Read-only).\n *\n * Per-session only, with a configurable default for new sessions.\n *\n * - yolo: auto-approve tools; the agent may still ask questions.\n * - auto: fully autonomous; a system-prompt addendum steers the model to\n * self-decide, and rollback is force-enabled for the session.\n * - read-only: mutating tools are hard-blocked.\n *\n * The gate is wired into `agent-session.ts` `_installAgentToolHooks` before\n * the synchronous `_toolCallGates` loop. beforeToolCall is already async, so\n * awaiting the approval dialog is fine.\n *\n * State (mode + session-scoped approvals) is keyed by session id so\n * concurrent gateway chats do not share permission decisions.\n */\n\nimport { dirname, join, resolve } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport { effectiveLargeSubagentLaunchCountForTurn, LARGE_SUBAGENT_LAUNCH_THRESHOLD } from \"./large-subagent-launch.ts\";\nimport { isUserInstructionsPath } from \"./model-instructions.ts\";\nimport { readOnlyModeBlockReason } from \"./plan-mode.ts\";\n\n/** Shift+Tab cycle order. */\nexport const PERMISSION_MODES = [\"yolo\", \"auto\", \"read-only\"] as const;\nexport type PermissionMode = (typeof PERMISSION_MODES)[number];\n\nexport function nextPermissionMode(current: PermissionMode): PermissionMode {\n\tconst i = PERMISSION_MODES.indexOf(current);\n\treturn PERMISSION_MODES[(i + 1) % PERMISSION_MODES.length];\n}\n\n/** True when the session is read-only. */\nexport function isReadOnlyModeActive(sessionId?: string): boolean {\n\treturn getPermissionMode(sessionId) === \"read-only\";\n}\n\n/**\n * Destination mode when leaving a read-only planning session.\n * Explicit Shift+Tab or `/mode` picks do not use this.\n */\nexport function restorePermissionModeAfterPlan(\n\tprevious: PermissionMode | undefined,\n\tdefaultMode: PermissionMode,\n): PermissionMode {\n\tif (previous && previous !== \"read-only\") return previous;\n\treturn defaultMode;\n}\n\nexport interface ApprovalRequest {\n\ttoolName: string;\n\t/** \"large-subagent-launch\" or \"plan\" approval. */\n\taction: string;\n\tdetail: string;\n\t/** \"large-subagent-launch\" for aggregate child confirmation, \"plan\" for the\n\t * present_plan plan-approval prompt — the UI renders a dedicated dialog\n\t * for each instead of the generic tool dialog. */\n\tkind?: \"large-subagent-launch\" | \"plan\";\n}\n\nexport type ApprovalDecision = \"once\" | \"session\" | \"reject\";\n/** Handlers may return a bare decision string, a reject carrying user feedback\n * that becomes the block reason the model sees, or an approve carrying optional\n * feedback (plan approval with comments). */\nexport type ApprovalResponse =\n\t| ApprovalDecision\n\t| { decision: \"reject\"; feedback: string }\n\t| { decision: \"approve\"; feedback?: string };\n\n/** Read-only tools that never need approval. */\nconst READ_ONLY_TOOLS = new Set([\n\t\"read\",\n\t\"grep\",\n\t\"find\",\n\t\"ls\",\n\t\"web_search\",\n\t\"web_fetch\",\n\t\"fetch_content\",\n\t\"get_search_content\",\n\t\"sourcegraph\",\n\t\"repo_map\",\n\t\"symbol_outline\",\n\t\"read_block\",\n\t\"code_overview\",\n\t\"ast_search\",\n\t\"lsp_diagnostics\",\n\t\"lsp_hover\",\n\t\"lsp_definition\",\n\t\"lsp_references\",\n\t\"lsp_symbols\",\n\t\"lsp_code_actions\",\n\t\"lsp_completions\",\n\t\"lsp_rename\",\n\t\"memory_load\",\n\t\"subagent_wait\",\n\t\"subagent_supervisor\",\n\t\"intercom\",\n\t\"contact_supervisor\",\n\t\"present_plan\",\n\t\"structured_output\",\n]);\n\nexport const NO_HANDLER_REASON = \"Approval channel unavailable.\";\nexport const LARGE_SUBAGENT_LAUNCH_REJECT_REASON = \"Large subagent launch rejected by user.\";\nexport const NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON = \"Large subagent launch blocked: no approval channel available.\";\nconst LARGE_SUBAGENT_LAUNCH_ACTION = \"large-subagent-launch\";\n\ninterface PermissionContext {\n\tmode: PermissionMode;\n\tapprovals: Set<string>;\n}\n\nconst contexts = new Map<string, PermissionContext>();\nlet defaultContext: PermissionContext = { mode: \"yolo\", approvals: new Set() };\nlet approvalHandler: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined;\n/** One aggregate prompt covers every sibling SINGLE `subagent` on the same assistant message. */\nconst turnLargeLaunchDecisions = new WeakMap<object, { decision: ApprovalDecision; feedback?: string }>();\n\nfunction getContext(sessionId?: string): PermissionContext {\n\tif (!sessionId) return defaultContext;\n\treturn contexts.get(sessionId) ?? defaultContext;\n}\n\nexport function createPermissionContext(sessionId: string, mode: PermissionMode = defaultContext.mode): void {\n\tcontexts.set(sessionId, { mode, approvals: new Set() });\n}\n\nexport function deletePermissionContext(sessionId: string): void {\n\tcontexts.delete(sessionId);\n}\n\nexport function getPermissionMode(sessionId?: string): PermissionMode {\n\treturn getContext(sessionId).mode;\n}\n\nexport function setPermissionMode(mode: PermissionMode, sessionId?: string): void {\n\tgetContext(sessionId).mode = mode;\n}\n\nexport function resetPermissions(defaultMode: PermissionMode = \"yolo\", sessionId?: string): void {\n\tif (sessionId) {\n\t\tcontexts.set(sessionId, { mode: defaultMode, approvals: new Set() });\n\t} else {\n\t\tdefaultContext = { mode: defaultMode, approvals: new Set() };\n\t}\n}\n\nexport function registerApprovalHandler(fn: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined): void {\n\tapprovalHandler = fn;\n}\n\n/** Model-facing result texts for the present_plan tool. */\nexport const PLAN_APPROVED_TEXT = \"Plan approved — implement it now.\";\nexport const PLAN_DECLINED_TEXT = \"Plan declined — revise the plan and call present_plan again.\";\nexport const PLAN_PASS_THROUGH_TEXT = \"Plan presented. The user will review and reply.\";\n\n/** lunr: map an approval response to the model-facing present_plan result text. */\nexport function planApprovalResultText(resp: ApprovalResponse): string {\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (decision === \"reject\") {\n\t\treturn feedback\n\t\t\t? `Plan declined: ${feedback} — revise the plan and call present_plan again.`\n\t\t\t: PLAN_DECLINED_TEXT;\n\t}\n\treturn feedback ? `Plan approved with feedback: ${feedback} — implement it now.` : PLAN_APPROVED_TEXT;\n}\n\n/**\n * lunr: present_plan approval request. Unlike the aggregate launch gate\n * this fails OPEN when no approval handler is registered (or none is reachable,\n * e.g. a gateway turn without a chat context): headless sessions have no one to\n * show the dialog to, so the plan is presented and the user replies in chat\n * instead of deadlocking the turn. Everything else keeps fail-closed.\n */\nexport async function requestPlanApproval(summary: string): Promise<string> {\n\tif (!approvalHandler) return PLAN_PASS_THROUGH_TEXT;\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({ toolName: \"present_plan\", action: \"plan\", detail: summary, kind: \"plan\" });\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"approval request failed\";\n\t\tif (message === NO_HANDLER_REASON) return PLAN_PASS_THROUGH_TEXT;\n\t\treturn `Plan declined: ${message} — revise the plan and call present_plan again.`;\n\t}\n\treturn planApprovalResultText(resp);\n}\n\nexport function clearSessionApprovals(sessionId?: string): void {\n\tgetContext(sessionId).approvals.clear();\n}\n\n/** Test seam: remove every per-session context and restore the default. */\nexport function resetAllPermissionContexts(): void {\n\tcontexts.clear();\n\tdefaultContext = { mode: \"yolo\", approvals: new Set() };\n\tapprovalHandler = undefined;\n}\n\n/** Appended to the system prompt while auto mode is active. */\nexport const AUTO_MODE_ADDENDUM =\n\t\"You are running fully autonomously. Do not ask the user questions or wait for confirmation; make reasonable decisions and complete the task end-to-end.\";\n\nfunction resolvePath(cwd: string, p: unknown): string {\n\tif (typeof p !== \"string\") return \"\";\n\tif (!p) return \"\";\n\treturn resolve(cwd, p);\n}\n\nexport const GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON =\n\t\"The agents instruction tree is user-managed. The agent cannot change ~/.lunr/agent/agents/.\";\nexport const MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"Memory is model-managed through the memory tools. Do not directly change ~/.lunr/simple-memory/memory.md.\";\nexport const SETTINGS_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"lunR settings are user-managed through /settings. Do not directly change settings.json.\";\n\nfunction protectedFileWriteReason(toolName: string, input: Record<string, unknown>, cwd: string): string | undefined {\n\tif (toolName !== \"edit\" && toolName !== \"write\" && toolName !== \"code_rewrite\") return undefined;\n\tconst target = resolvePath(cwd, input.path);\n\tif (!target) return undefined;\n\tconst normalize = (path: string) => {\n\t\tconst normalized = resolve(path).replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n\t\treturn process.platform === \"win32\" ? normalized.toLowerCase() : normalized;\n\t};\n\tif (isUserInstructionsPath(target, getAgentDir())) {\n\t\treturn GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON;\n\t}\n\tif (normalize(target) === normalize(join(dirname(getAgentDir()), \"simple-memory\", \"memory.md\"))) {\n\t\treturn MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\tconst globalSettings = normalize(join(getAgentDir(), \"settings.json\"));\n\tconst projectSettings = normalize(join(cwd, CONFIG_DIR_NAME, \"settings.json\"));\n\tconst normalizedTarget = normalize(target);\n\tif (normalizedTarget === normalize(join(getAgentDir(), \"install-features.json\"))) {\n\t\treturn \"Optional features are user-managed through lunr features; Browser is managed in /settings. Do not change install-features.json directly.\";\n\t}\n\tif (normalizedTarget === globalSettings || normalizedTarget === projectSettings) {\n\t\treturn SETTINGS_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\treturn undefined;\n}\n\ninterface RequestedChildLaunch {\n\tdescription: string;\n\tpermissions: \"full\" | \"read-only\";\n}\n\nfunction collectRequestedChildLaunches(value: unknown, launches: RequestedChildLaunch[]): void {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return;\n\tconst input = value as Record<string, unknown>;\n\tif (typeof input.task === \"string\" && input.task.trim()) {\n\t\tlaunches.push({\n\t\t\tdescription:\n\t\t\t\ttypeof input.description === \"string\" && input.description.trim()\n\t\t\t\t\t? input.description.trim()\n\t\t\t\t\t: input.task.trim(),\n\t\t\tpermissions: input.permissions === \"read-only\" ? \"read-only\" : \"full\",\n\t\t});\n\t\treturn;\n\t}\n\tfor (const key of [\"tasks\", \"chain\", \"parallel\"] as const) {\n\t\tconst children = input[key];\n\t\tif (Array.isArray(children)) {\n\t\t\tfor (const child of children) collectRequestedChildLaunches(child, launches);\n\t\t} else if (key === \"parallel\") {\n\t\t\tcollectRequestedChildLaunches(children, launches);\n\t\t}\n\t}\n}\n\nfunction getRequestedChildLaunches(input: Record<string, unknown>): RequestedChildLaunch[] {\n\tconst launches: RequestedChildLaunch[] = [];\n\tcollectRequestedChildLaunches(input, launches);\n\treturn launches;\n}\n\nexport interface GateOptions {\n\t/** Global preference for aggregate confirmation. Defaults to enabled. */\n\tconfirmLargeSubagentLaunches?: boolean;\n\t/** Assistant message that issued this tool call. Same-turn sibling SINGLE\n\t * `subagent` calls count toward the aggregate threshold. */\n\tassistantMessage?: {\n\t\tcontent?: ReadonlyArray<{ type?: string; name?: string; arguments?: unknown }>;\n\t};\n}\n\nfunction firstTaskText(value: unknown): string {\n\tif (typeof value === \"string\" && value.trim()) return sanitizeDetail(value);\n\treturn \"\";\n}\n\n/** First task text of a parallel fan-out or sibling SINGLE, used as the dialog summary. */\nfunction largeLaunchTaskSummary(\n\tinput: Record<string, unknown>,\n\tassistantMessage?: GateOptions[\"assistantMessage\"],\n): string {\n\tif (Array.isArray(input.tasks)) {\n\t\tfor (const task of input.tasks) {\n\t\t\tconst text = task && typeof task === \"object\" ? firstTaskText((task as { task?: unknown }).task) : \"\";\n\t\t\tif (text) return text;\n\t\t}\n\t}\n\tconst own = firstTaskText(input.task);\n\tif (own) return own;\n\tfor (const block of assistantMessage?.content ?? []) {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") continue;\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\tconst text = firstTaskText(args?.task);\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n/**\n * Aggregate launch gate. A launch above LARGE_SUBAGENT_LAUNCH_THRESHOLD\n * parallel subagents in one `tasks`/`chain.parallel` call, or that many same-turn\n * SINGLE `subagent` calls) requires user approval in yolo mode; auto\n * mode runs it unconditionally.\n * Fail-closed without an approval handler.\n */\nasync function gateLargeSubagentLaunch(\n\tinput: Record<string, unknown>,\n\tctx: PermissionContext,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tif (ctx.mode === \"auto\") return undefined;\n\tif (options?.confirmLargeSubagentLaunches === false) return undefined;\n\tconst count = effectiveLargeSubagentLaunchCountForTurn(input, options?.assistantMessage);\n\tif (count <= LARGE_SUBAGENT_LAUNCH_THRESHOLD) return undefined;\n\tif (ctx.approvals.has(LARGE_SUBAGENT_LAUNCH_ACTION)) return undefined;\n\n\tconst turnKey = options?.assistantMessage;\n\tconst cached = turnKey ? turnLargeLaunchDecisions.get(turnKey) : undefined;\n\tif (cached) {\n\t\tif (cached.decision === \"reject\") {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: cached.feedback\n\t\t\t\t\t? `${LARGE_SUBAGENT_LAUNCH_REJECT_REASON} ${cached.feedback}`\n\t\t\t\t\t: LARGE_SUBAGENT_LAUNCH_REJECT_REASON,\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tif (!approvalHandler) {\n\t\treturn { block: true, reason: NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON };\n\t}\n\n\tconst summary = largeLaunchTaskSummary(input, options?.assistantMessage);\n\tconst siblingLaunches = (options?.assistantMessage?.content ?? []).flatMap((block) => {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") return [];\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\treturn args ? getRequestedChildLaunches(args) : [];\n\t});\n\tconst launches = siblingLaunches.length > 0 ? siblingLaunches : getRequestedChildLaunches(input);\n\tconst launchSummary = launches\n\t\t.map((launch) => `${launch.description}\\npermissions: ${launch.permissions}`)\n\t\t.join(\"\\n\");\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({\n\t\t\ttoolName: \"subagent\",\n\t\t\taction: LARGE_SUBAGENT_LAUNCH_ACTION,\n\t\t\tdetail: `large subagent launch (${count} children)${launchSummary || summary ? `\\n${launchSummary || summary}` : \"\"}`,\n\t\t\tkind: \"large-subagent-launch\",\n\t\t});\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON;\n\t\treturn { block: true, reason: message };\n\t}\n\n\tconst rawDecision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst decision: ApprovalDecision = rawDecision === \"approve\" ? \"once\" : rawDecision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (turnKey) {\n\t\tturnLargeLaunchDecisions.set(turnKey, { decision, ...(feedback ? { feedback } : {}) });\n\t}\n\tif (decision === \"session\") {\n\t\tctx.approvals.add(LARGE_SUBAGENT_LAUNCH_ACTION);\n\t\treturn undefined;\n\t}\n\tif (decision === \"reject\") {\n\t\treturn {\n\t\t\tblock: true,\n\t\t\treason: feedback ? `${LARGE_SUBAGENT_LAUNCH_REJECT_REASON} ${feedback}` : LARGE_SUBAGENT_LAUNCH_REJECT_REASON,\n\t\t};\n\t}\n\treturn undefined;\n}\n\nfunction sanitizeDetail(value: unknown): string {\n\tconst text = String(value ?? \"\").trim();\n\treturn text.length > 200 ? `${text.slice(0, 200)}…` : text;\n}\n\n/**\n * Returns a block result when the tool call should be blocked, else undefined.\n * Read-only tools always pass. YOLO and Auto pass mutating tools. Read-only\n * mode hard-blocks mutating tools without prompting.\n */\nexport async function gateToolCall(\n\ttoolName: string,\n\tinput: Record<string, unknown>,\n\tcwd: string,\n\tsessionId?: string,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tconst ctx = getContext(sessionId);\n\tconst protectedWriteReason = protectedFileWriteReason(toolName, input, cwd);\n\tif (protectedWriteReason) {\n\t\treturn { block: true, reason: protectedWriteReason };\n\t}\n\tif (READ_ONLY_TOOLS.has(toolName)) return undefined;\n\n\tif (ctx.mode === \"read-only\") {\n\t\tconst reason = readOnlyModeBlockReason(toolName, input);\n\t\tif (reason) return { block: true, reason };\n\t\tif (toolName === \"mcp\") {\n\t\t\tif (input.tool || input.connect || (input.action && input.action !== \"ui-messages\")) {\n\t\t\t\treturn { block: true, reason: \"Read-only mode blocks MCP tool calls, connections, and authentication.\" };\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tif (toolName === \"subagent\") {\n\t\t\tconst action = input.action;\n\t\t\tif (\n\t\t\t\tgetRequestedChildLaunches(input).some((child) => child.permissions === \"full\") ||\n\t\t\t\taction === \"resume\" ||\n\t\t\t\taction === \"steer\" ||\n\t\t\t\taction === \"append-step\" ||\n\t\t\t\taction === \"schedule\" ||\n\t\t\t\taction === \"schedule-cancel\"\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\treason: \"Read-only mode cannot launch full-access children or change running children.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tif (toolName === \"bash\" || toolName === \"browser\" || toolName === \"code_rewrite\") return undefined;\n\t\treturn { block: true, reason: `Read-only mode cannot verify that ${toolName} is safe.` };\n\t}\n\tif (toolName === \"subagent\") {\n\t\tconst launchResult = await gateLargeSubagentLaunch(input, ctx, options);\n\t\tif (launchResult) return launchResult;\n\t}\n\treturn undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunR: permission modes (YOLO / Auto / Read-only).\n *\n * Per-session only, with a configurable default for new sessions.\n *\n * - yolo: auto-approve tools; the agent may still ask questions.\n * - auto: fully autonomous; a system-prompt addendum steers the model to\n * self-decide, and rollback is force-enabled for the session.\n * - read-only: mutating tools are hard-blocked.\n *\n * The gate is wired into `agent-session.ts` `_installAgentToolHooks` before\n * the synchronous `_toolCallGates` loop. beforeToolCall is already async, so\n * awaiting the approval dialog is fine.\n *\n * State (mode + session-scoped approvals) is keyed by session id so\n * concurrent gateway chats do not share permission decisions.\n */\n\nimport { dirname, join, resolve } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport { computerPolicy } from \"./computer-use/policy.ts\";\nimport { effectiveLargeSubagentLaunchCountForTurn, LARGE_SUBAGENT_LAUNCH_THRESHOLD } from \"./large-subagent-launch.ts\";\nimport { isUserInstructionsPath } from \"./model-instructions.ts\";\nimport { readOnlyModeBlockReason } from \"./plan-mode.ts\";\n\n/** Shift+Tab cycle order. */\nexport const PERMISSION_MODES = [\"yolo\", \"auto\", \"read-only\"] as const;\nexport type PermissionMode = (typeof PERMISSION_MODES)[number];\n\nexport function nextPermissionMode(current: PermissionMode): PermissionMode {\n\tconst i = PERMISSION_MODES.indexOf(current);\n\treturn PERMISSION_MODES[(i + 1) % PERMISSION_MODES.length];\n}\n\n/** True when the session is read-only. */\nexport function isReadOnlyModeActive(sessionId?: string): boolean {\n\treturn getPermissionMode(sessionId) === \"read-only\";\n}\n\n/**\n * Destination mode when leaving a read-only planning session.\n * Explicit Shift+Tab or `/mode` picks do not use this.\n */\nexport function restorePermissionModeAfterPlan(\n\tprevious: PermissionMode | undefined,\n\tdefaultMode: PermissionMode,\n): PermissionMode {\n\tif (previous && previous !== \"read-only\") return previous;\n\treturn defaultMode;\n}\n\nexport interface ApprovalRequest {\n\ttoolName: string;\n\t/** \"large-subagent-launch\" or \"plan\" approval. */\n\taction: string;\n\tdetail: string;\n\t/** \"large-subagent-launch\" for aggregate child confirmation, \"plan\" for the\n\t * present_plan plan-approval prompt — the UI renders a dedicated dialog\n\t * for each instead of the generic tool dialog. */\n\tkind?: \"large-subagent-launch\" | \"plan\";\n}\n\nexport type ApprovalDecision = \"once\" | \"session\" | \"reject\";\n/** Handlers may return a bare decision string, a reject carrying user feedback\n * that becomes the block reason the model sees, or an approve carrying optional\n * feedback (plan approval with comments). */\nexport type ApprovalResponse =\n\t| ApprovalDecision\n\t| { decision: \"reject\"; feedback: string }\n\t| { decision: \"approve\"; feedback?: string };\n\n/** Read-only tools that never need approval. */\nconst READ_ONLY_TOOLS = new Set([\n\t\"read\",\n\t\"grep\",\n\t\"find\",\n\t\"ls\",\n\t\"web_search\",\n\t\"web_fetch\",\n\t\"fetch_content\",\n\t\"get_search_content\",\n\t\"sourcegraph\",\n\t\"repo_map\",\n\t\"symbol_outline\",\n\t\"read_block\",\n\t\"code_overview\",\n\t\"ast_search\",\n\t\"lsp_diagnostics\",\n\t\"lsp_hover\",\n\t\"lsp_definition\",\n\t\"lsp_references\",\n\t\"lsp_symbols\",\n\t\"lsp_code_actions\",\n\t\"lsp_completions\",\n\t\"lsp_rename\",\n\t\"memory_load\",\n\t\"subagent_wait\",\n\t\"subagent_supervisor\",\n\t\"intercom\",\n\t\"contact_supervisor\",\n\t\"present_plan\",\n\t\"structured_output\",\n]);\n\nexport const NO_HANDLER_REASON = \"Approval channel unavailable.\";\nexport const LARGE_SUBAGENT_LAUNCH_REJECT_REASON = \"Large subagent launch rejected by user.\";\nexport const NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON = \"Large subagent launch blocked: no approval channel available.\";\nconst LARGE_SUBAGENT_LAUNCH_ACTION = \"large-subagent-launch\";\n\ninterface PermissionContext {\n\tallowApprovals?: boolean;\n\tmode: PermissionMode;\n\tapprovals: Set<string>;\n}\n\nconst contexts = new Map<string, PermissionContext>();\nlet defaultContext: PermissionContext = { mode: \"yolo\", approvals: new Set() };\nlet approvalHandler: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined;\n/** One aggregate prompt covers every sibling SINGLE `subagent` on the same assistant message. */\nconst turnLargeLaunchDecisions = new WeakMap<object, { decision: ApprovalDecision; feedback?: string }>();\n\nfunction getContext(sessionId?: string): PermissionContext {\n\tif (!sessionId) return defaultContext;\n\treturn contexts.get(sessionId) ?? defaultContext;\n}\n\nexport function createPermissionContext(\n\tsessionId: string,\n\tmode: PermissionMode = defaultContext.mode,\n\tallowApprovals = true,\n): void {\n\tcontexts.set(sessionId, { mode, allowApprovals, approvals: new Set() });\n}\n\nexport function deletePermissionContext(sessionId: string): void {\n\tcontexts.delete(sessionId);\n}\n\nexport function getPermissionMode(sessionId?: string): PermissionMode {\n\treturn getContext(sessionId).mode;\n}\n\nexport function setPermissionMode(mode: PermissionMode, sessionId?: string): void {\n\tgetContext(sessionId).mode = mode;\n}\n\nexport function resetPermissions(defaultMode: PermissionMode = \"yolo\", sessionId?: string): void {\n\tif (sessionId) {\n\t\tcontexts.set(sessionId, { mode: defaultMode, approvals: new Set() });\n\t} else {\n\t\tdefaultContext = { mode: defaultMode, approvals: new Set() };\n\t}\n}\n\nexport function registerApprovalHandler(fn: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined): void {\n\tapprovalHandler = fn;\n}\n\n/** Model-facing result texts for the present_plan tool. */\nexport const PLAN_APPROVED_TEXT = \"Plan approved — implement it now.\";\nexport const PLAN_DECLINED_TEXT = \"Plan declined — revise the plan and call present_plan again.\";\nexport const PLAN_PASS_THROUGH_TEXT = \"Plan presented. The user will review and reply.\";\n\n/** lunr: map an approval response to the model-facing present_plan result text. */\nexport function planApprovalResultText(resp: ApprovalResponse): string {\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (decision === \"reject\") {\n\t\treturn feedback\n\t\t\t? `Plan declined: ${feedback} — revise the plan and call present_plan again.`\n\t\t\t: PLAN_DECLINED_TEXT;\n\t}\n\treturn feedback ? `Plan approved with feedback: ${feedback} — implement it now.` : PLAN_APPROVED_TEXT;\n}\n\n/**\n * lunr: present_plan approval request. Unlike the aggregate launch gate\n * this fails OPEN when no approval handler is registered (or none is reachable,\n * e.g. a gateway turn without a chat context): headless sessions have no one to\n * show the dialog to, so the plan is presented and the user replies in chat\n * instead of deadlocking the turn. Everything else keeps fail-closed.\n */\nexport async function requestPlanApproval(summary: string): Promise<string> {\n\tif (!approvalHandler) return PLAN_PASS_THROUGH_TEXT;\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({ toolName: \"present_plan\", action: \"plan\", detail: summary, kind: \"plan\" });\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"approval request failed\";\n\t\tif (message === NO_HANDLER_REASON) return PLAN_PASS_THROUGH_TEXT;\n\t\treturn `Plan declined: ${message} — revise the plan and call present_plan again.`;\n\t}\n\treturn planApprovalResultText(resp);\n}\n\nexport function clearSessionApprovals(sessionId?: string): void {\n\tgetContext(sessionId).approvals.clear();\n}\n\n/** Test seam: remove every per-session context and restore the default. */\nexport function resetAllPermissionContexts(): void {\n\tcontexts.clear();\n\tdefaultContext = { mode: \"yolo\", approvals: new Set() };\n\tapprovalHandler = undefined;\n}\n\n/** Appended to the system prompt while auto mode is active. */\nexport const AUTO_MODE_ADDENDUM =\n\t\"You are running fully autonomously. Do not ask the user questions or wait for confirmation; make reasonable decisions and complete the task end-to-end.\";\n\nfunction resolvePath(cwd: string, p: unknown): string {\n\tif (typeof p !== \"string\") return \"\";\n\tif (!p) return \"\";\n\treturn resolve(cwd, p);\n}\n\nexport const GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON =\n\t\"The agents instruction tree is user-managed. The agent cannot change ~/.lunr/agent/agents/.\";\nexport const MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"Memory is model-managed through the memory tools. Do not directly change ~/.lunr/simple-memory/memory.md.\";\nexport const SETTINGS_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"lunR settings are user-managed through /settings. Do not directly change settings.json.\";\n\nfunction protectedFileWriteReason(toolName: string, input: Record<string, unknown>, cwd: string): string | undefined {\n\tif (toolName !== \"edit\" && toolName !== \"write\" && toolName !== \"code_rewrite\") return undefined;\n\tconst target = resolvePath(cwd, input.path);\n\tif (!target) return undefined;\n\tconst normalize = (path: string) => {\n\t\tconst normalized = resolve(path).replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n\t\treturn process.platform === \"win32\" ? normalized.toLowerCase() : normalized;\n\t};\n\tif (isUserInstructionsPath(target, getAgentDir())) {\n\t\treturn GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON;\n\t}\n\tif (normalize(target) === normalize(join(dirname(getAgentDir()), \"simple-memory\", \"memory.md\"))) {\n\t\treturn MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\tconst globalSettings = normalize(join(getAgentDir(), \"settings.json\"));\n\tconst projectSettings = normalize(join(cwd, CONFIG_DIR_NAME, \"settings.json\"));\n\tconst normalizedTarget = normalize(target);\n\tif (normalizedTarget === normalize(join(getAgentDir(), \"install-features.json\"))) {\n\t\treturn \"Optional features are user-managed through lunr features; Browser is managed in /settings. Do not change install-features.json directly.\";\n\t}\n\tif (normalizedTarget === globalSettings || normalizedTarget === projectSettings) {\n\t\treturn SETTINGS_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\treturn undefined;\n}\n\ninterface RequestedChildLaunch {\n\tdescription: string;\n\tpermissions: \"full\" | \"read-only\";\n}\n\nfunction collectRequestedChildLaunches(value: unknown, launches: RequestedChildLaunch[]): void {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return;\n\tconst input = value as Record<string, unknown>;\n\tif (typeof input.task === \"string\" && input.task.trim()) {\n\t\tlaunches.push({\n\t\t\tdescription:\n\t\t\t\ttypeof input.description === \"string\" && input.description.trim()\n\t\t\t\t\t? input.description.trim()\n\t\t\t\t\t: input.task.trim(),\n\t\t\tpermissions: input.permissions === \"read-only\" ? \"read-only\" : \"full\",\n\t\t});\n\t\treturn;\n\t}\n\tfor (const key of [\"tasks\", \"chain\", \"parallel\"] as const) {\n\t\tconst children = input[key];\n\t\tif (Array.isArray(children)) {\n\t\t\tfor (const child of children) collectRequestedChildLaunches(child, launches);\n\t\t} else if (key === \"parallel\") {\n\t\t\tcollectRequestedChildLaunches(children, launches);\n\t\t}\n\t}\n}\n\nfunction getRequestedChildLaunches(input: Record<string, unknown>): RequestedChildLaunch[] {\n\tconst launches: RequestedChildLaunch[] = [];\n\tcollectRequestedChildLaunches(input, launches);\n\treturn launches;\n}\n\nexport interface GateOptions {\n\t/** Global preference for aggregate confirmation. Defaults to enabled. */\n\tconfirmLargeSubagentLaunches?: boolean;\n\t/** Assistant message that issued this tool call. Same-turn sibling SINGLE\n\t * `subagent` calls count toward the aggregate threshold. */\n\tassistantMessage?: {\n\t\tcontent?: ReadonlyArray<{ type?: string; name?: string; arguments?: unknown }>;\n\t};\n}\n\nfunction firstTaskText(value: unknown): string {\n\tif (typeof value === \"string\" && value.trim()) return sanitizeDetail(value);\n\treturn \"\";\n}\n\n/** First task text of a parallel fan-out or sibling SINGLE, used as the dialog summary. */\nfunction largeLaunchTaskSummary(\n\tinput: Record<string, unknown>,\n\tassistantMessage?: GateOptions[\"assistantMessage\"],\n): string {\n\tif (Array.isArray(input.tasks)) {\n\t\tfor (const task of input.tasks) {\n\t\t\tconst text = task && typeof task === \"object\" ? firstTaskText((task as { task?: unknown }).task) : \"\";\n\t\t\tif (text) return text;\n\t\t}\n\t}\n\tconst own = firstTaskText(input.task);\n\tif (own) return own;\n\tfor (const block of assistantMessage?.content ?? []) {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") continue;\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\tconst text = firstTaskText(args?.task);\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n/**\n * Aggregate launch gate. A launch above LARGE_SUBAGENT_LAUNCH_THRESHOLD\n * parallel subagents in one `tasks`/`chain.parallel` call, or that many same-turn\n * SINGLE `subagent` calls) requires user approval in yolo mode; auto\n * mode runs it unconditionally.\n * Fail-closed without an approval handler.\n */\nasync function gateLargeSubagentLaunch(\n\tinput: Record<string, unknown>,\n\tctx: PermissionContext,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tif (ctx.mode === \"auto\") return undefined;\n\tif (options?.confirmLargeSubagentLaunches === false) return undefined;\n\tconst count = effectiveLargeSubagentLaunchCountForTurn(input, options?.assistantMessage);\n\tif (count <= LARGE_SUBAGENT_LAUNCH_THRESHOLD) return undefined;\n\tif (ctx.approvals.has(LARGE_SUBAGENT_LAUNCH_ACTION)) return undefined;\n\n\tconst turnKey = options?.assistantMessage;\n\tconst cached = turnKey ? turnLargeLaunchDecisions.get(turnKey) : undefined;\n\tif (cached) {\n\t\tif (cached.decision === \"reject\") {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: cached.feedback\n\t\t\t\t\t? `${LARGE_SUBAGENT_LAUNCH_REJECT_REASON} ${cached.feedback}`\n\t\t\t\t\t: LARGE_SUBAGENT_LAUNCH_REJECT_REASON,\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tif (!approvalHandler || ctx.allowApprovals === false) {\n\t\treturn { block: true, reason: NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON };\n\t}\n\n\tconst summary = largeLaunchTaskSummary(input, options?.assistantMessage);\n\tconst siblingLaunches = (options?.assistantMessage?.content ?? []).flatMap((block) => {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") return [];\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\treturn args ? getRequestedChildLaunches(args) : [];\n\t});\n\tconst launches = siblingLaunches.length > 0 ? siblingLaunches : getRequestedChildLaunches(input);\n\tconst launchSummary = launches\n\t\t.map((launch) => `${launch.description}\\npermissions: ${launch.permissions}`)\n\t\t.join(\"\\n\");\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({\n\t\t\ttoolName: \"subagent\",\n\t\t\taction: LARGE_SUBAGENT_LAUNCH_ACTION,\n\t\t\tdetail: `large subagent launch (${count} children)${launchSummary || summary ? `\\n${launchSummary || summary}` : \"\"}`,\n\t\t\tkind: \"large-subagent-launch\",\n\t\t});\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : NO_LARGE_SUBAGENT_LAUNCH_HANDLER_REASON;\n\t\treturn { block: true, reason: message };\n\t}\n\n\tconst rawDecision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst decision: ApprovalDecision = rawDecision === \"approve\" ? \"once\" : rawDecision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (turnKey) {\n\t\tturnLargeLaunchDecisions.set(turnKey, { decision, ...(feedback ? { feedback } : {}) });\n\t}\n\tif (decision === \"session\") {\n\t\tctx.approvals.add(LARGE_SUBAGENT_LAUNCH_ACTION);\n\t\treturn undefined;\n\t}\n\tif (decision === \"reject\") {\n\t\treturn {\n\t\t\tblock: true,\n\t\t\treason: feedback ? `${LARGE_SUBAGENT_LAUNCH_REJECT_REASON} ${feedback}` : LARGE_SUBAGENT_LAUNCH_REJECT_REASON,\n\t\t};\n\t}\n\treturn undefined;\n}\n\nfunction sanitizeDetail(value: unknown): string {\n\tconst text = String(value ?? \"\").trim();\n\treturn text.length > 200 ? `${text.slice(0, 200)}…` : text;\n}\n\n/**\n * Returns a block result when the tool call should be blocked, else undefined.\n * Read-only tools always pass. YOLO and Auto pass mutating tools. Read-only\n * mode hard-blocks mutating tools without prompting.\n */\nexport async function gateToolCall(\n\ttoolName: string,\n\tinput: Record<string, unknown>,\n\tcwd: string,\n\tsessionId?: string,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tconst ctx = getContext(sessionId);\n\tif (toolName.startsWith(\"computer_\")) {\n\t\ttry {\n\t\t\tcomputerPolicy(toolName, input);\n\t\t} catch (error) {\n\t\t\treturn { block: true, reason: String(error) };\n\t\t}\n\t}\n\tconst protectedWriteReason = protectedFileWriteReason(toolName, input, cwd);\n\tif (protectedWriteReason) {\n\t\treturn { block: true, reason: protectedWriteReason };\n\t}\n\tif (READ_ONLY_TOOLS.has(toolName)) return undefined;\n\n\tif (ctx.mode === \"read-only\") {\n\t\tconst reason = readOnlyModeBlockReason(toolName, input);\n\t\tif (reason) return { block: true, reason };\n\t\tif (toolName === \"mcp\") {\n\t\t\tif (input.tool || input.connect || (input.action && input.action !== \"ui-messages\")) {\n\t\t\t\treturn { block: true, reason: \"Read-only mode blocks MCP tool calls, connections, and authentication.\" };\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tif (toolName === \"subagent\") {\n\t\t\tconst action = input.action;\n\t\t\tif (\n\t\t\t\tgetRequestedChildLaunches(input).some((child) => child.permissions === \"full\") ||\n\t\t\t\taction === \"resume\" ||\n\t\t\t\taction === \"steer\" ||\n\t\t\t\taction === \"append-step\" ||\n\t\t\t\taction === \"schedule\" ||\n\t\t\t\taction === \"schedule-cancel\"\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\treason: \"Read-only mode cannot launch full-access children or change running children.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tif (toolName.startsWith(\"computer_\")) return undefined;\n\t\tif (toolName === \"bash\" || toolName === \"browser\" || toolName === \"code_rewrite\") return undefined;\n\t\treturn { block: true, reason: `Read-only mode cannot verify that ${toolName} is safe.` };\n\t}\n\tif (toolName === \"subagent\") {\n\t\tconst launchResult = await gateLargeSubagentLaunch(input, ctx, options);\n\t\tif (launchResult) return launchResult;\n\t}\n\treturn undefined;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-mode.d.ts","sourceRoot":"","sources":["../../src/core/plan-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,yNACmL,CAAC;AAExN,eAAO,MAAM,4BAA4B,kDAAkD,CAAC;AAwI5F,yFAAyF;AACzF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAiB5F;AAOD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAe9D","sourcesContent":["/**\n * lunr: read-only tool-gating heuristics + system-prompt addendum.\n *\n * `gateToolCall` in permissions.ts applies `readOnlyModeBlockReason` in read-only mode:\n * `edit`/`write` and mutating `bash` are hard-blocked; read tools stay open.\n * InteractiveMode installs `READ_ONLY_MODE_ADDENDUM` via the shared system-prompt\n * append slot (same slot auto mode uses).\n *\n * Bash heuristic (conservative, blocklist-based — NOT a security boundary):\n * - any `>`/`>>` redirect outside quotes blocks the whole command;\n * - the command is split on `;`, `|`, `&` separators (outside quotes) and every segment's\n * leading command must be read-only:\n * - known mutating commands (rm, mv, cp, mkdir, sed -i, tee, …) are blocked;\n * - `git` is limited to read-only subcommands (status/log/diff/show/… plus flag-only\n * branch/tag/remote); mutating subcommands (add/commit/push/checkout/…) are blocked;\n * - package managers are limited to read-only subcommands (install/add/remove/… blocked);\n * - arbitrary runners (sudo, xargs, npx, sh -c …) are blocked.\n * Unknown-but-not-listed commands are ALLOWED (blocklist, not allowlist) — the model is\n * additionally steered by the system-prompt addendum. False positives are expected; the\n * user can run the command themselves or switch to another mode.\n */\n\n/** Appended to the system prompt while read-only mode is active. */\nexport const READ_ONLY_MODE_ADDENDUM =\n\t\"You are in read-only mode. Investigate and answer without making changes. If the user asks for a plan, you may call present_plan for approval. Do not implement until the user switches modes or approves that plan.\";\n\nexport const READ_ONLY_MODE_BLOCK_MESSAGE = \"Read-only mode is active; no changes allowed.\";\n\nconst BLOCKED_TOOLS = new Set([\"edit\", \"write\", \"memory_add\", \"memory_remove\", \"cron\"]);\n\n/** Small allowlist of read-only commands permitted in read-only mode. Everything else is rejected. */\nconst ALLOWED_COMMANDS = new Set([\n\t\"ls\",\n\t\"ll\",\n\t\"cat\",\n\t\"tac\",\n\t\"grep\",\n\t\"rg\",\n\t\"find\",\n\t\"pwd\",\n\t\"echo\",\n\t\"printf\",\n\t\"head\",\n\t\"tail\",\n\t\"wc\",\n\t\"less\",\n\t\"more\",\n\t\"sort\",\n\t\"uniq\",\n\t\"diff\",\n\t\"cmp\",\n\t\"comm\",\n\t\"test\",\n\t\"[\",\n\t\"true\",\n\t\"false\",\n\t\"which\",\n\t\"whereis\",\n\t\"stat\",\n\t\"file\",\n\t\"id\",\n\t\"whoami\",\n\t\"who\",\n\t\"date\",\n\t\"cal\",\n\t\"env\",\n\t\"printenv\",\n\t\"uname\",\n\t\"hostname\",\n\t\"uptime\",\n\t\"nproc\",\n\t\"tput\",\n\t\"git\",\n\t\"gh\",\n\t\"node\",\n\t\"npm\",\n\t\"pnpm\",\n\t\"yarn\",\n\t\"bun\",\n]);\n\nconst MUTATING_GIT_SUBCOMMANDS = new Set([\n\t\"add\",\n\t\"commit\",\n\t\"push\",\n\t\"pull\",\n\t\"merge\",\n\t\"rebase\",\n\t\"reset\",\n\t\"checkout\",\n\t\"switch\",\n\t\"restore\",\n\t\"rm\",\n\t\"mv\",\n\t\"stash\",\n\t\"cherry-pick\",\n\t\"revert\",\n\t\"clean\",\n\t\"fetch\",\n\t\"config\",\n\t\"apply\",\n\t\"am\",\n\t\"init\",\n\t\"clone\",\n\t\"submodule\",\n\t\"worktree\",\n\t\"gc\",\n\t\"prune\",\n\t\"update-index\",\n]);\n\n// git subcommands that are read-only only when they carry no positional args or\n// mutating flags (`git branch` lists, `git branch foo` / `git branch -d foo` mutate).\nconst CONDITIONAL_GIT_SUBCOMMANDS = new Set([\"branch\", \"tag\", \"remote\"]);\nconst CONDITIONAL_GIT_MUTATING_FLAGS = new Set([\"-d\", \"-D\", \"-m\", \"-M\", \"-c\", \"-C\"]);\n\nconst PACKAGE_MANAGER_MUTATIONS: Record<string, Set<string>> = {\n\tnpm: new Set([\n\t\t\"install\",\n\t\t\"add\",\n\t\t\"remove\",\n\t\t\"uninstall\",\n\t\t\"update\",\n\t\t\"upgrade\",\n\t\t\"publish\",\n\t\t\"link\",\n\t\t\"unlink\",\n\t\t\"ci\",\n\t\t\"init\",\n\t]),\n\tpnpm: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tyarn: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tbun: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n};\n\n// Almost every subcommand mutates the system.\nconst ALWAYS_MUTATING_MANAGERS = new Set([\n\t\"apt\",\n\t\"apt-get\",\n\t\"brew\",\n\t\"dnf\",\n\t\"yum\",\n\t\"pacman\",\n\t\"choco\",\n\t\"winget\",\n\t\"scoop\",\n]);\n\n/** Flags that cause an interpreter to execute code and are never allowed in read-only mode. */\nconst EXECUTING_NODE_FLAGS = new Set([\n\t\"-e\",\n\t\"--eval\",\n\t\"-p\",\n\t\"--print\",\n\t\"-r\",\n\t\"--require\",\n\t\"--import\",\n\t\"-i\",\n\t\"--interactive\",\n]);\nconst EXECUTING_PYTHON_FLAGS = new Set([\"-c\", \"-m\", \"-i\", \"--interactive\"]);\n\n/** Apply-mode rewrite only. Default / omitted `dry_run` is preview and stays allowed. */\nexport function isCodeRewriteMutating(input: unknown): boolean {\n\treturn (input as { dry_run?: unknown } | undefined)?.dry_run === false;\n}\n\n/**\n * Returns the block reason when read-only mode should block this tool call, else undefined.\n */\nexport function readOnlyModeBlockReason(toolName: string, input: unknown): string | undefined {\n\tif (toolName === \"browser\" && (input as { action?: unknown } | undefined)?.action === \"act\") {\n\t\treturn `${READ_ONLY_MODE_BLOCK_MESSAGE} Browser interactions require a writable mode; observation remains available.`;\n\t}\n\tif (BLOCKED_TOOLS.has(toolName)) {\n\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"code_rewrite\" && isCodeRewriteMutating(input)) {\n\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"bash\") {\n\t\tconst command = readBashCommand(input);\n\t\tif (command && isMutatingBashCommand(command)) {\n\t\t\treturn `${READ_ONLY_MODE_BLOCK_MESSAGE} Blocked command: ${command}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction readBashCommand(input: unknown): string {\n\tconst command = (input as { command?: unknown } | undefined)?.command;\n\treturn typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Read-only bash allowlist. A command is mutating unless every segment is a\n * known read-only command used safely (no redirects, no command substitution,\n * no process substitution, no executing-interpreter flags).\n */\nexport function isMutatingBashCommand(command: string): boolean {\n\tif (!command.trim()) return false;\n\n\t// Any output redirect outside quotes can write a file.\n\tif (hasUnquotedRedirect(command)) return true;\n\n\t// Command substitution / process substitution / grouped redirect syntaxes\n\t// bypass a simple command-name check.\n\tif (hasShellSubstitution(command)) return true;\n\n\t// Every segment separated by ; | & && || must individually be read-only.\n\tfor (const segment of splitShellSegments(command)) {\n\t\tif (isMutatingSegment(segment)) return true;\n\t}\n\treturn false;\n}\n\nfunction hasUnquotedRedirect(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction splitShellSegments(command: string): string[] {\n\tconst segments: string[] = [];\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tlet start = 0;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tconst next = command[i + 1];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\t// Combined operators && and || split as one boundary.\n\t\tif ((ch === \"&\" && next === \"&\") || (ch === \"|\" && next === \"|\")) {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\ti++;\n\t\t\tstart = i + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \";\" || ch === \"|\" || ch === \"&\" || ch === \"\\n\") {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\tsegments.push(command.slice(start));\n\treturn segments.map((s) => s.trim()).filter((s) => s.length > 0);\n}\n\n/** True when the command contains command/process substitution outside quotes. */\nfunction hasShellSubstitution(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"`\") return true;\n\t\tif (ch === \"$\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"<\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \">\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"&\" && command[i + 1] === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction isMutatingSegment(segment: string): boolean {\n\tlet tokens = segment.split(/\\s+/).filter((t) => t.length > 0);\n\t// Skip leading env assignments (FOO=bar cmd …) and command wrappers we can't see through.\n\twhile (tokens.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) {\n\t\ttokens = tokens.slice(1);\n\t}\n\tif (tokens.length === 0) return false;\n\n\tconst command = basenameOf(tokens[0]).toLowerCase();\n\tconst args = tokens.slice(1);\n\n\tif (ALWAYS_MUTATING_MANAGERS.has(command)) return true;\n\n\tif (command === \"sed\") {\n\t\treturn args.some((a) => a === \"-i\" || a.startsWith(\"-i\") || a.startsWith(\"--in-place\") || /^-[^-]*i/.test(a));\n\t}\n\tif (command === \"find\") {\n\t\treturn args.some((a) => [\"-delete\", \"-exec\", \"-execdir\", \"-ok\", \"-okdir\"].includes(a));\n\t}\n\tif (command === \"git\") {\n\t\treturn isMutatingGit(args);\n\t}\n\tif (command === \"gh\") {\n\t\t// Allow read-only views; block everything that changes remote state.\n\t\tconst sub = `${args[0] ?? \"\"} ${args[1] ?? \"\"}`;\n\t\treturn ![\n\t\t\t\"pr view\",\n\t\t\t\"pr list\",\n\t\t\t\"pr status\",\n\t\t\t\"issue view\",\n\t\t\t\"issue list\",\n\t\t\t\"issue status\",\n\t\t\t\"repo view\",\n\t\t\t\"release view\",\n\t\t\t\"release list\",\n\t\t\t\"run list\",\n\t\t\t\"run view\",\n\t\t\t\"status\",\n\t\t].includes(sub.trim());\n\t}\n\tif (command === \"sh\" || command === \"bash\" || command === \"zsh\" || command === \"dash\") {\n\t\t// `sh -c '…'` runs arbitrary code; bare `sh script` also executes. Block -c; allow\n\t\t// nothing else is too restrictive for `bash --version`, so allow flag-only invocations.\n\t\treturn args.some((a) => a === \"-c\" || a === \"-s\") || args.some((a) => !a.startsWith(\"-\"));\n\t}\n\n\tconst pkgMutations = PACKAGE_MANAGER_MUTATIONS[command];\n\tif (pkgMutations) {\n\t\tconst subcommand = args.find((a) => !a.startsWith(\"-\"))?.toLowerCase();\n\t\treturn subcommand !== undefined && pkgMutations.has(subcommand);\n\t}\n\n\t// Node / Python interpreters: flag-only, no executing flags, no positional scripts.\n\tif (command === \"node\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_NODE_FLAGS.has(a));\n\t}\n\tif (command === \"python\" || command === \"python3\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_PYTHON_FLAGS.has(a));\n\t}\n\n\t// Final gate: the command must be in the read-only allowlist.\n\treturn !ALLOWED_COMMANDS.has(command);\n}\n\n/** Global git options that take no value. Unknown leading flags are treated as mutating. */\nconst GIT_GLOBAL_FLAGS = new Set([\n\t\"--no-pager\",\n\t\"--paginate\",\n\t\"-p\",\n\t\"--version\",\n\t\"--help\",\n\t\"-h\",\n\t\"--bare\",\n\t\"--no-replace-objects\",\n\t\"--no-optional-locks\",\n\t\"--literal-pathspecs\",\n\t\"--glob-pathspecs\",\n\t\"--noglob-pathspecs\",\n\t\"--icase-pathspecs\",\n]);\n\n/** Walk past known `git` globals. Returns the subcommand index, or -1 to block. */\nfunction gitSubcommandIndex(args: string[]): number {\n\tlet index = 0;\n\twhile (index < args.length) {\n\t\tconst token = args[index];\n\t\tif (!token.startsWith(\"-\")) return index;\n\t\tif (token === \"--\") return index + 1;\n\t\tif (GIT_GLOBAL_FLAGS.has(token)) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken === \"-C\" ||\n\t\t\ttoken === \"-c\" ||\n\t\t\ttoken === \"--git-dir\" ||\n\t\t\ttoken === \"--work-tree\" ||\n\t\t\ttoken === \"--namespace\"\n\t\t) {\n\t\t\tif (args[index + 1] === undefined) return -1;\n\t\t\tindex += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken.startsWith(\"--git-dir=\") ||\n\t\t\ttoken.startsWith(\"--work-tree=\") ||\n\t\t\ttoken.startsWith(\"--namespace=\") ||\n\t\t\ttoken.startsWith(\"--config-env=\")\n\t\t) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\treturn -1;\n\t}\n\treturn index;\n}\n\nfunction isMutatingGit(args: string[]): boolean {\n\tconst index = gitSubcommandIndex(args);\n\tif (index < 0) return true;\n\tconst subcommand = args[index]?.toLowerCase();\n\tif (!subcommand) return false;\n\n\tif (MUTATING_GIT_SUBCOMMANDS.has(subcommand)) return true;\n\tif (CONDITIONAL_GIT_SUBCOMMANDS.has(subcommand)) {\n\t\tconst rest = args.slice(index + 1);\n\t\treturn rest.some((a) => !a.startsWith(\"-\") || CONDITIONAL_GIT_MUTATING_FLAGS.has(a));\n\t}\n\treturn false;\n}\n\nfunction basenameOf(token: string): string {\n\tconst parts = token.split(/[\\\\/]/);\n\treturn parts[parts.length - 1] ?? token;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plan-mode.d.ts","sourceRoot":"","sources":["../../src/core/plan-mode.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,yNACmL,CAAC;AAExN,eAAO,MAAM,4BAA4B,kDAAkD,CAAC;AAwI5F,yFAAyF;AACzF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAwB5F;AAOD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAe9D","sourcesContent":["import { computerPolicy } from \"./computer-use/policy.ts\";\n\n/**\n * lunr: read-only tool-gating heuristics + system-prompt addendum.\n *\n * `gateToolCall` in permissions.ts applies `readOnlyModeBlockReason` in read-only mode:\n * `edit`/`write` and mutating `bash` are hard-blocked; read tools stay open.\n * InteractiveMode installs `READ_ONLY_MODE_ADDENDUM` via the shared system-prompt\n * append slot (same slot auto mode uses).\n *\n * Bash heuristic (conservative, blocklist-based — NOT a security boundary):\n * - any `>`/`>>` redirect outside quotes blocks the whole command;\n * - the command is split on `;`, `|`, `&` separators (outside quotes) and every segment's\n * leading command must be read-only:\n * - known mutating commands (rm, mv, cp, mkdir, sed -i, tee, …) are blocked;\n * - `git` is limited to read-only subcommands (status/log/diff/show/… plus flag-only\n * branch/tag/remote); mutating subcommands (add/commit/push/checkout/…) are blocked;\n * - package managers are limited to read-only subcommands (install/add/remove/… blocked);\n * - arbitrary runners (sudo, xargs, npx, sh -c …) are blocked.\n * Unknown-but-not-listed commands are ALLOWED (blocklist, not allowlist) — the model is\n * additionally steered by the system-prompt addendum. False positives are expected; the\n * user can run the command themselves or switch to another mode.\n */\n\n/** Appended to the system prompt while read-only mode is active. */\nexport const READ_ONLY_MODE_ADDENDUM =\n\t\"You are in read-only mode. Investigate and answer without making changes. If the user asks for a plan, you may call present_plan for approval. Do not implement until the user switches modes or approves that plan.\";\n\nexport const READ_ONLY_MODE_BLOCK_MESSAGE = \"Read-only mode is active; no changes allowed.\";\n\nconst BLOCKED_TOOLS = new Set([\"edit\", \"write\", \"memory_add\", \"memory_remove\", \"cron\"]);\n\n/** Small allowlist of read-only commands permitted in read-only mode. Everything else is rejected. */\nconst ALLOWED_COMMANDS = new Set([\n\t\"ls\",\n\t\"ll\",\n\t\"cat\",\n\t\"tac\",\n\t\"grep\",\n\t\"rg\",\n\t\"find\",\n\t\"pwd\",\n\t\"echo\",\n\t\"printf\",\n\t\"head\",\n\t\"tail\",\n\t\"wc\",\n\t\"less\",\n\t\"more\",\n\t\"sort\",\n\t\"uniq\",\n\t\"diff\",\n\t\"cmp\",\n\t\"comm\",\n\t\"test\",\n\t\"[\",\n\t\"true\",\n\t\"false\",\n\t\"which\",\n\t\"whereis\",\n\t\"stat\",\n\t\"file\",\n\t\"id\",\n\t\"whoami\",\n\t\"who\",\n\t\"date\",\n\t\"cal\",\n\t\"env\",\n\t\"printenv\",\n\t\"uname\",\n\t\"hostname\",\n\t\"uptime\",\n\t\"nproc\",\n\t\"tput\",\n\t\"git\",\n\t\"gh\",\n\t\"node\",\n\t\"npm\",\n\t\"pnpm\",\n\t\"yarn\",\n\t\"bun\",\n]);\n\nconst MUTATING_GIT_SUBCOMMANDS = new Set([\n\t\"add\",\n\t\"commit\",\n\t\"push\",\n\t\"pull\",\n\t\"merge\",\n\t\"rebase\",\n\t\"reset\",\n\t\"checkout\",\n\t\"switch\",\n\t\"restore\",\n\t\"rm\",\n\t\"mv\",\n\t\"stash\",\n\t\"cherry-pick\",\n\t\"revert\",\n\t\"clean\",\n\t\"fetch\",\n\t\"config\",\n\t\"apply\",\n\t\"am\",\n\t\"init\",\n\t\"clone\",\n\t\"submodule\",\n\t\"worktree\",\n\t\"gc\",\n\t\"prune\",\n\t\"update-index\",\n]);\n\n// git subcommands that are read-only only when they carry no positional args or\n// mutating flags (`git branch` lists, `git branch foo` / `git branch -d foo` mutate).\nconst CONDITIONAL_GIT_SUBCOMMANDS = new Set([\"branch\", \"tag\", \"remote\"]);\nconst CONDITIONAL_GIT_MUTATING_FLAGS = new Set([\"-d\", \"-D\", \"-m\", \"-M\", \"-c\", \"-C\"]);\n\nconst PACKAGE_MANAGER_MUTATIONS: Record<string, Set<string>> = {\n\tnpm: new Set([\n\t\t\"install\",\n\t\t\"add\",\n\t\t\"remove\",\n\t\t\"uninstall\",\n\t\t\"update\",\n\t\t\"upgrade\",\n\t\t\"publish\",\n\t\t\"link\",\n\t\t\"unlink\",\n\t\t\"ci\",\n\t\t\"init\",\n\t]),\n\tpnpm: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tyarn: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tbun: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n};\n\n// Almost every subcommand mutates the system.\nconst ALWAYS_MUTATING_MANAGERS = new Set([\n\t\"apt\",\n\t\"apt-get\",\n\t\"brew\",\n\t\"dnf\",\n\t\"yum\",\n\t\"pacman\",\n\t\"choco\",\n\t\"winget\",\n\t\"scoop\",\n]);\n\n/** Flags that cause an interpreter to execute code and are never allowed in read-only mode. */\nconst EXECUTING_NODE_FLAGS = new Set([\n\t\"-e\",\n\t\"--eval\",\n\t\"-p\",\n\t\"--print\",\n\t\"-r\",\n\t\"--require\",\n\t\"--import\",\n\t\"-i\",\n\t\"--interactive\",\n]);\nconst EXECUTING_PYTHON_FLAGS = new Set([\"-c\", \"-m\", \"-i\", \"--interactive\"]);\n\n/** Apply-mode rewrite only. Default / omitted `dry_run` is preview and stays allowed. */\nexport function isCodeRewriteMutating(input: unknown): boolean {\n\treturn (input as { dry_run?: unknown } | undefined)?.dry_run === false;\n}\n\n/**\n * Returns the block reason when read-only mode should block this tool call, else undefined.\n */\nexport function readOnlyModeBlockReason(toolName: string, input: unknown): string | undefined {\n\tif (toolName.startsWith(\"computer_\")) {\n\t\ttry {\n\t\t\treturn computerPolicy(toolName, {})?.observation ? undefined : READ_ONLY_MODE_BLOCK_MESSAGE;\n\t\t} catch {\n\t\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t\t}\n\t}\n\tif (toolName === \"browser\" && (input as { action?: unknown } | undefined)?.action === \"act\") {\n\t\treturn `${READ_ONLY_MODE_BLOCK_MESSAGE} Browser interactions require a writable mode; observation remains available.`;\n\t}\n\tif (BLOCKED_TOOLS.has(toolName)) {\n\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"code_rewrite\" && isCodeRewriteMutating(input)) {\n\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"bash\") {\n\t\tconst command = readBashCommand(input);\n\t\tif (command && isMutatingBashCommand(command)) {\n\t\t\treturn `${READ_ONLY_MODE_BLOCK_MESSAGE} Blocked command: ${command}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction readBashCommand(input: unknown): string {\n\tconst command = (input as { command?: unknown } | undefined)?.command;\n\treturn typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Read-only bash allowlist. A command is mutating unless every segment is a\n * known read-only command used safely (no redirects, no command substitution,\n * no process substitution, no executing-interpreter flags).\n */\nexport function isMutatingBashCommand(command: string): boolean {\n\tif (!command.trim()) return false;\n\n\t// Any output redirect outside quotes can write a file.\n\tif (hasUnquotedRedirect(command)) return true;\n\n\t// Command substitution / process substitution / grouped redirect syntaxes\n\t// bypass a simple command-name check.\n\tif (hasShellSubstitution(command)) return true;\n\n\t// Every segment separated by ; | & && || must individually be read-only.\n\tfor (const segment of splitShellSegments(command)) {\n\t\tif (isMutatingSegment(segment)) return true;\n\t}\n\treturn false;\n}\n\nfunction hasUnquotedRedirect(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction splitShellSegments(command: string): string[] {\n\tconst segments: string[] = [];\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tlet start = 0;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tconst next = command[i + 1];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\t// Combined operators && and || split as one boundary.\n\t\tif ((ch === \"&\" && next === \"&\") || (ch === \"|\" && next === \"|\")) {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\ti++;\n\t\t\tstart = i + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \";\" || ch === \"|\" || ch === \"&\" || ch === \"\\n\") {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\tsegments.push(command.slice(start));\n\treturn segments.map((s) => s.trim()).filter((s) => s.length > 0);\n}\n\n/** True when the command contains command/process substitution outside quotes. */\nfunction hasShellSubstitution(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"`\") return true;\n\t\tif (ch === \"$\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"<\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \">\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"&\" && command[i + 1] === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction isMutatingSegment(segment: string): boolean {\n\tlet tokens = segment.split(/\\s+/).filter((t) => t.length > 0);\n\t// Skip leading env assignments (FOO=bar cmd …) and command wrappers we can't see through.\n\twhile (tokens.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) {\n\t\ttokens = tokens.slice(1);\n\t}\n\tif (tokens.length === 0) return false;\n\n\tconst command = basenameOf(tokens[0]).toLowerCase();\n\tconst args = tokens.slice(1);\n\n\tif (ALWAYS_MUTATING_MANAGERS.has(command)) return true;\n\n\tif (command === \"sed\") {\n\t\treturn args.some((a) => a === \"-i\" || a.startsWith(\"-i\") || a.startsWith(\"--in-place\") || /^-[^-]*i/.test(a));\n\t}\n\tif (command === \"find\") {\n\t\treturn args.some((a) => [\"-delete\", \"-exec\", \"-execdir\", \"-ok\", \"-okdir\"].includes(a));\n\t}\n\tif (command === \"git\") {\n\t\treturn isMutatingGit(args);\n\t}\n\tif (command === \"gh\") {\n\t\t// Allow read-only views; block everything that changes remote state.\n\t\tconst sub = `${args[0] ?? \"\"} ${args[1] ?? \"\"}`;\n\t\treturn ![\n\t\t\t\"pr view\",\n\t\t\t\"pr list\",\n\t\t\t\"pr status\",\n\t\t\t\"issue view\",\n\t\t\t\"issue list\",\n\t\t\t\"issue status\",\n\t\t\t\"repo view\",\n\t\t\t\"release view\",\n\t\t\t\"release list\",\n\t\t\t\"run list\",\n\t\t\t\"run view\",\n\t\t\t\"status\",\n\t\t].includes(sub.trim());\n\t}\n\tif (command === \"sh\" || command === \"bash\" || command === \"zsh\" || command === \"dash\") {\n\t\t// `sh -c '…'` runs arbitrary code; bare `sh script` also executes. Block -c; allow\n\t\t// nothing else is too restrictive for `bash --version`, so allow flag-only invocations.\n\t\treturn args.some((a) => a === \"-c\" || a === \"-s\") || args.some((a) => !a.startsWith(\"-\"));\n\t}\n\n\tconst pkgMutations = PACKAGE_MANAGER_MUTATIONS[command];\n\tif (pkgMutations) {\n\t\tconst subcommand = args.find((a) => !a.startsWith(\"-\"))?.toLowerCase();\n\t\treturn subcommand !== undefined && pkgMutations.has(subcommand);\n\t}\n\n\t// Node / Python interpreters: flag-only, no executing flags, no positional scripts.\n\tif (command === \"node\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_NODE_FLAGS.has(a));\n\t}\n\tif (command === \"python\" || command === \"python3\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_PYTHON_FLAGS.has(a));\n\t}\n\n\t// Final gate: the command must be in the read-only allowlist.\n\treturn !ALLOWED_COMMANDS.has(command);\n}\n\n/** Global git options that take no value. Unknown leading flags are treated as mutating. */\nconst GIT_GLOBAL_FLAGS = new Set([\n\t\"--no-pager\",\n\t\"--paginate\",\n\t\"-p\",\n\t\"--version\",\n\t\"--help\",\n\t\"-h\",\n\t\"--bare\",\n\t\"--no-replace-objects\",\n\t\"--no-optional-locks\",\n\t\"--literal-pathspecs\",\n\t\"--glob-pathspecs\",\n\t\"--noglob-pathspecs\",\n\t\"--icase-pathspecs\",\n]);\n\n/** Walk past known `git` globals. Returns the subcommand index, or -1 to block. */\nfunction gitSubcommandIndex(args: string[]): number {\n\tlet index = 0;\n\twhile (index < args.length) {\n\t\tconst token = args[index];\n\t\tif (!token.startsWith(\"-\")) return index;\n\t\tif (token === \"--\") return index + 1;\n\t\tif (GIT_GLOBAL_FLAGS.has(token)) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken === \"-C\" ||\n\t\t\ttoken === \"-c\" ||\n\t\t\ttoken === \"--git-dir\" ||\n\t\t\ttoken === \"--work-tree\" ||\n\t\t\ttoken === \"--namespace\"\n\t\t) {\n\t\t\tif (args[index + 1] === undefined) return -1;\n\t\t\tindex += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken.startsWith(\"--git-dir=\") ||\n\t\t\ttoken.startsWith(\"--work-tree=\") ||\n\t\t\ttoken.startsWith(\"--namespace=\") ||\n\t\t\ttoken.startsWith(\"--config-env=\")\n\t\t) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\treturn -1;\n\t}\n\treturn index;\n}\n\nfunction isMutatingGit(args: string[]): boolean {\n\tconst index = gitSubcommandIndex(args);\n\tif (index < 0) return true;\n\tconst subcommand = args[index]?.toLowerCase();\n\tif (!subcommand) return false;\n\n\tif (MUTATING_GIT_SUBCOMMANDS.has(subcommand)) return true;\n\tif (CONDITIONAL_GIT_SUBCOMMANDS.has(subcommand)) {\n\t\tconst rest = args.slice(index + 1);\n\t\treturn rest.some((a) => !a.startsWith(\"-\") || CONDITIONAL_GIT_MUTATING_FLAGS.has(a));\n\t}\n\treturn false;\n}\n\nfunction basenameOf(token: string): string {\n\tconst parts = token.split(/[\\\\/]/);\n\treturn parts[parts.length - 1] ?? token;\n}\n"]}
|
package/dist/core/plan-mode.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { computerPolicy } from "./computer-use/policy.js";
|
|
1
2
|
/**
|
|
2
3
|
* lunr: read-only tool-gating heuristics + system-prompt addendum.
|
|
3
4
|
*
|
|
@@ -157,6 +158,14 @@ export function isCodeRewriteMutating(input) {
|
|
|
157
158
|
* Returns the block reason when read-only mode should block this tool call, else undefined.
|
|
158
159
|
*/
|
|
159
160
|
export function readOnlyModeBlockReason(toolName, input) {
|
|
161
|
+
if (toolName.startsWith("computer_")) {
|
|
162
|
+
try {
|
|
163
|
+
return computerPolicy(toolName, {})?.observation ? undefined : READ_ONLY_MODE_BLOCK_MESSAGE;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return READ_ONLY_MODE_BLOCK_MESSAGE;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
160
169
|
if (toolName === "browser" && input?.action === "act") {
|
|
161
170
|
return `${READ_ONLY_MODE_BLOCK_MESSAGE} Browser interactions require a writable mode; observation remains available.`;
|
|
162
171
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-mode.js","sourceRoot":"","sources":["../../src/core/plan-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunr: read-only tool-gating heuristics + system-prompt addendum.\n *\n * `gateToolCall` in permissions.ts applies `readOnlyModeBlockReason` in read-only mode:\n * `edit`/`write` and mutating `bash` are hard-blocked; read tools stay open.\n * InteractiveMode installs `READ_ONLY_MODE_ADDENDUM` via the shared system-prompt\n * append slot (same slot auto mode uses).\n *\n * Bash heuristic (conservative, blocklist-based — NOT a security boundary):\n * - any `>`/`>>` redirect outside quotes blocks the whole command;\n * - the command is split on `;`, `|`, `&` separators (outside quotes) and every segment's\n * leading command must be read-only:\n * - known mutating commands (rm, mv, cp, mkdir, sed -i, tee, …) are blocked;\n * - `git` is limited to read-only subcommands (status/log/diff/show/… plus flag-only\n * branch/tag/remote); mutating subcommands (add/commit/push/checkout/…) are blocked;\n * - package managers are limited to read-only subcommands (install/add/remove/… blocked);\n * - arbitrary runners (sudo, xargs, npx, sh -c …) are blocked.\n * Unknown-but-not-listed commands are ALLOWED (blocklist, not allowlist) — the model is\n * additionally steered by the system-prompt addendum. False positives are expected; the\n * user can run the command themselves or switch to another mode.\n */\n\n/** Appended to the system prompt while read-only mode is active. */\nexport const READ_ONLY_MODE_ADDENDUM =\n\t\"You are in read-only mode. Investigate and answer without making changes. If the user asks for a plan, you may call present_plan for approval. Do not implement until the user switches modes or approves that plan.\";\n\nexport const READ_ONLY_MODE_BLOCK_MESSAGE = \"Read-only mode is active; no changes allowed.\";\n\nconst BLOCKED_TOOLS = new Set([\"edit\", \"write\", \"memory_add\", \"memory_remove\", \"cron\"]);\n\n/** Small allowlist of read-only commands permitted in read-only mode. Everything else is rejected. */\nconst ALLOWED_COMMANDS = new Set([\n\t\"ls\",\n\t\"ll\",\n\t\"cat\",\n\t\"tac\",\n\t\"grep\",\n\t\"rg\",\n\t\"find\",\n\t\"pwd\",\n\t\"echo\",\n\t\"printf\",\n\t\"head\",\n\t\"tail\",\n\t\"wc\",\n\t\"less\",\n\t\"more\",\n\t\"sort\",\n\t\"uniq\",\n\t\"diff\",\n\t\"cmp\",\n\t\"comm\",\n\t\"test\",\n\t\"[\",\n\t\"true\",\n\t\"false\",\n\t\"which\",\n\t\"whereis\",\n\t\"stat\",\n\t\"file\",\n\t\"id\",\n\t\"whoami\",\n\t\"who\",\n\t\"date\",\n\t\"cal\",\n\t\"env\",\n\t\"printenv\",\n\t\"uname\",\n\t\"hostname\",\n\t\"uptime\",\n\t\"nproc\",\n\t\"tput\",\n\t\"git\",\n\t\"gh\",\n\t\"node\",\n\t\"npm\",\n\t\"pnpm\",\n\t\"yarn\",\n\t\"bun\",\n]);\n\nconst MUTATING_GIT_SUBCOMMANDS = new Set([\n\t\"add\",\n\t\"commit\",\n\t\"push\",\n\t\"pull\",\n\t\"merge\",\n\t\"rebase\",\n\t\"reset\",\n\t\"checkout\",\n\t\"switch\",\n\t\"restore\",\n\t\"rm\",\n\t\"mv\",\n\t\"stash\",\n\t\"cherry-pick\",\n\t\"revert\",\n\t\"clean\",\n\t\"fetch\",\n\t\"config\",\n\t\"apply\",\n\t\"am\",\n\t\"init\",\n\t\"clone\",\n\t\"submodule\",\n\t\"worktree\",\n\t\"gc\",\n\t\"prune\",\n\t\"update-index\",\n]);\n\n// git subcommands that are read-only only when they carry no positional args or\n// mutating flags (`git branch` lists, `git branch foo` / `git branch -d foo` mutate).\nconst CONDITIONAL_GIT_SUBCOMMANDS = new Set([\"branch\", \"tag\", \"remote\"]);\nconst CONDITIONAL_GIT_MUTATING_FLAGS = new Set([\"-d\", \"-D\", \"-m\", \"-M\", \"-c\", \"-C\"]);\n\nconst PACKAGE_MANAGER_MUTATIONS: Record<string, Set<string>> = {\n\tnpm: new Set([\n\t\t\"install\",\n\t\t\"add\",\n\t\t\"remove\",\n\t\t\"uninstall\",\n\t\t\"update\",\n\t\t\"upgrade\",\n\t\t\"publish\",\n\t\t\"link\",\n\t\t\"unlink\",\n\t\t\"ci\",\n\t\t\"init\",\n\t]),\n\tpnpm: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tyarn: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tbun: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n};\n\n// Almost every subcommand mutates the system.\nconst ALWAYS_MUTATING_MANAGERS = new Set([\n\t\"apt\",\n\t\"apt-get\",\n\t\"brew\",\n\t\"dnf\",\n\t\"yum\",\n\t\"pacman\",\n\t\"choco\",\n\t\"winget\",\n\t\"scoop\",\n]);\n\n/** Flags that cause an interpreter to execute code and are never allowed in read-only mode. */\nconst EXECUTING_NODE_FLAGS = new Set([\n\t\"-e\",\n\t\"--eval\",\n\t\"-p\",\n\t\"--print\",\n\t\"-r\",\n\t\"--require\",\n\t\"--import\",\n\t\"-i\",\n\t\"--interactive\",\n]);\nconst EXECUTING_PYTHON_FLAGS = new Set([\"-c\", \"-m\", \"-i\", \"--interactive\"]);\n\n/** Apply-mode rewrite only. Default / omitted `dry_run` is preview and stays allowed. */\nexport function isCodeRewriteMutating(input: unknown): boolean {\n\treturn (input as { dry_run?: unknown } | undefined)?.dry_run === false;\n}\n\n/**\n * Returns the block reason when read-only mode should block this tool call, else undefined.\n */\nexport function readOnlyModeBlockReason(toolName: string, input: unknown): string | undefined {\n\tif (toolName === \"browser\" && (input as { action?: unknown } | undefined)?.action === \"act\") {\n\t\treturn `${READ_ONLY_MODE_BLOCK_MESSAGE} Browser interactions require a writable mode; observation remains available.`;\n\t}\n\tif (BLOCKED_TOOLS.has(toolName)) {\n\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"code_rewrite\" && isCodeRewriteMutating(input)) {\n\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"bash\") {\n\t\tconst command = readBashCommand(input);\n\t\tif (command && isMutatingBashCommand(command)) {\n\t\t\treturn `${READ_ONLY_MODE_BLOCK_MESSAGE} Blocked command: ${command}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction readBashCommand(input: unknown): string {\n\tconst command = (input as { command?: unknown } | undefined)?.command;\n\treturn typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Read-only bash allowlist. A command is mutating unless every segment is a\n * known read-only command used safely (no redirects, no command substitution,\n * no process substitution, no executing-interpreter flags).\n */\nexport function isMutatingBashCommand(command: string): boolean {\n\tif (!command.trim()) return false;\n\n\t// Any output redirect outside quotes can write a file.\n\tif (hasUnquotedRedirect(command)) return true;\n\n\t// Command substitution / process substitution / grouped redirect syntaxes\n\t// bypass a simple command-name check.\n\tif (hasShellSubstitution(command)) return true;\n\n\t// Every segment separated by ; | & && || must individually be read-only.\n\tfor (const segment of splitShellSegments(command)) {\n\t\tif (isMutatingSegment(segment)) return true;\n\t}\n\treturn false;\n}\n\nfunction hasUnquotedRedirect(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction splitShellSegments(command: string): string[] {\n\tconst segments: string[] = [];\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tlet start = 0;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tconst next = command[i + 1];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\t// Combined operators && and || split as one boundary.\n\t\tif ((ch === \"&\" && next === \"&\") || (ch === \"|\" && next === \"|\")) {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\ti++;\n\t\t\tstart = i + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \";\" || ch === \"|\" || ch === \"&\" || ch === \"\\n\") {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\tsegments.push(command.slice(start));\n\treturn segments.map((s) => s.trim()).filter((s) => s.length > 0);\n}\n\n/** True when the command contains command/process substitution outside quotes. */\nfunction hasShellSubstitution(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"`\") return true;\n\t\tif (ch === \"$\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"<\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \">\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"&\" && command[i + 1] === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction isMutatingSegment(segment: string): boolean {\n\tlet tokens = segment.split(/\\s+/).filter((t) => t.length > 0);\n\t// Skip leading env assignments (FOO=bar cmd …) and command wrappers we can't see through.\n\twhile (tokens.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) {\n\t\ttokens = tokens.slice(1);\n\t}\n\tif (tokens.length === 0) return false;\n\n\tconst command = basenameOf(tokens[0]).toLowerCase();\n\tconst args = tokens.slice(1);\n\n\tif (ALWAYS_MUTATING_MANAGERS.has(command)) return true;\n\n\tif (command === \"sed\") {\n\t\treturn args.some((a) => a === \"-i\" || a.startsWith(\"-i\") || a.startsWith(\"--in-place\") || /^-[^-]*i/.test(a));\n\t}\n\tif (command === \"find\") {\n\t\treturn args.some((a) => [\"-delete\", \"-exec\", \"-execdir\", \"-ok\", \"-okdir\"].includes(a));\n\t}\n\tif (command === \"git\") {\n\t\treturn isMutatingGit(args);\n\t}\n\tif (command === \"gh\") {\n\t\t// Allow read-only views; block everything that changes remote state.\n\t\tconst sub = `${args[0] ?? \"\"} ${args[1] ?? \"\"}`;\n\t\treturn ![\n\t\t\t\"pr view\",\n\t\t\t\"pr list\",\n\t\t\t\"pr status\",\n\t\t\t\"issue view\",\n\t\t\t\"issue list\",\n\t\t\t\"issue status\",\n\t\t\t\"repo view\",\n\t\t\t\"release view\",\n\t\t\t\"release list\",\n\t\t\t\"run list\",\n\t\t\t\"run view\",\n\t\t\t\"status\",\n\t\t].includes(sub.trim());\n\t}\n\tif (command === \"sh\" || command === \"bash\" || command === \"zsh\" || command === \"dash\") {\n\t\t// `sh -c '…'` runs arbitrary code; bare `sh script` also executes. Block -c; allow\n\t\t// nothing else is too restrictive for `bash --version`, so allow flag-only invocations.\n\t\treturn args.some((a) => a === \"-c\" || a === \"-s\") || args.some((a) => !a.startsWith(\"-\"));\n\t}\n\n\tconst pkgMutations = PACKAGE_MANAGER_MUTATIONS[command];\n\tif (pkgMutations) {\n\t\tconst subcommand = args.find((a) => !a.startsWith(\"-\"))?.toLowerCase();\n\t\treturn subcommand !== undefined && pkgMutations.has(subcommand);\n\t}\n\n\t// Node / Python interpreters: flag-only, no executing flags, no positional scripts.\n\tif (command === \"node\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_NODE_FLAGS.has(a));\n\t}\n\tif (command === \"python\" || command === \"python3\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_PYTHON_FLAGS.has(a));\n\t}\n\n\t// Final gate: the command must be in the read-only allowlist.\n\treturn !ALLOWED_COMMANDS.has(command);\n}\n\n/** Global git options that take no value. Unknown leading flags are treated as mutating. */\nconst GIT_GLOBAL_FLAGS = new Set([\n\t\"--no-pager\",\n\t\"--paginate\",\n\t\"-p\",\n\t\"--version\",\n\t\"--help\",\n\t\"-h\",\n\t\"--bare\",\n\t\"--no-replace-objects\",\n\t\"--no-optional-locks\",\n\t\"--literal-pathspecs\",\n\t\"--glob-pathspecs\",\n\t\"--noglob-pathspecs\",\n\t\"--icase-pathspecs\",\n]);\n\n/** Walk past known `git` globals. Returns the subcommand index, or -1 to block. */\nfunction gitSubcommandIndex(args: string[]): number {\n\tlet index = 0;\n\twhile (index < args.length) {\n\t\tconst token = args[index];\n\t\tif (!token.startsWith(\"-\")) return index;\n\t\tif (token === \"--\") return index + 1;\n\t\tif (GIT_GLOBAL_FLAGS.has(token)) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken === \"-C\" ||\n\t\t\ttoken === \"-c\" ||\n\t\t\ttoken === \"--git-dir\" ||\n\t\t\ttoken === \"--work-tree\" ||\n\t\t\ttoken === \"--namespace\"\n\t\t) {\n\t\t\tif (args[index + 1] === undefined) return -1;\n\t\t\tindex += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken.startsWith(\"--git-dir=\") ||\n\t\t\ttoken.startsWith(\"--work-tree=\") ||\n\t\t\ttoken.startsWith(\"--namespace=\") ||\n\t\t\ttoken.startsWith(\"--config-env=\")\n\t\t) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\treturn -1;\n\t}\n\treturn index;\n}\n\nfunction isMutatingGit(args: string[]): boolean {\n\tconst index = gitSubcommandIndex(args);\n\tif (index < 0) return true;\n\tconst subcommand = args[index]?.toLowerCase();\n\tif (!subcommand) return false;\n\n\tif (MUTATING_GIT_SUBCOMMANDS.has(subcommand)) return true;\n\tif (CONDITIONAL_GIT_SUBCOMMANDS.has(subcommand)) {\n\t\tconst rest = args.slice(index + 1);\n\t\treturn rest.some((a) => !a.startsWith(\"-\") || CONDITIONAL_GIT_MUTATING_FLAGS.has(a));\n\t}\n\treturn false;\n}\n\nfunction basenameOf(token: string): string {\n\tconst parts = token.split(/[\\\\/]/);\n\treturn parts[parts.length - 1] ?? token;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plan-mode.js","sourceRoot":"","sources":["../../src/core/plan-mode.ts"],"names":[],"mappings":"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","sourcesContent":["import { computerPolicy } from \"./computer-use/policy.ts\";\n\n/**\n * lunr: read-only tool-gating heuristics + system-prompt addendum.\n *\n * `gateToolCall` in permissions.ts applies `readOnlyModeBlockReason` in read-only mode:\n * `edit`/`write` and mutating `bash` are hard-blocked; read tools stay open.\n * InteractiveMode installs `READ_ONLY_MODE_ADDENDUM` via the shared system-prompt\n * append slot (same slot auto mode uses).\n *\n * Bash heuristic (conservative, blocklist-based — NOT a security boundary):\n * - any `>`/`>>` redirect outside quotes blocks the whole command;\n * - the command is split on `;`, `|`, `&` separators (outside quotes) and every segment's\n * leading command must be read-only:\n * - known mutating commands (rm, mv, cp, mkdir, sed -i, tee, …) are blocked;\n * - `git` is limited to read-only subcommands (status/log/diff/show/… plus flag-only\n * branch/tag/remote); mutating subcommands (add/commit/push/checkout/…) are blocked;\n * - package managers are limited to read-only subcommands (install/add/remove/… blocked);\n * - arbitrary runners (sudo, xargs, npx, sh -c …) are blocked.\n * Unknown-but-not-listed commands are ALLOWED (blocklist, not allowlist) — the model is\n * additionally steered by the system-prompt addendum. False positives are expected; the\n * user can run the command themselves or switch to another mode.\n */\n\n/** Appended to the system prompt while read-only mode is active. */\nexport const READ_ONLY_MODE_ADDENDUM =\n\t\"You are in read-only mode. Investigate and answer without making changes. If the user asks for a plan, you may call present_plan for approval. Do not implement until the user switches modes or approves that plan.\";\n\nexport const READ_ONLY_MODE_BLOCK_MESSAGE = \"Read-only mode is active; no changes allowed.\";\n\nconst BLOCKED_TOOLS = new Set([\"edit\", \"write\", \"memory_add\", \"memory_remove\", \"cron\"]);\n\n/** Small allowlist of read-only commands permitted in read-only mode. Everything else is rejected. */\nconst ALLOWED_COMMANDS = new Set([\n\t\"ls\",\n\t\"ll\",\n\t\"cat\",\n\t\"tac\",\n\t\"grep\",\n\t\"rg\",\n\t\"find\",\n\t\"pwd\",\n\t\"echo\",\n\t\"printf\",\n\t\"head\",\n\t\"tail\",\n\t\"wc\",\n\t\"less\",\n\t\"more\",\n\t\"sort\",\n\t\"uniq\",\n\t\"diff\",\n\t\"cmp\",\n\t\"comm\",\n\t\"test\",\n\t\"[\",\n\t\"true\",\n\t\"false\",\n\t\"which\",\n\t\"whereis\",\n\t\"stat\",\n\t\"file\",\n\t\"id\",\n\t\"whoami\",\n\t\"who\",\n\t\"date\",\n\t\"cal\",\n\t\"env\",\n\t\"printenv\",\n\t\"uname\",\n\t\"hostname\",\n\t\"uptime\",\n\t\"nproc\",\n\t\"tput\",\n\t\"git\",\n\t\"gh\",\n\t\"node\",\n\t\"npm\",\n\t\"pnpm\",\n\t\"yarn\",\n\t\"bun\",\n]);\n\nconst MUTATING_GIT_SUBCOMMANDS = new Set([\n\t\"add\",\n\t\"commit\",\n\t\"push\",\n\t\"pull\",\n\t\"merge\",\n\t\"rebase\",\n\t\"reset\",\n\t\"checkout\",\n\t\"switch\",\n\t\"restore\",\n\t\"rm\",\n\t\"mv\",\n\t\"stash\",\n\t\"cherry-pick\",\n\t\"revert\",\n\t\"clean\",\n\t\"fetch\",\n\t\"config\",\n\t\"apply\",\n\t\"am\",\n\t\"init\",\n\t\"clone\",\n\t\"submodule\",\n\t\"worktree\",\n\t\"gc\",\n\t\"prune\",\n\t\"update-index\",\n]);\n\n// git subcommands that are read-only only when they carry no positional args or\n// mutating flags (`git branch` lists, `git branch foo` / `git branch -d foo` mutate).\nconst CONDITIONAL_GIT_SUBCOMMANDS = new Set([\"branch\", \"tag\", \"remote\"]);\nconst CONDITIONAL_GIT_MUTATING_FLAGS = new Set([\"-d\", \"-D\", \"-m\", \"-M\", \"-c\", \"-C\"]);\n\nconst PACKAGE_MANAGER_MUTATIONS: Record<string, Set<string>> = {\n\tnpm: new Set([\n\t\t\"install\",\n\t\t\"add\",\n\t\t\"remove\",\n\t\t\"uninstall\",\n\t\t\"update\",\n\t\t\"upgrade\",\n\t\t\"publish\",\n\t\t\"link\",\n\t\t\"unlink\",\n\t\t\"ci\",\n\t\t\"init\",\n\t]),\n\tpnpm: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tyarn: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tbun: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n};\n\n// Almost every subcommand mutates the system.\nconst ALWAYS_MUTATING_MANAGERS = new Set([\n\t\"apt\",\n\t\"apt-get\",\n\t\"brew\",\n\t\"dnf\",\n\t\"yum\",\n\t\"pacman\",\n\t\"choco\",\n\t\"winget\",\n\t\"scoop\",\n]);\n\n/** Flags that cause an interpreter to execute code and are never allowed in read-only mode. */\nconst EXECUTING_NODE_FLAGS = new Set([\n\t\"-e\",\n\t\"--eval\",\n\t\"-p\",\n\t\"--print\",\n\t\"-r\",\n\t\"--require\",\n\t\"--import\",\n\t\"-i\",\n\t\"--interactive\",\n]);\nconst EXECUTING_PYTHON_FLAGS = new Set([\"-c\", \"-m\", \"-i\", \"--interactive\"]);\n\n/** Apply-mode rewrite only. Default / omitted `dry_run` is preview and stays allowed. */\nexport function isCodeRewriteMutating(input: unknown): boolean {\n\treturn (input as { dry_run?: unknown } | undefined)?.dry_run === false;\n}\n\n/**\n * Returns the block reason when read-only mode should block this tool call, else undefined.\n */\nexport function readOnlyModeBlockReason(toolName: string, input: unknown): string | undefined {\n\tif (toolName.startsWith(\"computer_\")) {\n\t\ttry {\n\t\t\treturn computerPolicy(toolName, {})?.observation ? undefined : READ_ONLY_MODE_BLOCK_MESSAGE;\n\t\t} catch {\n\t\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t\t}\n\t}\n\tif (toolName === \"browser\" && (input as { action?: unknown } | undefined)?.action === \"act\") {\n\t\treturn `${READ_ONLY_MODE_BLOCK_MESSAGE} Browser interactions require a writable mode; observation remains available.`;\n\t}\n\tif (BLOCKED_TOOLS.has(toolName)) {\n\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"code_rewrite\" && isCodeRewriteMutating(input)) {\n\t\treturn READ_ONLY_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"bash\") {\n\t\tconst command = readBashCommand(input);\n\t\tif (command && isMutatingBashCommand(command)) {\n\t\t\treturn `${READ_ONLY_MODE_BLOCK_MESSAGE} Blocked command: ${command}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction readBashCommand(input: unknown): string {\n\tconst command = (input as { command?: unknown } | undefined)?.command;\n\treturn typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Read-only bash allowlist. A command is mutating unless every segment is a\n * known read-only command used safely (no redirects, no command substitution,\n * no process substitution, no executing-interpreter flags).\n */\nexport function isMutatingBashCommand(command: string): boolean {\n\tif (!command.trim()) return false;\n\n\t// Any output redirect outside quotes can write a file.\n\tif (hasUnquotedRedirect(command)) return true;\n\n\t// Command substitution / process substitution / grouped redirect syntaxes\n\t// bypass a simple command-name check.\n\tif (hasShellSubstitution(command)) return true;\n\n\t// Every segment separated by ; | & && || must individually be read-only.\n\tfor (const segment of splitShellSegments(command)) {\n\t\tif (isMutatingSegment(segment)) return true;\n\t}\n\treturn false;\n}\n\nfunction hasUnquotedRedirect(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction splitShellSegments(command: string): string[] {\n\tconst segments: string[] = [];\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tlet start = 0;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tconst next = command[i + 1];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\t// Combined operators && and || split as one boundary.\n\t\tif ((ch === \"&\" && next === \"&\") || (ch === \"|\" && next === \"|\")) {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\ti++;\n\t\t\tstart = i + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \";\" || ch === \"|\" || ch === \"&\" || ch === \"\\n\") {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\tsegments.push(command.slice(start));\n\treturn segments.map((s) => s.trim()).filter((s) => s.length > 0);\n}\n\n/** True when the command contains command/process substitution outside quotes. */\nfunction hasShellSubstitution(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"`\") return true;\n\t\tif (ch === \"$\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"<\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \">\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"&\" && command[i + 1] === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction isMutatingSegment(segment: string): boolean {\n\tlet tokens = segment.split(/\\s+/).filter((t) => t.length > 0);\n\t// Skip leading env assignments (FOO=bar cmd …) and command wrappers we can't see through.\n\twhile (tokens.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) {\n\t\ttokens = tokens.slice(1);\n\t}\n\tif (tokens.length === 0) return false;\n\n\tconst command = basenameOf(tokens[0]).toLowerCase();\n\tconst args = tokens.slice(1);\n\n\tif (ALWAYS_MUTATING_MANAGERS.has(command)) return true;\n\n\tif (command === \"sed\") {\n\t\treturn args.some((a) => a === \"-i\" || a.startsWith(\"-i\") || a.startsWith(\"--in-place\") || /^-[^-]*i/.test(a));\n\t}\n\tif (command === \"find\") {\n\t\treturn args.some((a) => [\"-delete\", \"-exec\", \"-execdir\", \"-ok\", \"-okdir\"].includes(a));\n\t}\n\tif (command === \"git\") {\n\t\treturn isMutatingGit(args);\n\t}\n\tif (command === \"gh\") {\n\t\t// Allow read-only views; block everything that changes remote state.\n\t\tconst sub = `${args[0] ?? \"\"} ${args[1] ?? \"\"}`;\n\t\treturn ![\n\t\t\t\"pr view\",\n\t\t\t\"pr list\",\n\t\t\t\"pr status\",\n\t\t\t\"issue view\",\n\t\t\t\"issue list\",\n\t\t\t\"issue status\",\n\t\t\t\"repo view\",\n\t\t\t\"release view\",\n\t\t\t\"release list\",\n\t\t\t\"run list\",\n\t\t\t\"run view\",\n\t\t\t\"status\",\n\t\t].includes(sub.trim());\n\t}\n\tif (command === \"sh\" || command === \"bash\" || command === \"zsh\" || command === \"dash\") {\n\t\t// `sh -c '…'` runs arbitrary code; bare `sh script` also executes. Block -c; allow\n\t\t// nothing else is too restrictive for `bash --version`, so allow flag-only invocations.\n\t\treturn args.some((a) => a === \"-c\" || a === \"-s\") || args.some((a) => !a.startsWith(\"-\"));\n\t}\n\n\tconst pkgMutations = PACKAGE_MANAGER_MUTATIONS[command];\n\tif (pkgMutations) {\n\t\tconst subcommand = args.find((a) => !a.startsWith(\"-\"))?.toLowerCase();\n\t\treturn subcommand !== undefined && pkgMutations.has(subcommand);\n\t}\n\n\t// Node / Python interpreters: flag-only, no executing flags, no positional scripts.\n\tif (command === \"node\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_NODE_FLAGS.has(a));\n\t}\n\tif (command === \"python\" || command === \"python3\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_PYTHON_FLAGS.has(a));\n\t}\n\n\t// Final gate: the command must be in the read-only allowlist.\n\treturn !ALLOWED_COMMANDS.has(command);\n}\n\n/** Global git options that take no value. Unknown leading flags are treated as mutating. */\nconst GIT_GLOBAL_FLAGS = new Set([\n\t\"--no-pager\",\n\t\"--paginate\",\n\t\"-p\",\n\t\"--version\",\n\t\"--help\",\n\t\"-h\",\n\t\"--bare\",\n\t\"--no-replace-objects\",\n\t\"--no-optional-locks\",\n\t\"--literal-pathspecs\",\n\t\"--glob-pathspecs\",\n\t\"--noglob-pathspecs\",\n\t\"--icase-pathspecs\",\n]);\n\n/** Walk past known `git` globals. Returns the subcommand index, or -1 to block. */\nfunction gitSubcommandIndex(args: string[]): number {\n\tlet index = 0;\n\twhile (index < args.length) {\n\t\tconst token = args[index];\n\t\tif (!token.startsWith(\"-\")) return index;\n\t\tif (token === \"--\") return index + 1;\n\t\tif (GIT_GLOBAL_FLAGS.has(token)) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken === \"-C\" ||\n\t\t\ttoken === \"-c\" ||\n\t\t\ttoken === \"--git-dir\" ||\n\t\t\ttoken === \"--work-tree\" ||\n\t\t\ttoken === \"--namespace\"\n\t\t) {\n\t\t\tif (args[index + 1] === undefined) return -1;\n\t\t\tindex += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken.startsWith(\"--git-dir=\") ||\n\t\t\ttoken.startsWith(\"--work-tree=\") ||\n\t\t\ttoken.startsWith(\"--namespace=\") ||\n\t\t\ttoken.startsWith(\"--config-env=\")\n\t\t) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\treturn -1;\n\t}\n\treturn index;\n}\n\nfunction isMutatingGit(args: string[]): boolean {\n\tconst index = gitSubcommandIndex(args);\n\tif (index < 0) return true;\n\tconst subcommand = args[index]?.toLowerCase();\n\tif (!subcommand) return false;\n\n\tif (MUTATING_GIT_SUBCOMMANDS.has(subcommand)) return true;\n\tif (CONDITIONAL_GIT_SUBCOMMANDS.has(subcommand)) {\n\t\tconst rest = args.slice(index + 1);\n\t\treturn rest.some((a) => !a.startsWith(\"-\") || CONDITIONAL_GIT_MUTATING_FLAGS.has(a));\n\t}\n\treturn false;\n}\n\nfunction basenameOf(token: string): string {\n\tconst parts = token.split(/[\\\\/]/);\n\treturn parts[parts.length - 1] ?? token;\n}\n"]}
|
|
@@ -130,6 +130,8 @@ export interface Settings {
|
|
|
130
130
|
modelTiers?: ModelTiersSettings;
|
|
131
131
|
modelInstructions?: ModelInstructionsSettings;
|
|
132
132
|
sessionRetentionDays?: number;
|
|
133
|
+
computerUse?: boolean;
|
|
134
|
+
computerForeground?: boolean;
|
|
133
135
|
browserEnabled?: boolean;
|
|
134
136
|
browserAllowPrivateNetwork?: boolean;
|
|
135
137
|
memoryEnabled?: boolean;
|
|
@@ -302,6 +304,10 @@ export declare class SettingsManager {
|
|
|
302
304
|
getSessionRetentionDays(): number;
|
|
303
305
|
setSessionRetentionDays(days: number): void;
|
|
304
306
|
getMemoryCharCap(): number;
|
|
307
|
+
getComputerUse(): boolean;
|
|
308
|
+
setComputerUse(enabled: boolean): void;
|
|
309
|
+
getComputerForeground(): boolean;
|
|
310
|
+
setComputerForeground(enabled: boolean): void;
|
|
305
311
|
getBrowserEnabled(): boolean;
|
|
306
312
|
setBrowserEnabled(enabled: boolean): void;
|
|
307
313
|
getMemoryEnabled(): boolean;
|