one-code-extension 0.4.1 → 0.5.0
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/README.md +16 -5
- package/agents/general-purpose.md +2 -2
- package/docs/guide/README.md +2 -1
- package/docs/guide/bring-your-claude-code-setup.md +60 -9
- package/docs/guide/configuration.md +48 -14
- package/docs/guide/differences-from-claude-code.md +32 -23
- package/docs/guide/doctor.md +20 -13
- package/docs/guide/hooks.md +18 -3
- package/docs/guide/installation.md +27 -4
- package/docs/guide/permissions-modes-and-auto-mode.md +225 -49
- package/docs/guide/providers-and-models.md +137 -54
- package/docs/guide/reference.md +27 -15
- package/docs/guide/sessions-and-context.md +69 -16
- package/docs/guide/skills-plugins-and-mcp.md +57 -20
- package/docs/guide/subagents-and-workflows.md +95 -29
- package/docs/guide/tasks-and-background-work.md +101 -26
- package/docs/guide/terminal-interface.md +24 -12
- package/docs/guide/tools.md +46 -5
- package/docs/guide/troubleshooting.md +13 -9
- package/docs/guide/windows.md +58 -31
- package/extensions/artifacts/gallery.ts +227 -0
- package/extensions/artifacts/index.ts +288 -0
- package/extensions/artifacts/store.ts +570 -0
- package/extensions/artifacts/viewer.ts +199 -0
- package/extensions/ask-user/description.ts +67 -0
- package/extensions/ask-user/dialogs.ts +80 -0
- package/extensions/ask-user/index.ts +37 -33
- package/extensions/ask-user/questions.ts +32 -7
- package/extensions/ask-user/widget.ts +45 -25
- package/extensions/auto-mode/actions.ts +6 -0
- package/extensions/auto-mode/cache.ts +88 -0
- package/extensions/auto-mode/classifier-prompt.ts +5 -4
- package/extensions/auto-mode/classifier.ts +290 -65
- package/extensions/auto-mode/config.ts +72 -20
- package/extensions/auto-mode/decision-log.ts +2 -0
- package/extensions/auto-mode/defaults.ts +1 -1
- package/extensions/auto-mode/denials.ts +123 -0
- package/extensions/auto-mode/git-checkout-programs.ts +187 -0
- package/extensions/auto-mode/git-status-meta.ts +159 -0
- package/extensions/auto-mode/history.ts +189 -0
- package/extensions/auto-mode/instructions.ts +58 -52
- package/extensions/auto-mode/model-select.ts +159 -134
- package/extensions/auto-mode/paths.ts +57 -5
- package/extensions/auto-mode/pause.ts +57 -2
- package/extensions/auto-mode/prompt.ts +37 -21
- package/extensions/auto-mode/read-only-options.ts +724 -0
- package/extensions/auto-mode/resolved-paths-meta.ts +133 -0
- package/extensions/auto-mode/rules.ts +18 -1
- package/extensions/auto-mode/safety-floor.ts +361 -18
- package/extensions/auto-mode/setup-run.ts +20 -14
- package/extensions/auto-mode/shell-analysis.ts +764 -490
- package/extensions/auto-mode/shell-parse.ts +885 -0
- package/extensions/auto-mode/system-note.ts +33 -0
- package/extensions/auto-mode/transcript.ts +80 -51
- package/extensions/background/cron.ts +515 -0
- package/extensions/background/index.ts +514 -236
- package/extensions/background/loop-fire.ts +136 -0
- package/extensions/background/loop-preamble.ts +59 -0
- package/extensions/background/loop-skill.ts +163 -0
- package/extensions/background/monitor-batch.ts +53 -0
- package/extensions/background/noop-fold.ts +128 -0
- package/extensions/background/switch-guard.ts +52 -0
- package/extensions/background/wakeup.ts +159 -55
- package/extensions/bash/background.ts +53 -17
- package/extensions/bash/child.ts +7 -0
- package/extensions/bash/description.ts +188 -0
- package/extensions/bash/guards.ts +15 -67
- package/extensions/bash/index.ts +88 -35
- package/extensions/branding/compaction-keep.ts +63 -0
- package/extensions/branding/declined.ts +22 -0
- package/extensions/branding/index.ts +133 -9
- package/extensions/branding/prompt-editor.ts +53 -6
- package/extensions/branding/queued-edit.ts +31 -0
- package/extensions/branding/replaced-builtins.ts +68 -0
- package/extensions/branding/startup.ts +33 -71
- package/extensions/btw/index.ts +229 -71
- package/extensions/btw/panel.ts +228 -100
- package/extensions/btw/prompt.ts +41 -4
- package/extensions/claude-compat/index.ts +7 -11
- package/extensions/claude-context/index.ts +446 -58
- package/extensions/compaction/cut.ts +157 -0
- package/extensions/compaction/index.ts +216 -75
- package/extensions/compaction/kept-thinking.ts +62 -0
- package/extensions/compaction/prompt.ts +15 -12
- package/extensions/context-budget/index.ts +24 -5
- package/extensions/context-management/index.ts +25 -0
- package/extensions/doctor/build.ts +59 -8
- package/extensions/doctor/builtins.ts +84 -0
- package/extensions/doctor/cli.ts +7 -1
- package/extensions/doctor/compat.ts +88 -23
- package/extensions/doctor/dependencies.ts +41 -5
- package/extensions/doctor/fix-prompt.ts +9 -2
- package/extensions/doctor/index.ts +102 -58
- package/extensions/doctor/models.ts +102 -63
- package/extensions/doctor/presets.ts +42 -27
- package/extensions/doctor/report.ts +19 -2
- package/extensions/doctor/viewer.ts +49 -27
- package/extensions/effort/index.ts +72 -19
- package/extensions/effort/settings.ts +21 -0
- package/extensions/effort/slider.ts +24 -20
- package/extensions/exit/index.ts +32 -1
- package/extensions/file-tracker/index.ts +337 -26
- package/extensions/file-tracker/replay.ts +96 -10
- package/extensions/file-tracker/restore.ts +63 -0
- package/extensions/file-tracker/results.ts +66 -0
- package/extensions/file-tracker/shell-reads.ts +211 -0
- package/extensions/file-tracker/tracker.ts +32 -15
- package/extensions/footer/footer-line.ts +45 -24
- package/extensions/footer/index.ts +47 -2
- package/extensions/footer/pr.ts +34 -5
- package/extensions/hooks/compaction.ts +7 -0
- package/extensions/hooks/executor.ts +32 -30
- package/extensions/hooks/index.ts +198 -31
- package/extensions/hooks/matcher.ts +3 -0
- package/extensions/hooks/protocol.ts +41 -3
- package/extensions/hooks/settings.ts +50 -19
- package/extensions/hooks/subagent-bridge.ts +2 -0
- package/extensions/hooks/trust.ts +13 -5
- package/extensions/idle-compact/index.ts +119 -0
- package/extensions/idle-compact/policy.ts +143 -0
- package/extensions/init/index.ts +11 -10
- package/extensions/init/prompt.ts +25 -32
- package/extensions/interrupted/index.ts +13 -1
- package/extensions/kept-thinking/index.ts +27 -0
- package/extensions/lib/agent-cron.ts +130 -0
- package/extensions/lib/agent-loader.ts +15 -1
- package/extensions/lib/agent-view.ts +85 -0
- package/extensions/lib/anthropic-payload.ts +82 -1
- package/extensions/lib/anthropic-server-call.ts +230 -0
- package/extensions/lib/anthropic-server-tools.ts +485 -0
- package/extensions/lib/app-launch.mjs +94 -0
- package/extensions/lib/argument-hints.ts +190 -0
- package/extensions/lib/atomic-write.ts +6 -2
- package/extensions/lib/auto-memory.ts +75 -0
- package/extensions/lib/bash-parser.ts +84 -0
- package/extensions/lib/btw-fork.ts +93 -0
- package/extensions/lib/child-extensions.ts +42 -0
- package/extensions/lib/child-writes.ts +45 -0
- package/extensions/lib/claude-context.ts +515 -100
- package/extensions/lib/claude-external-includes.ts +68 -0
- package/extensions/lib/claude-id.ts +22 -0
- package/extensions/lib/claude-rules.ts +323 -0
- package/extensions/lib/claude-settings.ts +76 -4
- package/extensions/lib/compaction-boundary.ts +36 -0
- package/extensions/lib/compaction-keep.mjs +83 -0
- package/extensions/lib/config-mode.ts +112 -0
- package/extensions/lib/consent-dialogs.ts +63 -0
- package/extensions/lib/consent-preview.ts +5 -1
- package/extensions/lib/consent-stores.ts +48 -0
- package/extensions/lib/context-facts.ts +78 -0
- package/extensions/lib/context-stack.ts +81 -0
- package/extensions/lib/deferred.ts +219 -25
- package/extensions/lib/dock-rows.ts +60 -0
- package/extensions/lib/empty-tool-result.ts +27 -0
- package/extensions/lib/environment-block.ts +76 -0
- package/extensions/lib/fetch-timeout.ts +24 -6
- package/extensions/{system-prompt → lib}/git-status.ts +51 -13
- package/extensions/lib/git.ts +75 -13
- package/extensions/lib/grammars/LICENSE-tree-sitter-bash +21 -0
- package/extensions/lib/grammars/README.md +2 -0
- package/extensions/lib/grammars/tree-sitter-bash.wasm +0 -0
- package/extensions/lib/guide-docs.ts +45 -0
- package/extensions/lib/headless-output.ts +46 -0
- package/extensions/lib/hook-gate.ts +7 -7
- package/extensions/lib/interrupt.ts +20 -4
- package/extensions/lib/key-input.ts +455 -0
- package/extensions/lib/keys.ts +14 -1
- package/extensions/lib/local-command.ts +47 -13
- package/extensions/lib/mcp-overrides.ts +1 -1
- package/extensions/lib/mcp-share.ts +46 -0
- package/extensions/lib/memory-content.ts +146 -0
- package/extensions/lib/memory-index.ts +18 -0
- package/extensions/lib/memory.ts +134 -123
- package/extensions/lib/model-catalog/huggingface.json +174 -0
- package/extensions/lib/model-catalog/models-dev.json +18297 -0
- package/extensions/lib/model-catalog/openrouter.json +5252 -0
- package/extensions/lib/model-catalog-data.ts +513 -0
- package/extensions/lib/model-catalog.ts +462 -0
- package/extensions/lib/model-choice-warnings.ts +137 -0
- package/extensions/lib/model-pairings.ts +152 -0
- package/extensions/{auto-mode → lib}/model-picker.ts +26 -43
- package/extensions/lib/model-policy.ts +112 -15
- package/extensions/lib/model-tier.ts +283 -355
- package/extensions/lib/model-unusable.ts +1 -1
- package/extensions/lib/newer-model.ts +100 -0
- package/extensions/lib/notices.ts +87 -0
- package/extensions/lib/notifications.ts +308 -64
- package/extensions/lib/one-code-settings.ts +74 -8
- package/extensions/lib/open-browser.ts +63 -0
- package/extensions/lib/openrouter-generation.ts +94 -0
- package/extensions/lib/operation-deadline.ts +30 -0
- package/extensions/lib/original-command.ts +4 -4
- package/extensions/lib/package-version.ts +1 -1
- package/extensions/lib/panel-focus.ts +134 -0
- package/extensions/lib/paths.ts +17 -2
- package/extensions/lib/permission-gate.ts +72 -6
- package/extensions/lib/persisted-output.ts +60 -8
- package/extensions/lib/pi-ai-estimate.ts +19 -3
- package/extensions/lib/pi-version.ts +21 -2
- package/extensions/lib/plan-mode-channels.ts +20 -5
- package/extensions/lib/plugins.ts +26 -17
- package/extensions/lib/powershell-parse-script.ts +208 -0
- package/extensions/lib/powershell-parser.ts +344 -0
- package/extensions/lib/process-tree.ts +131 -8
- package/extensions/lib/prompt-options.ts +82 -0
- package/extensions/lib/queued-delivery.ts +44 -0
- package/extensions/lib/reminders.ts +364 -58
- package/extensions/lib/replaced-builtins.mjs +199 -0
- package/extensions/lib/replay-call.ts +70 -0
- package/extensions/lib/request-replay.ts +439 -0
- package/extensions/lib/scratchpad.ts +81 -14
- package/extensions/lib/send-now-channel.ts +7 -0
- package/extensions/lib/session-model-tier.ts +51 -0
- package/extensions/lib/session-work.ts +64 -0
- package/extensions/lib/settings-channels.ts +4 -4
- package/extensions/lib/shell-exit-semantics.ts +170 -0
- package/extensions/lib/shell-quote.ts +11 -0
- package/extensions/lib/shell-result.ts +70 -0
- package/extensions/lib/shell-spawn.ts +70 -6
- package/extensions/lib/shell-tool.ts +75 -25
- package/extensions/lib/side-call-cache.ts +124 -0
- package/extensions/lib/side-call-run.ts +96 -0
- package/extensions/lib/side-call-usage.ts +38 -0
- package/extensions/lib/side-call.ts +13 -1
- package/extensions/lib/single-flight.ts +18 -0
- package/extensions/lib/skill-body.ts +42 -0
- package/extensions/lib/skill-scan.ts +63 -24
- package/extensions/lib/spill-file.ts +140 -0
- package/extensions/lib/subagent-handback.ts +113 -0
- package/extensions/lib/system-role.ts +156 -0
- package/extensions/lib/terminal-text.ts +114 -0
- package/extensions/lib/text-width.ts +47 -16
- package/extensions/lib/timer-ops.ts +20 -0
- package/extensions/lib/tool-additions.ts +149 -0
- package/extensions/lib/tool-call-corruption.ts +134 -0
- package/extensions/lib/tool-path.ts +66 -0
- package/extensions/lib/tool-variants.ts +69 -0
- package/extensions/lib/tui-render.ts +255 -27
- package/extensions/lib/turn-budget-layout.ts +143 -0
- package/extensions/lib/update-check.mjs +15 -2
- package/extensions/lib/usage-bus.ts +1 -1
- package/extensions/lib/user-denial.ts +38 -0
- package/extensions/lib/workspace-channel.ts +16 -0
- package/extensions/lib/worktree-channel.ts +31 -3
- package/extensions/lib/worktree-isolation.ts +40 -10
- package/extensions/lsp/client.ts +8 -9
- package/extensions/lsp/index.ts +70 -4
- package/extensions/lsp/keep-alive.ts +1 -1
- package/extensions/lsp/trust.ts +119 -0
- package/extensions/lsp/watcher.ts +1 -1
- package/extensions/mcp/announce.ts +87 -5
- package/extensions/mcp/client.ts +161 -48
- package/extensions/mcp/config.ts +132 -8
- package/extensions/mcp/discovery.ts +19 -0
- package/extensions/mcp/index.ts +209 -71
- package/extensions/mcp/oauth/browser.ts +38 -17
- package/extensions/mcp/oauth/flow.ts +25 -17
- package/extensions/mcp/oauth/provider.ts +14 -8
- package/extensions/mcp/oauth/store.ts +34 -16
- package/extensions/mcp/panel/keys.ts +12 -11
- package/extensions/mcp/panel/render.ts +9 -6
- package/extensions/mcp/schema.ts +104 -5
- package/extensions/mcp/trust.ts +151 -67
- package/extensions/memory/entries.ts +23 -14
- package/extensions/memory/index.ts +134 -28
- package/extensions/memory/open-external.ts +33 -18
- package/extensions/memory/panel.ts +135 -26
- package/extensions/newer-model/index.ts +31 -0
- package/extensions/notebook/description.ts +18 -0
- package/extensions/notebook/index.ts +6 -5
- package/extensions/notebook/notebook.ts +1 -1
- package/extensions/permissions/index.ts +1300 -381
- package/extensions/permissions/matcher.ts +425 -74
- package/extensions/permissions/modes.ts +6 -4
- package/extensions/permissions/panel/host.ts +130 -0
- package/extensions/permissions/panel/keys.ts +48 -0
- package/extensions/permissions/panel/render.ts +450 -0
- package/extensions/permissions/panel/state.ts +550 -0
- package/extensions/permissions/powershell-cmdlets.ts +198 -0
- package/extensions/permissions/powershell-paths.ts +197 -0
- package/extensions/permissions/powershell-rules.ts +207 -280
- package/extensions/permissions/powershell-tree.ts +557 -0
- package/extensions/permissions/project-trust.ts +27 -11
- package/extensions/permissions/protected-paths.ts +14 -2
- package/extensions/permissions/session-grant.ts +6 -0
- package/extensions/permissions/settings.ts +166 -31
- package/extensions/permissions/subagent-gate.ts +25 -0
- package/extensions/permissions/workspace.ts +78 -0
- package/extensions/plan-mode/index.ts +156 -69
- package/extensions/plan-mode/reminder.ts +89 -21
- package/extensions/plan-mode/texts.ts +177 -0
- package/extensions/plan-mode/viewer.ts +92 -27
- package/extensions/plugins/counts.ts +3 -3
- package/extensions/plugins/index.ts +61 -46
- package/extensions/plugins/install/install.ts +16 -0
- package/extensions/plugins/marketplace/sync.ts +9 -3
- package/extensions/plugins/marketplace/types.ts +3 -1
- package/extensions/plugins/panel/keys.ts +21 -24
- package/extensions/plugins/panel/render.ts +12 -6
- package/extensions/plugins/shell-expand.ts +107 -0
- package/extensions/plugins/template.ts +32 -15
- package/extensions/powershell/child.ts +7 -0
- package/extensions/powershell/description.ts +38 -6
- package/extensions/powershell/guards.ts +1 -1
- package/extensions/powershell/index.ts +12 -7
- package/extensions/recap/index.ts +65 -60
- package/extensions/recap/prompt.ts +2 -2
- package/extensions/recap/scheduler.ts +3 -5
- package/extensions/search-tools/grep-merge.ts +39 -0
- package/extensions/search-tools/index.ts +0 -0
- package/extensions/send-now/chord.ts +62 -0
- package/extensions/send-now/index.ts +133 -0
- package/extensions/session-title/index.ts +3 -0
- package/extensions/session-title/title.ts +4 -1
- package/extensions/skill/code-review.ts +97 -0
- package/extensions/skill/index.ts +421 -101
- package/extensions/skill/invoke.ts +128 -18
- package/extensions/skill/listing.ts +133 -9
- package/extensions/skill/panel/keys.ts +15 -16
- package/extensions/skill/panel/render.ts +5 -2
- package/extensions/skill/panel/state.ts +12 -1
- package/extensions/subagents/agent-args.ts +39 -0
- package/extensions/subagents/agent-description.ts +132 -0
- package/extensions/subagents/agents.ts +116 -23
- package/extensions/subagents/announce.ts +69 -0
- package/extensions/subagents/default-model.ts +2 -3
- package/extensions/subagents/delegation-steer.ts +4 -4
- package/extensions/subagents/fork-cache.ts +76 -0
- package/extensions/subagents/guide-agent.ts +189 -0
- package/extensions/subagents/hand-back-review.ts +3 -0
- package/extensions/subagents/index.ts +1493 -824
- package/extensions/subagents/live-runs.ts +26 -6
- package/extensions/subagents/model-select.ts +38 -25
- package/extensions/subagents/outcome.ts +2 -2
- package/extensions/subagents/panel-keys.ts +73 -31
- package/extensions/subagents/panel-render.ts +120 -96
- package/extensions/subagents/panel-widget.ts +60 -89
- package/extensions/subagents/runner.ts +108 -80
- package/extensions/subagents/runs.ts +39 -5
- package/extensions/subagents/send-to-main-tool.ts +1 -1
- package/extensions/subagents/session-turns.ts +32 -8
- package/extensions/subagents/shell-panel.ts +36 -178
- package/extensions/subagents/tasks-dialog.ts +170 -0
- package/extensions/subagents/viewport-mirror.ts +95 -0
- package/extensions/subagents/worktree.ts +57 -13
- package/extensions/system-prompt/environment.ts +19 -19
- package/extensions/system-prompt/idle-turn.ts +65 -0
- package/extensions/system-prompt/index.ts +131 -47
- package/extensions/system-prompt/template.ts +24 -50
- package/extensions/system-prompt/tiers/common.ts +23 -64
- package/extensions/system-prompt/tiers/frontier.ts +32 -11
- package/extensions/system-prompt/tiers/low.ts +67 -45
- package/extensions/system-prompt/tiers/mid.ts +96 -38
- package/extensions/system-reminder/index.ts +175 -13
- package/extensions/tasks/descriptions.ts +190 -0
- package/extensions/tasks/index.ts +120 -41
- package/extensions/tasks/store.ts +83 -16
- package/extensions/tool-call-corruption/child.ts +7 -0
- package/extensions/tool-call-corruption/index.ts +237 -0
- package/extensions/tool-search/announce.ts +16 -0
- package/extensions/tool-search/index.ts +189 -41
- package/extensions/tool-style/index.ts +68 -10
- package/extensions/tool-style/write-description.ts +40 -0
- package/extensions/tool-style/write-render.ts +237 -0
- package/extensions/turn-duration/index.ts +7 -3
- package/extensions/turn-duration/line.ts +47 -4
- package/extensions/web/backends.ts +6 -9
- package/extensions/web/description.ts +50 -0
- package/extensions/web/index.ts +118 -53
- package/extensions/web/native-call.ts +15 -0
- package/extensions/web/native-results.ts +41 -0
- package/extensions/web-fetch/description.ts +42 -0
- package/extensions/web-fetch/extract.ts +53 -6
- package/extensions/web-fetch/index.ts +125 -76
- package/extensions/web-fetch/page-content.ts +19 -0
- package/extensions/web-fetch/response.ts +49 -0
- package/extensions/web-fetch/summarize.ts +9 -10
- package/extensions/workflow/agent-session.ts +105 -18
- package/extensions/workflow/args.ts +24 -0
- package/extensions/workflow/description.ts +67 -0
- package/extensions/workflow/globals.ts +17 -3
- package/extensions/workflow/index.ts +145 -162
- package/extensions/workflow/records.ts +1 -0
- package/extensions/workflow/run-manager.ts +29 -6
- package/extensions/workflow/saved-workflows.ts +3 -2
- package/extensions/workflow/types.ts +22 -1
- package/extensions/workflow/viewer.ts +54 -24
- package/extensions/workflow/widget.ts +20 -0
- package/extensions/worktree/descriptions.ts +91 -0
- package/extensions/worktree/guards.ts +316 -54
- package/extensions/worktree/index.ts +121 -39
- package/extensions/worktree/powershell-guards.ts +167 -0
- package/extensions/worktree/rewrite.ts +14 -16
- package/package.json +18 -7
- package/skills/artifact-design/SKILL.md +85 -0
- package/skills/code-review/SKILL.md +20 -20
- package/skills/code-review/cells/arguments-and-flags.md +19 -0
- package/skills/code-review/cells/high-3x5-recall-verify.md +137 -0
- package/skills/code-review/cells/high-8-inline.md +122 -0
- package/skills/code-review/cells/low-1-pass-max4.md +27 -0
- package/skills/code-review/cells/low-1-pass-min-files-4.md +28 -0
- package/skills/code-review/cells/max-5x5-verify-sweep.md +162 -0
- package/skills/code-review/cells/medium-3x5-verify.md +132 -0
- package/skills/code-review/cells/minimal-prompt.md +32 -0
- package/skills/code-review/cells/xhigh-10-inline-sweep.md +149 -0
- package/skills/code-review/cells/xhigh-5x5-verify-sweep.md +162 -0
- package/skills/fewer-permission-prompts/SKILL.md +1 -1
- package/skills/loop/SKILL.md +11 -0
- package/skills/security-review/SKILL.md +2 -5
- package/skills/simplify/SKILL.md +7 -5
- package/skills/workflow-authoring/SKILL.md +143 -0
- package/themes/onecode-light.json +1 -1
- package/themes/onecode.json +1 -1
- package/types/app.d.ts +58 -0
- package/types/community-packages.d.ts +26 -1
- package/extensions/auto-mode/recoverability.ts +0 -229
- package/extensions/lib/capability-index.ts +0 -466
- package/extensions/lib/model-facts.generated.json +0 -2675
- package/extensions/lib/model-facts.ts +0 -162
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cmdlets the PowerShell pre-gate may clear, and the parameters each may
|
|
3
|
+
* be called with (pure): the PowerShell twin of `auto-mode/read-only-options.ts`
|
|
4
|
+
* (decisions/windows.md "The PowerShell pre-gate reads PowerShell's own parse").
|
|
5
|
+
*
|
|
6
|
+
* Parameters are named as PowerShell's static binder reports them: the
|
|
7
|
+
* canonical name, after aliases (`-LP`, `-First`) and abbreviations (`-pa`)
|
|
8
|
+
* are resolved, and positional arguments assigned (`Select-String TODO a.txt`
|
|
9
|
+
* binds `Pattern` and `Path`). A parameter outside a cmdlet's table is not
|
|
10
|
+
* cleared, so a cmdlet is proved by its parameters, not its name. Left out on
|
|
11
|
+
* purpose, everywhere: `-Credential` (another identity), `-ComputerName`
|
|
12
|
+
* (another machine), `-*Variable` (sets a session variable), `-UseTransaction`,
|
|
13
|
+
* `-FollowSymlink` (recursion through links, which the path checks cannot
|
|
14
|
+
* see), `-Wait` (never returns), `-RelativeBasePath` and `-InputStream`.
|
|
15
|
+
*
|
|
16
|
+
* - `read`: the read-only cmdlets (Claude Code's allowlist, plus the in-process
|
|
17
|
+
* pipeline cmdlets and `Where-Object`/`ForEach-Object` with a checked script
|
|
18
|
+
* block). `paths` are judged where they resolve; `scriptBlocks` may hold only
|
|
19
|
+
* the expression subset `powershell-tree.ts` checks.
|
|
20
|
+
* - `write`: Claude Code's acceptEdits cmdlets, and nothing else: `New-Item`,
|
|
21
|
+
* `Copy-Item`, `Move-Item` and the rest are left to the classifier, as
|
|
22
|
+
* Claude Code leaves them to a prompt.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export interface CmdletSpec {
|
|
26
|
+
/** Parameters naming a path the cmdlet reads (read cmdlets) or writes (write cmdlets). */
|
|
27
|
+
paths?: readonly string[];
|
|
28
|
+
/** Parameters that take no value. */
|
|
29
|
+
switches?: readonly string[];
|
|
30
|
+
/** Parameters that take a constant value that is not a path. */
|
|
31
|
+
values?: readonly string[];
|
|
32
|
+
/** Parameters that take a script block, checked by `powershell-tree.ts`. */
|
|
33
|
+
scriptBlocks?: readonly string[];
|
|
34
|
+
/** Allowed after a pipe (`|`) as well as at a pipeline's head. */
|
|
35
|
+
tail?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Common parameters every cmdlet takes; the `*Variable` ones are left out (they set session variables). */
|
|
39
|
+
const COMMON_SWITCHES = ["Verbose", "Debug"] as const;
|
|
40
|
+
const COMMON_VALUES = ["ErrorAction", "WarningAction", "InformationAction", "ProgressAction", "OutBuffer"] as const;
|
|
41
|
+
|
|
42
|
+
const FILTERS = ["Filter", "Include", "Exclude"] as const;
|
|
43
|
+
const FORMAT_SWITCHES = ["Force", "DisplayError", "ShowError"] as const;
|
|
44
|
+
|
|
45
|
+
/** Keyed by the lowercase cmdlet name. */
|
|
46
|
+
export const READ_CMDLETS: Readonly<Record<string, CmdletSpec>> = Object.freeze({
|
|
47
|
+
"get-childitem": {
|
|
48
|
+
paths: ["Path", "LiteralPath"],
|
|
49
|
+
switches: ["Recurse", "Force", "Name", "Directory", "File", "Hidden", "ReadOnly", "System"],
|
|
50
|
+
values: [...FILTERS, "Depth", "Attributes"],
|
|
51
|
+
},
|
|
52
|
+
"get-content": {
|
|
53
|
+
paths: ["Path", "LiteralPath"],
|
|
54
|
+
switches: ["Force", "Raw", "AsByteStream"],
|
|
55
|
+
values: [...FILTERS, "ReadCount", "TotalCount", "Tail", "Delimiter", "Encoding", "Stream"],
|
|
56
|
+
},
|
|
57
|
+
"get-item": { paths: ["Path", "LiteralPath"], switches: ["Force"], values: [...FILTERS, "Stream"] },
|
|
58
|
+
"test-path": { paths: ["Path", "LiteralPath"], switches: ["IsValid"], values: [...FILTERS, "PathType", "OlderThan", "NewerThan"] },
|
|
59
|
+
"resolve-path": { paths: ["Path", "LiteralPath"], switches: ["Relative", "Force"] },
|
|
60
|
+
"get-filehash": { paths: ["Path", "LiteralPath"], values: ["Algorithm"] },
|
|
61
|
+
"get-acl": { paths: ["Path", "LiteralPath"], switches: ["Audit", "AllCentralAccessPolicies"], values: [...FILTERS] },
|
|
62
|
+
"format-hex": { paths: ["Path", "LiteralPath"], switches: ["Raw"], values: ["InputObject", "Encoding", "Count", "Offset"] },
|
|
63
|
+
"select-string": {
|
|
64
|
+
paths: ["Path", "LiteralPath"],
|
|
65
|
+
switches: ["SimpleMatch", "CaseSensitive", "Quiet", "List", "NotMatch", "AllMatches", "NoEmphasis", "Raw"],
|
|
66
|
+
values: ["Pattern", "InputObject", "Include", "Exclude", "Encoding", "Context", "Culture"],
|
|
67
|
+
tail: true,
|
|
68
|
+
},
|
|
69
|
+
"get-location": {},
|
|
70
|
+
"get-process": { switches: ["IncludeUserName", "Module", "FileVersionInfo"], values: ["Name", "Id"] },
|
|
71
|
+
"get-service": { switches: ["DependentServices", "RequiredServices"], values: ["Name", "DisplayName", "Include", "Exclude"] },
|
|
72
|
+
"write-output": { switches: ["NoEnumerate"], values: ["InputObject"], tail: true },
|
|
73
|
+
"write-host": { switches: ["NoNewline"], values: ["Object", "Separator", "ForegroundColor", "BackgroundColor"], tail: true },
|
|
74
|
+
// In-process pipeline cmdlets: they shape objects already in memory.
|
|
75
|
+
"select-object": {
|
|
76
|
+
switches: ["Unique", "Wait", "CaseInsensitive"],
|
|
77
|
+
values: ["Property", "ExcludeProperty", "ExpandProperty", "First", "Last", "Skip", "SkipLast", "Index", "SkipIndex"],
|
|
78
|
+
tail: true,
|
|
79
|
+
},
|
|
80
|
+
"sort-object": {
|
|
81
|
+
switches: ["Descending", "Unique", "CaseSensitive", "Stable"],
|
|
82
|
+
values: ["Top", "Bottom", "Culture"],
|
|
83
|
+
scriptBlocks: ["Property"],
|
|
84
|
+
tail: true,
|
|
85
|
+
},
|
|
86
|
+
"measure-object": {
|
|
87
|
+
switches: ["Sum", "Average", "Maximum", "Minimum", "Line", "Word", "Character", "IgnoreWhiteSpace", "StandardDeviation", "AllStats"],
|
|
88
|
+
values: ["Property"],
|
|
89
|
+
tail: true,
|
|
90
|
+
},
|
|
91
|
+
"group-object": { switches: ["NoElement", "AsHashTable", "AsString", "CaseSensitive"], values: ["Culture"], scriptBlocks: ["Property"], tail: true },
|
|
92
|
+
"convertfrom-json": { switches: ["AsHashtable", "NoEnumerate"], values: ["InputObject", "Depth", "DateKind"], tail: true },
|
|
93
|
+
"out-string": { switches: ["Stream", "NoNewline"], values: ["Width"], tail: true },
|
|
94
|
+
"format-table": {
|
|
95
|
+
switches: [...FORMAT_SWITCHES, "AutoSize", "Wrap", "HideTableHeaders", "RepeatHeader"],
|
|
96
|
+
values: ["Property", "GroupBy", "View"],
|
|
97
|
+
tail: true,
|
|
98
|
+
},
|
|
99
|
+
"format-list": { switches: [...FORMAT_SWITCHES], values: ["Property", "GroupBy", "View"], tail: true },
|
|
100
|
+
"format-wide": { switches: [...FORMAT_SWITCHES, "AutoSize"], values: ["Property", "Column", "GroupBy", "View"], tail: true },
|
|
101
|
+
"format-custom": { switches: [...FORMAT_SWITCHES], values: ["Property", "Depth", "GroupBy", "View"], tail: true },
|
|
102
|
+
// A script block that reads `$_` and compares; `-MemberName` is left out:
|
|
103
|
+
// `ForEach-Object Delete` calls the input's Delete() method. Their safety
|
|
104
|
+
// rests on powershell-tree.ts `checkScriptBlock`, which every
|
|
105
|
+
// `scriptBlocks` parameter goes through: a new parameter here that takes
|
|
106
|
+
// code or names a member must be one it checks.
|
|
107
|
+
"where-object": {
|
|
108
|
+
switches: [
|
|
109
|
+
"EQ", "NE", "GT", "GE", "LT", "LE", "Like", "NotLike", "Match", "NotMatch", "Contains", "NotContains", "In", "NotIn",
|
|
110
|
+
"Is", "IsNot", "Not", "CEQ", "CNE", "CGT", "CGE", "CLT", "CLE", "CLike", "CNotLike", "CMatch", "CNotMatch",
|
|
111
|
+
"CContains", "CNotContains", "CIn", "CNotIn",
|
|
112
|
+
],
|
|
113
|
+
values: ["Property", "Value"],
|
|
114
|
+
scriptBlocks: ["FilterScript"],
|
|
115
|
+
tail: true,
|
|
116
|
+
},
|
|
117
|
+
"foreach-object": { scriptBlocks: ["Process"], tail: true },
|
|
118
|
+
"out-null": { tail: true },
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
/** The PowerShell cmdlets Claude Code allows in acceptEdits mode, and their parameters. */
|
|
122
|
+
export const WRITE_CMDLETS: Readonly<Record<string, CmdletSpec>> = Object.freeze({
|
|
123
|
+
"set-content": {
|
|
124
|
+
paths: ["Path", "LiteralPath"],
|
|
125
|
+
switches: ["PassThru", "Force", "WhatIf", "Confirm", "NoNewline", "AsByteStream"],
|
|
126
|
+
values: ["Value", ...FILTERS, "Encoding", "Stream"],
|
|
127
|
+
},
|
|
128
|
+
"add-content": {
|
|
129
|
+
paths: ["Path", "LiteralPath"],
|
|
130
|
+
switches: ["PassThru", "Force", "WhatIf", "Confirm", "NoNewline", "AsByteStream"],
|
|
131
|
+
values: ["Value", ...FILTERS, "Encoding", "Stream"],
|
|
132
|
+
},
|
|
133
|
+
"remove-item": { paths: ["Path", "LiteralPath"], switches: ["Recurse", "Force", "WhatIf", "Confirm"], values: [...FILTERS, "Stream"] },
|
|
134
|
+
"clear-content": { paths: ["Path", "LiteralPath"], switches: ["Force", "WhatIf", "Confirm"], values: [...FILTERS, "Stream"] },
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Pipeline tails a write line may end in (Claude Code's safe output
|
|
139
|
+
* cmdlets): they format or drop what the write passes on.
|
|
140
|
+
*/
|
|
141
|
+
export const WRITE_TAILS = new Set(["out-null", "out-string", "format-table", "format-list", "format-wide", "select-object", "sort-object", "measure-object", "write-output"]);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The upstream cmdlets a `Select-String` after a pipe may read from. It
|
|
145
|
+
* searches the files behind `FileInfo` input (from `Get-ChildItem` and
|
|
146
|
+
* `Get-Item`), so an object source that could carry an arbitrary path
|
|
147
|
+
* (`ConvertFrom-Json`) must not feed it.
|
|
148
|
+
*/
|
|
149
|
+
export const SELECT_STRING_SOURCES = new Set(["get-content", "get-childitem", "get-item", "select-string", "where-object", "sort-object", "select-object", "out-string"]);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Native commands the read-only list names (Windows), and the `/X` switches
|
|
153
|
+
* each may take (`c:` takes a value, as in `/C:text`); every other argument
|
|
154
|
+
* is judged as a path. Left out: findstr's `/S` and where.exe's `/R`, which
|
|
155
|
+
* recurse, and findstr's `/F:`, `/G:` and `/D:`, which name more files.
|
|
156
|
+
*/
|
|
157
|
+
const FINDSTR_SWITCHES = new Set(["b", "e", "l", "r", "i", "x", "v", "n", "m", "o", "p", "off", "offline", "a:", "c:"]);
|
|
158
|
+
export const READ_APPLICATIONS: Readonly<Record<string, ReadonlySet<string>>> = Object.freeze({
|
|
159
|
+
findstr: FINDSTR_SWITCHES,
|
|
160
|
+
"findstr.exe": FINDSTR_SWITCHES,
|
|
161
|
+
"where.exe": new Set(["q", "f", "t"]),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
/** How one argument to a read-only application reads: a switch it may take, one it may not, or a path. */
|
|
165
|
+
export function applicationArgument(application: string, argument: string): "switch" | "refused" | "path" {
|
|
166
|
+
const switches = READ_APPLICATIONS[application.toLowerCase()];
|
|
167
|
+
const flag = /^\/([A-Za-z]+)(:.*)?$/s.exec(argument);
|
|
168
|
+
if (!switches || !flag) return "path";
|
|
169
|
+
const name = flag[1].toLowerCase();
|
|
170
|
+
return switches.has(flag[2] === undefined ? name : `${name}:`) ? "switch" : "refused";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** The modules a cleared cmdlet must come from: PowerShell's own. */
|
|
174
|
+
export const TRUSTED_MODULES = new Set([
|
|
175
|
+
"microsoft.powershell.management",
|
|
176
|
+
"microsoft.powershell.utility",
|
|
177
|
+
"microsoft.powershell.core",
|
|
178
|
+
"microsoft.powershell.security",
|
|
179
|
+
]);
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Whether `spelled` (as typed, without its dash) names one of `spec`'s
|
|
183
|
+
* switches by PowerShell's rule: the whole name or a prefix of it.
|
|
184
|
+
*/
|
|
185
|
+
export function isSwitchSpelling(spec: CmdletSpec, spelled: string): boolean {
|
|
186
|
+
const lower = spelled.toLowerCase();
|
|
187
|
+
return lower.length > 0 && [...(spec.switches ?? []), ...COMMON_SWITCHES].some((name) => name.toLowerCase().startsWith(lower));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** How `parameter` may appear on `spec`: as a path, a script block, a switch or a value; undefined when not at all. */
|
|
191
|
+
export function parameterKind(spec: CmdletSpec, parameter: string): "path" | "switch" | "value" | "scriptBlock" | undefined {
|
|
192
|
+
const has = (list: readonly string[] | undefined) => list?.some((name) => name.toLowerCase() === parameter.toLowerCase()) ?? false;
|
|
193
|
+
if (has(spec.paths)) return "path";
|
|
194
|
+
if (has(spec.scriptBlocks)) return "scriptBlock";
|
|
195
|
+
if (has(spec.switches) || has(COMMON_SWITCHES)) return "switch";
|
|
196
|
+
if (has(spec.values) || has(COMMON_VALUES)) return "value";
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a path a PowerShell cmdlet is given resolves, and whether the
|
|
3
|
+
* pre-gate may vouch for it (pure apart from filesystem reads). Used by the
|
|
4
|
+
* tree verdicts in `powershell-tree.ts`; the value is PowerShell's own
|
|
5
|
+
* (quotes and escapes already resolved by its parser).
|
|
6
|
+
*
|
|
7
|
+
* A path is refused by shape when it is UNC (`\\server`), home-relative
|
|
8
|
+
* (`~`), drive-relative (`C:foo`), provider-qualified (`HKLM:`, `Env:`,
|
|
9
|
+
* `FileSystem::…`, `Microsoft.PowerShell.Core\FileSystem::…`), climbs
|
|
10
|
+
* (`..`) or has a space at either end; otherwise it is resolved through symlinks and judged where it
|
|
11
|
+
* lands, with a wildcard in the last component judged match by match.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { readdirSync } from "node:fs";
|
|
15
|
+
import { basename, dirname, isAbsolute, join, sep } from "node:path";
|
|
16
|
+
import { isWithin, resolveForContainment, toAbsolute } from "../auto-mode/paths.ts";
|
|
17
|
+
import { isSensitivePath } from "../auto-mode/sensitive.ts";
|
|
18
|
+
|
|
19
|
+
export interface PowerShellPathOptions {
|
|
20
|
+
/** The working directory the command runs in. */
|
|
21
|
+
cwd: string;
|
|
22
|
+
/** The user's home, for `toAbsolute`. */
|
|
23
|
+
home: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Whether a path is one this check will not vouch for by shape: UNC, home,
|
|
28
|
+
* a PSDrive outside the filesystem or a provider-qualified path, one that
|
|
29
|
+
* climbs, or a drive-relative one.
|
|
30
|
+
*/
|
|
31
|
+
function pathUnvouchable(value: string): boolean {
|
|
32
|
+
if (!value) return false;
|
|
33
|
+
if (value.startsWith("\\\\") || value.startsWith("//")) return true;
|
|
34
|
+
// Provider-qualified, however the provider is spelled: `FileSystem::C:\x`
|
|
35
|
+
// and `Microsoft.PowerShell.Core\FileSystem::C:\x` both name C:\x, which
|
|
36
|
+
// read as a relative name would be judged inside the working directory.
|
|
37
|
+
if (value.includes("::")) return true;
|
|
38
|
+
if (/^[A-Za-z][A-Za-z0-9]+:/.test(value)) return true; // HKLM:, env:, cert: (a drive is one letter)
|
|
39
|
+
// Drive-relative (`C:foo.txt`, no separator after the colon) means "foo.txt
|
|
40
|
+
// relative to PowerShell's current directory ON C:", which need not be the
|
|
41
|
+
// tool's cwd; `path.isAbsolute` does not call it absolute, so `toAbsolute`
|
|
42
|
+
// would join it onto the cwd and vouch for the wrong file. Refuse by shape.
|
|
43
|
+
if (/^[A-Za-z]:(?![\\/])/.test(value)) return true;
|
|
44
|
+
if (value.startsWith("~")) return true;
|
|
45
|
+
if (/(^|[\\/])\.\.([\\/]|$)/.test(value)) return true;
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Whether a PowerShell path holds a wildcard (`*`, `?`, `[…]`), which `-Path` expands. */
|
|
50
|
+
export function hasPowerShellWildcard(value: string): boolean {
|
|
51
|
+
return /[*?[]/.test(value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A path with the backtick escapes `-Path` drops (`` `[ `` to `[`, ``` `` ``` to
|
|
56
|
+
* `` ` ``); `-LiteralPath` keeps them, so a check that does not know which
|
|
57
|
+
* parameter bound the value judges both spellings.
|
|
58
|
+
*/
|
|
59
|
+
export function powershellUnescaped(value: string): string {
|
|
60
|
+
return value.replace(/`([*?[\]`])/g, "$1");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A PowerShell path in this platform's separators: PowerShell on macOS and
|
|
65
|
+
* Linux takes `\` as a separator too, so `sub\link` is `sub/link` there, not
|
|
66
|
+
* one file named with a backslash.
|
|
67
|
+
*/
|
|
68
|
+
export function powershellSeparators(value: string): string {
|
|
69
|
+
return sep === "/" ? value.replaceAll("\\", "/") : value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** An absolute path by Windows or POSIX spelling: `C:\x`, `C:/x`, `/x`, `\x`. */
|
|
73
|
+
function isAbsoluteSpelling(value: string): boolean {
|
|
74
|
+
return /^[A-Za-z]:/.test(value) || value.startsWith("/") || value.startsWith("\\");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The absolute path a PowerShell path value names, or undefined when it is
|
|
79
|
+
* refused by shape or spells an absolute path this platform does not call
|
|
80
|
+
* absolute (`C:\x` on macOS).
|
|
81
|
+
*/
|
|
82
|
+
export function powershellPathAbsolute(value: string, opts: PowerShellPathOptions): string | undefined {
|
|
83
|
+
// The value is PowerShell's own, so a space at either end is part of the
|
|
84
|
+
// name (`' leading.txt'`): trimming it would judge another file. Windows
|
|
85
|
+
// drops a trailing space where macOS and Linux keep it, so refuse either.
|
|
86
|
+
if (!value || value !== value.trim() || pathUnvouchable(value)) return undefined;
|
|
87
|
+
// Resolve only what THIS platform's path module calls absolute: on a POSIX
|
|
88
|
+
// host `C:\x` is not, and `toAbsolute` would join it onto the cwd and
|
|
89
|
+
// vouch for a file the shell would never touch.
|
|
90
|
+
if (isAbsoluteSpelling(value) && !isAbsolute(value)) return undefined;
|
|
91
|
+
return toAbsolute(opts.cwd, powershellSeparators(value), opts.home);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
type WildcardPart = { star: true } | { star: false; matches: (ch: string) => boolean };
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* A PowerShell wildcard component (`*`, `?`, `[a-c]`) as a case-insensitive
|
|
98
|
+
* matcher that matches a superset of what PowerShell does, or undefined.
|
|
99
|
+
* Matched without a regex over the whole name: the model writes the pattern,
|
|
100
|
+
* and `*a*a*a…z` would backtrack polynomially against every directory entry
|
|
101
|
+
* on the permission-gate path.
|
|
102
|
+
*/
|
|
103
|
+
function wildcardMatcher(pattern: string): ((name: string) => boolean) | undefined {
|
|
104
|
+
const parts: WildcardPart[] = [];
|
|
105
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
106
|
+
const ch = pattern[i];
|
|
107
|
+
const close = ch === "[" ? pattern.indexOf("]", i + 1) : -1;
|
|
108
|
+
if (ch === "*" || ch === "?") {
|
|
109
|
+
// `?` is read as `*`: a superset of what it matches (one character, or
|
|
110
|
+
// none at the end of a name on some filesystem APIs), so no match escapes.
|
|
111
|
+
if (!parts.at(-1)?.star) parts.push({ star: true });
|
|
112
|
+
} else if (close > i + 1) {
|
|
113
|
+
let set: RegExp;
|
|
114
|
+
try {
|
|
115
|
+
set = new RegExp(`^[${pattern.slice(i + 1, close).replace(/[\\\]^]/g, "\\$&")}]$`, "i");
|
|
116
|
+
} catch {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
parts.push({ star: false, matches: (c) => set.test(c) });
|
|
120
|
+
i = close;
|
|
121
|
+
} else {
|
|
122
|
+
const lower = ch.toLowerCase();
|
|
123
|
+
parts.push({ star: false, matches: (c) => c.toLowerCase() === lower });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Greedy match that backtracks only to the last `*`: O(name × pattern).
|
|
127
|
+
return (name) => {
|
|
128
|
+
let p = 0;
|
|
129
|
+
let t = 0;
|
|
130
|
+
let starAt = -1;
|
|
131
|
+
let resumeAt = 0;
|
|
132
|
+
while (t < name.length) {
|
|
133
|
+
const part = parts[p];
|
|
134
|
+
if (part && !part.star && part.matches(name[t])) {
|
|
135
|
+
p++;
|
|
136
|
+
t++;
|
|
137
|
+
} else if (part?.star) {
|
|
138
|
+
starAt = p++;
|
|
139
|
+
resumeAt = t;
|
|
140
|
+
} else if (starAt >= 0) {
|
|
141
|
+
p = starAt + 1;
|
|
142
|
+
t = ++resumeAt;
|
|
143
|
+
} else return false;
|
|
144
|
+
}
|
|
145
|
+
while (parts[p]?.star) p++;
|
|
146
|
+
return p === parts.length;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The paths a wildcard in the last component names, or undefined when they
|
|
152
|
+
* cannot be enumerated (a wildcard in a directory component, an unreadable
|
|
153
|
+
* or huge directory). Matched case-insensitively and with hidden entries, a
|
|
154
|
+
* superset of what PowerShell reads, so every match that could be read is judged.
|
|
155
|
+
*/
|
|
156
|
+
function wildcardTargets(absolute: string): string[] | undefined {
|
|
157
|
+
const dir = dirname(absolute);
|
|
158
|
+
const matches = wildcardMatcher(basename(absolute));
|
|
159
|
+
if (hasPowerShellWildcard(dir) || !matches) return undefined;
|
|
160
|
+
let entries: string[];
|
|
161
|
+
try {
|
|
162
|
+
entries = readdirSync(dir);
|
|
163
|
+
} catch {
|
|
164
|
+
return [dir];
|
|
165
|
+
}
|
|
166
|
+
if (entries.length > 2_000) return undefined;
|
|
167
|
+
return [dir, ...entries.filter((entry) => matches(entry)).map((entry) => join(dir, entry))];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Why a path a read cmdlet is given must not be vouched for, or undefined.
|
|
172
|
+
* It is refused by shape when unvouchable, then resolved through
|
|
173
|
+
* `resolveForContainment`, relative paths included: an in-project `notes.txt`
|
|
174
|
+
* can be a symlink out of it (AUTO-MODE-SECURITY-REVIEW-2026-09-24 M4). A
|
|
175
|
+
* wildcard leaf is judged match by match. Every target must lie inside one
|
|
176
|
+
* of `roots` (realpath-resolved) and resolve to no credential path.
|
|
177
|
+
*/
|
|
178
|
+
export function powershellPathProblem(value: string, opts: PowerShellPathOptions, roots: string[]): string | undefined {
|
|
179
|
+
const outside = "a path outside the working directory";
|
|
180
|
+
if (!value) return undefined;
|
|
181
|
+
if (isSensitivePath(value)) return "a credential or secret path";
|
|
182
|
+
const absolute = powershellPathAbsolute(value, opts);
|
|
183
|
+
if (absolute === undefined) return outside;
|
|
184
|
+
// The value's own wildcard, not one in the working directory's name. The
|
|
185
|
+
// literal path is judged too: `-LiteralPath 'n[1].txt'` reads the file of
|
|
186
|
+
// that name, which a bracket set does not match, and so does
|
|
187
|
+
// `-Path 'n`[1`].txt'` once PowerShell drops the escaping backticks.
|
|
188
|
+
const matches = hasPowerShellWildcard(value) ? wildcardTargets(absolute) : [];
|
|
189
|
+
if (matches === undefined) return outside;
|
|
190
|
+
const targets = [...new Set([absolute, powershellUnescaped(absolute), ...matches])];
|
|
191
|
+
for (const target of targets) {
|
|
192
|
+
const resolved = resolveForContainment(target);
|
|
193
|
+
if (resolved === undefined || !roots.some((root) => isWithin(root, resolved))) return outside;
|
|
194
|
+
if (isSensitivePath(resolved)) return "a credential or secret path";
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|