@klarkxy/dsh-safe-auto 0.1.0-rc.6 → 0.2.0-rc.3

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 CHANGED
@@ -1,174 +1,107 @@
1
1
  # Safe Auto (release candidate)
2
2
 
3
- Budgeted preflight plus opt-in automatic approval of one native sandbox escalation at a time. **The reviewer follows the current conversation model by default, and can be configured independently.** The plugin reuses DSH's model adapters, tool loop and approval service. It never switches the standing session to Full Access, and never lets a model enlarge the envelope you configured.
3
+ Automatic review of native sandbox escalation requests. When a real `write`/`edit`/`bash`/`pwsh` call asks to widen its sandbox beyond Workspace Write, an independent reviewer model vets that one call — except a `bash` call the built-in static proof can show is read-only, which is granted without a model. A pass continues automatically; other review results offer an exact-call confirmation in the current session, with 60 seconds to approve once or reject. No response means rejection. The plugin never switches the standing session to Full Access.
4
4
 
5
- [简体中文](README.zh-CN.md) · [Preflight](docs/ADR-0001.md) · [One-shot escalation](docs/ADR-0002.md) · [Reviewer routing](docs/ADR-0003.md)
5
+ [简体中文](README.zh-CN.md) · [One-shot escalation](docs/ADR-0002.md) · [Reviewer routing](docs/ADR-0003.md) · [Authorization and evidence](docs/ADR-0004.md) · [Timed human confirmation](docs/ADR-0005.md) · [Static shell proof](docs/ADR-0006.md)
6
6
 
7
- ## Install and configure
7
+ > **0.2.0 is a breaking simplification.** The 0.1.x exact-rule preflight, workspace/shell/escalation candidate lists, `shadow`/`smart`/`unattended` modes, the deep review stage and the HTTP endpoint were removed. See [Migrating from 0.1.x](#migrating-from-01x).
8
8
 
9
- Use a disposable profile from a checked repository checkout:
9
+ ## Install and enable
10
10
 
11
11
  ```sh
12
- pnpm install --frozen-lockfile
13
- pnpm --filter @klarkxy/dsh-safe-auto test
14
- dsh plugin --profile web add ./plugins/dsh-safe-auto
12
+ dsh plugin --profile <profile> add @klarkxy/dsh-safe-auto
15
13
  ```
16
14
 
17
- A PR is not an npm release. The bundle inserts the `dsh-safe-auto` profile row. Configure its `config` through the profile patch mechanism:
18
-
19
- ```yaml
20
- id: dsh-safe-auto
21
- name: '@klarkxy/dsh-safe-auto'
22
- config:
23
- mode: shadow
24
- workspaceRoots:
25
- - /absolute/canonical/project
26
- shellCandidates:
27
- - git status --short
28
- # No endpoint or model override: follow this conversation's DSH provider/model.
29
- ```
30
-
31
- The enrolled canonical root must exactly match session cwd and the resolved sandbox root. Operator envelopes, candidates and budgets remain strictly validated profile configuration; reload after editing them.
32
-
33
- ## Plugin-page activation and independent approval review
34
-
35
- **What you do.** Select a live root session on the plugin page and click **Enable**. **Disable** only revokes automatic review; it does not change native permissions. Enable keeps **Workspace Write + ask**, never the official Full Access Auto preset. Opening, refreshing or saving the page never activates a session. Children, restarts and UI Host disposal do not inherit activation.
36
-
37
- **What the plugin does.** Set `approvalReview: true` (default `false`), or save **Independent approval reviewer** in the plugin-page mode selector. Inspired by `dsh-approval-review@0.5.1`, this mode reviews real native single-call sandbox escalation requests for `pwsh/bash/write/edit`, including Windows, without POSIX candidate commands. It binds to the current tool execution, not free-text claims, a reused callId or old logs. Unknown tools, remote execution, nested calls, children, incomplete inputs and requests that cannot be bound to a live execution are rejected while independent approval is active. The tool-free reviewer receives the complete bounded action, direct human intent and additional restrictions only.
38
-
39
- Structured verdicts separate risk, authorization, scope and rationale. Automatic allowance requires low/medium risk, medium/high direct authorization and bounded scope. High/critical risk, uncertainty, unknown scripts lacking decisive evidence, malformed verdicts, errors, timeouts, insufficient budgets and invalidated grants are rejected. Explicit denials never fall back to another answerer. The default 64-token fast output budget may be too small for structured output; adjust profile budgets as needed. Truncated output never grants approval.
40
-
41
- This is an explicit delegation of native approval, not authority for arbitrary operations. Native `approval: never` rejects before the chain. The plugin page displays a fixed **Reject (default)** policy for inability to judge. The human approval option is disabled and not persisted, because no human-only DSH channel has been verified; calling waterfall `next()` could reach another automatic answerer and is not a human fallback. Independent approval does not delegate non-allowing decisions downstream. Legacy exact-rule behavior is unchanged. Source changes do not uninstall installed plugins or publish a release.
42
-
43
- ## Reviewer settings
44
-
45
- The updated bundle loads a separate UI Host row. Settings and session controls live on the plugin page; the native composer permission control is not replaced. Enable uses the native preset write path, without the official Full Access `registerAuto()` hook. Native `approval: never` remains authoritative.
46
-
47
- The Safe Auto plugin page selects fast/deep reviewer models, their advertised reasoning efforts, and an additional review prompt (up to 4096 characters). Empty fast route follows the current conversation; empty deep route disables deep review. Selecting a new model clears its previous effort; saved unlisted values are retained rather than silently replaced. Unsupported explicit efforts fail closed. The additional prompt can only add restrictions, never replace the fixed safety instructions or enlarge an envelope. Saving settings performs no inference, changes no session permission, keeps the budget ledger and invalidates pending old grants. Reasoning-heavy models may need larger `fastOutputTokens/deepOutputTokens` in the profile. HTTP mode is read-only in this panel and rejects native effort overrides.
48
-
49
- The `dsh-safe-auto-ui` Host row persists reviewer preferences through `storageDomain`, overriding corresponding profile model fields, but never persists session authorization. Activation belongs to the exact live session object: native selection, an external permission change, restart or UI Host disposal disables it, and forks and children do not inherit it. While UI control is attached, legacy smart/unattended profiles do not automatically activate untouched sessions; loading only the original core Host row retains legacy operation. Removing the Client restores the original permission control.
50
-
51
- ## Choose the approval model
52
-
53
- ### Default: follow the conversation
54
-
55
- Leave `endpoint`, `fastProvider` and `fastModel` unset or empty. Each eligible review resolves the provider/model from the requesting session's accepted `requestHeader().config`; if no accepted header exists, it uses that same agent's `options`. A malformed header never falls back to another route. A new conversation request using a different model changes subsequent reviews; concurrent sessions do not share a global model selection.
56
-
57
- This reuses DSH's configured provider and credentials, so no additional API key or endpoint is required. **Only the model route is inherited**, not the conversation history, main-agent prompt, tools, replay state, reasoning setting or output budget. The reviewer is a separate tool-free one-shot with its own prompt and caps. A model requiring more reasoning tokens may need a larger reviewer cap; unsupported options fail closed rather than dropping limits.
58
-
59
- ### Independent DSH model
15
+ From a checked source checkout instead:
60
16
 
61
- Set both fields in the same `config`, using IDs from your DSH model configuration:
62
-
63
- ```yaml
64
- fastProvider: your-review-provider
65
- fastModel: your-small-review-model
17
+ ```sh
18
+ pnpm install --frozen-lockfile
19
+ pnpm --filter @klarkxy/dsh-safe-auto test
20
+ dsh plugin --profile <profile> add ./plugins/dsh-safe-auto
66
21
  ```
67
22
 
68
- The model can differ from the conversation in both provider and model. It stays fixed when the conversation switches models. Clearing both fields restores following. Invalid/missing providers or models do not trigger a silent fallback to the conversation, another provider, or HTTP.
23
+ The bundle inserts the `dsh-safe-auto` and `dsh-safe-auto-ui` profile rows. Safe Auto then appears as a fourth option in the composer's permission menu, next to the native presets — pick **Safe Auto** there to enable it for the current session, and pick any native preset to disable it again. Nothing is automatic until you do: no session inherits activation, and restart, a permission change or uninstall revokes it. The plugin page only holds reviewer configuration, safety notes and the read-only budget limits, grouped into tabs.
69
24
 
70
- The optional deep stage is independently configurable, including while the primary reviewer follows the conversation:
25
+ > The composer permission control is a replacement slot: while Safe Auto is installed, the plugin renders that control itself (native presets included) so the option can appear in the menu. If the host redesigns this control, the plugin's copy may lag behind until updated.
71
26
 
72
- ```yaml
73
- deepProvider: your-deep-review-provider
74
- deepModel: your-deep-review-model
75
- ```
27
+ ## How it works
76
28
 
77
- Only a fast `review` decision invokes it. Both deep fields empty means no deep model; uncertainty is rejected in independent approval mode. Legacy exact-rule mode retains human handling in smart mode and rejection in unattended mode. There is no second implicit call to the conversation model. Native provider/model fields must be configured in pairs.
29
+ 1. A native tool call asks for `sandbox_permissions` widening (`workspace-write` or `danger-full-access`).
30
+ 2. The plugin binds the live execution — agent, callId, signal, exact arguments, cwd, sandbox policy and the ordered direct-human instructions, including later restrictions and revocations.
31
+ 3. A fully literal `bash` command is granted without evidence or a model only when every invocation matches an exact positive grammar: case-sensitive POSIX program names, supported flags and values, input-only operand counts, safe redirects and bounded environment prefixes. Unknown options, abbreviations, clusters, output operands and assignment-only statements continue to review. Ordinary reads such as `ls -la`, `cat input | jq .name`, `grep -rn pattern src`, `find . -name "*.md"` and `ps aux` retain this fast path; `pwsh` does not.
32
+ 4. The exact request is reviewed once. For shell calls, bounded workspace package definitions and referenced local scripts provide untrusted evidence; their canonical paths and content are rechecked before granting.
33
+ 5. A reviewed pass returns `allowed-once`. For an otherwise eligible action, model denial, uncertainty, failure or budget exhaustion opens a timed confirmation. The dialog shows the exact operation, requested permission, reviewer opinion and countdown. Explicit approval grants this call after another binding/evidence check; rejection or expiry returns `rejected`. Closing the dialog rejects. No downstream approval answerer is consulted.
78
34
 
79
- ### Independent HTTP endpoint (RC2-compatible)
35
+ Native prohibitions, structural refusals, changed evidence, cancellation and invalidated requests cannot be overridden. Timed confirmation requires the UI row and an authenticated browser client; without them, or with the timeout set to zero, the existing non-grant path remains. Headless sessions do not gain an automatic fallback.
80
36
 
81
- ```yaml
82
- endpoint: https://your-trusted-gateway.example/v1/chat/completions
83
- fastModel: your-http-review-model
84
- # deepModel: your-http-deep-model
85
- apiKeyEnv: DSH_SAFE_AUTO_API_KEY
86
- ```
87
-
88
- `endpoint` is the complete OpenAI-compatible Chat Completions URL. This explicit endpoint uses the existing HTTP transport, including compatible lapp gateways; omit `fastProvider` and `deepProvider`. Combining native providers with an HTTP endpoint is rejected rather than guessed. Only this mode reads the named API key environment variable. HTTPS is required except loopback HTTP; redirects, URL credentials, query and fragment are rejected. To restore following, clear the endpoint and its fast model, not just the endpoint.
37
+ The reviewer sees the bounded action, chronological direct-human instructions and local evidence, with no main-agent prompt, private reasoning or tools. Authorization is judged by substance: necessary local installation, build and test steps may implement a requested development task without the user naming every command. Earlier authority remains visible after a progress question or “continue”; later restrictions still apply. Automatic allowance requires low/medium risk, medium/high authorization and bounded side effects.
89
38
 
90
- Both ordinary preflight and one-shot escalation use the selected reviewer. Routes are snapshotted for each review, and a change during an outstanding native review invalidates automatic allowance; the final guards recheck the route. Removing the model service leaves the policy guards installed, and switching models does not reset budgets. Explicit denials remain denials even if the route or user authority changes. Ordinary reviewed grants are bound before review to the action, workspace, sandbox policy and direct-user authority; the final guard rejects a stale grant after downstream policy completes.
39
+ Human text is retained without lossy selection, up to 12 KiB. Sensitive text, nontext constraints or overflow prevent automatic review rather than silently dropping restrictions; an otherwise valid action can receive fresh explicit confirmation through the timed UI without sending that history to the model. Evidence is capped at eight files, 6 KiB per file and 12 KiB overall. Protected, escaped, sensitive or unreadable files are withheld with explicit omission markers. Evidence coverage is partial: dependencies, imported code and workspace-wide scripts are not exhaustively inspected. Material remaining uncertainty prevents automatic permission.
91
40
 
92
- ## Policy and one-shot escalation
41
+ ## Configuration
93
42
 
94
- The following exact-rule smart-mode behavior is retained for compatibility (`approvalReview: false`); it is not the independent approval fallback policy.
43
+ Everything is optional; with no configuration the reviewer follows the current conversation's model. Edit the profile row's `config` and reload:
95
44
 
96
- | Action | Smart behavior |
97
- | --- | --- |
98
- | Ordinary `read/read_image/write/edit` in an enrolled workspace | Deterministic pass to existing policy; no reviewer call |
99
- | Protected credentials/security configuration or selected dangerous programs | Hard denial, including escalation |
100
- | Exact enrolled simple `shell/bash` command | Reviewer, within the operator envelope only |
101
- | Exact separately enrolled native `write/edit` or eligible `bash` escalation | Review at native `approval/request`; a fresh allow returns `allowed-once` |
102
- | Unenrolled, unsupported or ambiguous operation | Native human approval; unattended rejects |
103
- | Explicit model denial | Rejected, no semantic retry |
104
- | Cancellation, binding mismatch or changed authority | No automatic grant |
105
-
106
- `escalationCandidates` defaults to `[]`. Ordinary `shellCandidates` do not authorize widening. Register exact rules separately:
107
-
108
- ```yaml
109
- escalationCandidates:
110
- - tool: write
111
- cwd: /absolute/canonical/project
112
- mode: danger-full-access
113
- filePath: /absolute/other-project/notes.txt
114
- - tool: edit
115
- cwd: /absolute/canonical/project
116
- mode: danger-full-access
117
- filePath: /absolute/other-project/notes.txt
118
- - tool: bash
119
- cwd: /absolute/canonical/project
120
- mode: danger-full-access
121
- command: git status --short
122
- escalationApprovalTtlMs: 30000
123
- escalationMaxTimeoutMs: 30000
124
- ```
125
-
126
- Rules require exactly tool/cwd/mode and filePath or command. No prefixes, globs or directory grants. Native DSH requests use `sandbox_permissions: danger-full-access` with `justification`, not Codex's `require_escalated`. Only widening from Workspace Write is supported. File targets must be absolute and canonical, with existing parents; links, hard-linked writes, protected/system targets and unknown arguments do not get automatic approval. The reviewer receives complete bounded file-write/edit arguments, including content, or refuses oversized/sensitive inputs without truncating them.
45
+ | Key | Default | Meaning |
46
+ | --- | --- | --- |
47
+ | `enabled` | `true` | Master switch. `false` mounts nothing. |
48
+ | `provider` / `model` | *(follow conversation)* | Fixed reviewer route, configured as a pair using your DSH model IDs. |
49
+ | `reasoningEffort` | *(model default)* | Advertised reasoning effort of the fixed route. |
50
+ | `reviewerPrompt` | *(none)* | Extra review constraints (≤4096 chars); may only restrict, never widen. |
51
+ | `timeoutMs` | `30000` | Per-review deadline. |
52
+ | `humanApprovalTimeoutMs` | `60000` | Human confirmation window, separate from model review; `0` disables it. Maximum 300000 ms; profile-owned. |
53
+ | `maxInputBytes` | `32768` | Combined UTF-8 prompt/input cap; existing explicit values are retained. |
54
+ | `outputTokens` | `1024` | Reviewer output cap, including reasoning where the model counts it. Explicit profile values are retained; incomplete or invalid verdicts still require human confirmation. |
55
+ | `maxReviewsPerTask` | `20` | Review calls per direct user task. |
56
+ | `consecutiveDenials` | `3` | Consecutive explicit denials before the breaker opens. Uncertainty and failures reset the streak but still consume review reservations. |
57
+ | `staticReadonly` | `true` | Grant provably read-only `bash` escalations without a model call. `false` sends everything to the reviewer. |
127
58
 
128
- **Automatic Bash escalation requires no `jobs` service**, a visible sandbox-capable shell, false/omitted `run_in_background`, an explicit positive `timeoutMs` within the configured limit, and no workdir change. A jobs-enabled DSH profile can promote even a foreground call after timeout. Such requests stay manual or are rejected in unattended mode; the plugin never silently disables jobs. Neither a timeout nor one-shot approval proves that arbitrary descendants cannot outlive the call.
59
+ Unknown keys fail validation rather than being ignored. Reviewer model, effort and prompt can also be set per deployment on the plugin page; those saved values override the profile route but never the budgets.
129
60
 
130
- The native tool consumes the grant; the plugin does not execute the command itself. Async context and opaque execution tokens bind the exact agent, call, signal, arguments, cwd, policy, user intent and filesystem state. Concurrent identical call IDs cannot borrow a grant. One execution consumes one approval slot; no cross-call grant cache exists. `escalationApprovalTtlMs` limits decision freshness, not process lifetime, revocation or rollback. Expiry asks a human or denies; side effects are not undone. See [ADR-0002](docs/ADR-0002.md) for the complete execution contract.
61
+ ## The reviewer model
131
62
 
132
- ## Modes and composition
63
+ **Default: follow the conversation.** Leave `provider`/`model` empty. Each review resolves the provider/model from the requesting session's accepted request header, reusing DSH's configured credentials — no extra API key. Only the model route is inherited, not history, prompt, tools or budgets.
133
64
 
134
- The following legacy mode behavior is retained with `approvalReview: false`. Active independent approval rejects unknown/unbound requests and every non-allowing verdict, error, timeout, budget exhaustion or invalidation, without human or downstream fallback.
65
+ **Fixed model.** Set `provider` and `model` together to pin a reviewer that stays put when the conversation switches models. A missing or invalid route rejects instead of falling back silently.
135
66
 
136
- `off` installs nothing. `shadow` observes ordinary candidates without protecting execution; **enrolled ordinary commands can now use the conversation model even without an explicit endpoint**, and consume reviewer tokens. Shadow escalation remains native/manual without automatic review. Empty candidate lists make no model requests on installation. `smart` enforces policy and sends uncertainty to native human approval. `unattended` can grant eligible reviewed one-shot escalations but rejects uncertainty and other approval requests.
67
+ ## Policy
137
68
 
138
- Native `approval: never` rejects before any answerer. For automatic escalation, keep native approval at `ask` even with plugin `unattended`; `ask` dispatches to an answerer, not necessarily a human. Missing native approval services fail closed. Ordinary passes call `next()`, preserving other policy denials and prompts. Never stack this with official experimental Auto, Autogate or another auto-answerer. Legacy rule-mode human fallback assumes the downstream native human channel; active independent approval never uses that fallback.
69
+ | Request | Outcome |
70
+ | --- | --- |
71
+ | Bound single escalation of `write`/`edit`/`bash`/`pwsh`, reviewer passes | `allowed-once`, this call only |
72
+ | Bound `bash` escalation proven read-only by the strict static parse | `allowed-once`, no model call, no budget consumed |
73
+ | Protected credentials/security files, secrets, dangerous programs (anywhere in a fully parsed command) | Hard denial before review |
74
+ | Model denial (including risk opinions), uncertainty or review failure for an eligible action | Timed human confirmation; no grant without explicit approval |
75
+ | Unknown tools, subagents, nested or unbound requests | No automatic grant |
76
+ | Human rejection or confirmation expiry | Rejected; fresh execution needs fresh review |
77
+ | Changed evidence, invalidated grants, audit failure or cancellation | No grant; terminal feedback |
139
78
 
140
- ## Budgets and privacy
79
+ Native `approval: never` still rejects before any answerer. Never stack this with another automatic approval answerer.
141
80
 
142
- | Setting | Default | Meaning |
143
- | --- | --- | --- |
144
- | `timeoutMs`, `maxInputBytes` | `8000`, `8192` | Per-stage deadline and combined UTF-8 prompt/input cap |
145
- | `fastOutputTokens`, `deepOutputTokens` | `64`, `256` | Explicit native `maxTokens` or HTTP output caps |
146
- | `tokenField` | `max_tokens` | HTTP only; alternatively `max_completion_tokens` |
147
- | `fastCallsPerTask`, `deepCallsPerTask` | `20`, `3` | Atomic logical-review reservations per direct user task |
148
- | `sessionBudgetUnits` | `100000` | Prompt bytes + output cap + 1024 reserved per stage |
149
- | `consecutiveDenials`, `totalDenials` | `3`, `20` | Non-allowing review/error fuse per task/session |
81
+ ## Migrating from 0.1.x
150
82
 
151
- Fast JSON is `allow/review/deny`; deep JSON is `allow/ask/deny`. Extra fields, invalid JSON, tool calls, missing finish or output truncation cannot grant. Both transports have bounded responses, including native reasoning text, and an outer cancellation/timeout deadline. No plugin-level transport or semantic retry is added. Native adapters/middleware remain host-controlled and may implement their own transport policy; reservations count logical reviews, not every downstream wire attempt.
83
+ - Profile keys `mode`, `workspaceRoots`, `shellCandidates`, `escalationCandidates`, `endpoint`, `apiKeyEnv`, `tokenField`, `fast*`/`deep*` and the budget fuses `sessionBudgetUnits`/`totalDenials` were removed; a profile still carrying them fails validation. The equivalent of 0.1.x `approvalReview: true` plus a UI-enabled session is now the only behavior.
84
+ - `fastProvider`/`fastModel`/`fastReasoningEffort` became `provider`/`model`/`reasoningEffort`; `fastOutputTokens` became `outputTokens`; `fastCallsPerTask` became `maxReviewsPerTask`.
85
+ - Settings saved by the 0.1.x panel keep loading (retired keys are stripped), but the reviewer route falls back to following the conversation — re-pick a model on the plugin page if you had a fixed one.
152
86
 
153
- Only the action and latest direct human text are supplied. No main transcript, assistant reasoning or tool results are copied. Descriptions and justifications do not authorize actions. Secret detection is heuristic; following a model or configuring a remote reviewer sends bounded review inputs to that provider, including file contents for escalation. Fixed routes never silently change data destinations on failure.
87
+ ## Boundaries and limits
154
88
 
155
- Preflight and escalation share a session ledger, reserved before I/O with no error refunds. Usage counts include DSH's disjoint cache counters when reported. Reservations are not exact billable tokens, currency limits or a cap on the main agent. Providers must honor limits. New direct user messages reset task counters but not session totals; model changes reset neither; plugin reload/restart resets in-memory counters. The fuse stops more reviews, not the whole agent loop.
89
+ - **Not an audited boundary.** The reviewer is a language model and can be wrong, especially in adversarial contexts. Keep the native sandbox, isolation and backups you already rely on.
90
+ - **Static proof assumes operator-trusted PATH and runtimes.** It checks the original command text, not installed binary identity, shell functions or ambient runtime integrity. Explicit executable paths, `.exe`/`.cmd` suffixes, case variants, executable pager/config environment prefixes and persistent assignments do not qualify. Parser or grammar defects can produce incorrect proofs; this is not a runtime attestation or an absolute safety guarantee. An unproven command returns to reviewer/manual confirmation, not a new hard refusal.
91
+ - **Quoting does not bypass hard refusals.** Literal argv, environment and redirect values are decoded before the protected-path/secret checks, including adjacent quote fragments. These checks also apply outside the static path and cannot be overridden by reviewer or manual confirmation. Unquoted wildcard fragments still invalidate proof even next to quoted text. Bash `/dev/tcp` and `/dev/udp` file redirects return to review, including quoted and numbered-fd input redirects; ordinary file input, fd merges and `/dev/null` output retain their existing rules.
92
+ - **Git is not read-only by subcommand name.** Bare `git status`, worktree diffs, `git ls-files --modified` and other content-checking worktree operations remain under review because refresh/conversion can execute configured clean/process filters. Supported object/index reads require the original `--no-pager --no-optional-locks --no-lazy-fetch -c core.fsmonitor=false`; cached/staged diff also requires `--no-ext-diff --no-textconv --ignore-submodules=all`. History reads additionally need `--no-show-signature` and a supported fixed format such as `--oneline`. The plugin never prepends controls or rewrites argv. Exact `git version` and `git --no-pager config --get user.name` are narrow independent reads; transport helpers, editors, filters and mixed config mutations do not qualify. Ordinary `sort` can spill to temporary files, so only its check mode qualifies.
93
+ - **Dedicated confirmation channel.** Pinned DSH 0.2.0-rc.2 approval and question waterfalls accept automatic answerers. Manual confirmation instead uses the plugin's authenticated browser HTTP endpoints and unpredictable single-use request IDs. Fetch metadata and host origin/authentication checks protect the browser channel against cross-site requests; they do not prove physical human action. Authenticated clients, their transport and same-process plugins remain trusted. No model tool is registered for approval.
94
+ - **Server-owned expiry.** The window starts when a pending request is published. The server uses a monotonic deadline and atomically accepts the first valid answer; duplicate, late or cross-session answers fail. Disabling, changing settings, unloading or cancelling invalidates pending requests. Requests are in memory only, so restarts do not restore them. Both direct browser requests and the authenticated DSH desktop carrier are supported; incompatible request metadata is rejected.
95
+ - **Foreign native approvals remain native.** Blueprint order and Classmates model approvals continue to downstream answerers when no Safe Auto-owned execution context exists. Requests in an owned context, including mismatches, stale/claimed requests, and unbound impersonation of `bash`/`pwsh`/`write`/`edit`, remain fail-closed.
96
+ - **Coverage stops at native single-call escalation.** Only `write`/`edit`/`bash`/`pwsh` widening from `workspace-write` is reviewed. Other tools, MCP, remote execution, subagent calls and standing permission changes stay outside the automatic envelope.
97
+ - **Evidence is checked, execution is not atomic.** Evidence paths, versions and SHA-256 digests are revalidated before granting, but files can still change between approval and execution. Other same-process plugins remain trusted; unloading removes the guards. Keep external isolation with restricted credentials and egress.
98
+ - **No guarantee is claimed.** There is no fail-open option, no durable audit database and no claim of absolute safety or savings.
156
99
 
157
100
  ## Verification
158
101
 
159
- Run `npm test`, `npm run build` (JavaScript syntax checks plus the browser bundle, not TypeScript checking), and `npm pack --dry-run` in this package, plus repository `pnpm check`. Tests cover routing, concurrent sessions, native streams, caps, stale decisions, model service removal, preflight/escalation binding, real loopback HTTP, and real Cordis/ToolRuntime/ApprovalService/LlmRuntime contracts. CI requires installed DSH dependencies; offline source-only tests may explicitly skip native contracts. POSIX-only file and escalation grant cases are explicitly skipped on Windows, while Windows tests assert fail-closed behavior; native model routing still runs. If the Windows sandbox blocks the test runner's subprocess pipes, run each test file separately with `node --test --test-isolation=none test/<file>.test.js`.
160
-
161
- The native test uses a controlled adapter and fixture session/tool/policy. It proves runtime integration, not live model accuracy, OS isolation or authenticated Web/Headless acceptance. These remain in [ADR-0002's checklist](docs/ADR-0002.md). Logs separate assessment, escalation outcome and final result without raw commands/prompts/keys; host retention is operator-managed.
162
-
163
- ## Boundaries and limits
102
+ Run `npm test`, `npm run build` and `npm pack --dry-run` in this package, plus repository `pnpm check`. Tests cover routing, concurrent sessions, native streams, caps, stale decisions, model service removal, execution binding, and real Cordis/ToolRuntime/ApprovalService/LlmRuntime contracts. CI requires installed DSH dependencies; offline source-only runs may skip the native contracts. If the Windows sandbox blocks the test runner's subprocess pipes, run each test file separately with `node --test --test-isolation=none test/<file>.test.js`.
164
103
 
165
- - **Not an audited boundary.** The exact-rule path (local POSIX/native-tool candidates) and independent approval mode (Windows native escalation included) are candidates, not an independently audited security boundary. Start with `shadow`, and keep the native sandbox providers, isolation and backups you already rely on.
166
- - **Human approval is not a fallback for independent review.** It remains available only in legacy rule mode or when independent approval is inactive.
167
- - **Exact rules are not a finer OS sandbox.** DSH `workspace-write` governs file effects, not network egress or all secret reads, and an approved `danger-full-access` call genuinely bypasses the DSH file sandbox.
168
- - **Exact rule mode does not enlarge the operator envelope.** With `approvalReview: false`, empty candidate lists authorize no model grants; Windows file auto-passes and exact-rule PowerShell escalation remain unsupported. Independent approval mode requires an explicit saved choice and session activation, as described above.
169
- - **Coverage stops at native single-call escalation.** `grep/glob`, PTC, MCP, remote execution and subagent model grants stay outside the automatic envelope, as does widening from read-only to workspace-write. Exact-rule mode also excludes PowerShell and complex shell; independent native approval mode can review them, but missing decisive script evidence is rejected.
170
- - **Enrolled content is not pinned and other plugins stay trusted.** Tests, builds, installation and Git hooks can run repository-controlled code and are not inherently safe; enrollment does not pin executable contents. Trusted same-process plugins and execution providers remain trusted, and unloading a policy removes its guards. Path rechecks cannot eliminate OS TOCTOU, so use external isolation with restricted credentials and egress.
171
- - **No guarantee is claimed.** There is no fail-open option, no read-only investigation tool and no claim of full Codex parity. No durable budget/audit database, cross-call grant cache or PI probe is bundled, and no absolute safety or savings percentage is claimed.
104
+ The native contract tests use controlled adapters and fixture sessions/tools. They prove runtime integration, not live model accuracy, OS isolation or authenticated Web/Headless acceptance; those remain in [ADR-0002's checklist](docs/ADR-0002.md). Logs separate assessment, outcome and final result without raw commands, prompts or keys; host retention is operator-managed.
172
105
 
173
106
  ## License
174
107
 
package/README.zh-CN.md CHANGED
@@ -1,162 +1,108 @@
1
1
  # 安全自动(候选版)
2
2
 
3
- 在明确登记的范围内自动审核并批准单次原生沙箱提权,**审批模型默认跟随当前对话,也能单独指定 provider/model,或继续使用独立 HTTP 端点**。复用 DSH 原生工具循环、模型适配器和审批服务;不会把整个会话切成 Full Access,模型只能缩小规则给定的权限范围。
3
+ 自动审核原生沙箱提权请求。当真实的 `write`/`edit`/`bash`/`pwsh` 调用要求把沙箱放宽到 Workspace Write 之外时,由独立审核模型把关这一次调用——内置静态证明能判定为只读的 `bash` 命令除外,它们不调模型直接放行。通过就自动继续;其他审核结果会在当前会话显示完整操作,给你 60 秒选择“仅批准这一次”或拒绝。无人响应则到期拒绝。插件不会把整个会话切成 Full Access。
4
4
 
5
- [English](README.md) · [预检](docs/ADR-0001.md) · [单次提权](docs/ADR-0002.md) · [审批模型路由](docs/ADR-0003.md)
5
+ [English](README.md) · [单次提权](docs/ADR-0002.md) · [审核模型路由](docs/ADR-0003.md) · [授权与证据](docs/ADR-0004.md) · [限时人工确认](docs/ADR-0005.md) · [静态 Shell 证明](docs/ADR-0006.md)
6
6
 
7
- ## 安装与默认配置
7
+ > **0.2.0 是破坏性简化。** 0.1.x 的精确规则预检、workspace/shell/escalation 候选名单、`shadow`/`smart`/`unattended` 模式、深度审核阶段和 HTTP 端点均已删除。见[从 0.1.x 迁移](#从-01x-迁移)。
8
8
 
9
- 在仓库检查通过后,向一次性测试 profile 安装本地包:
9
+ ## 安装与启用
10
10
 
11
11
  ```sh
12
- pnpm install --frozen-lockfile
13
- pnpm --filter @klarkxy/dsh-safe-auto test
14
- dsh plugin --profile web add ./plugins/dsh-safe-auto
15
- ```
16
-
17
- PR 不等于 npm 已发布。bundle 会插入 `dsh-safe-auto` 条目,通过 profile 补丁机制配置它的 `config`:
18
-
19
- ```yaml
20
- mode: shadow
21
- workspaceRoots:
22
- - /absolute/canonical/project
23
- shellCandidates:
24
- - git status --short
25
- # 模型字段不填,默认跟随本对话。
12
+ dsh plugin --profile <profile> add @klarkxy/dsh-safe-auto
26
13
  ```
27
14
 
28
- 工作区必须是规范绝对路径,与会话 cwd 和沙箱 root 完全相同。授权范围、候选命令、提权名单和预算仍通过 profile 配置,严格校验且修改后重载插件。
29
-
30
- ## 插件页启停与独立代审批
31
-
32
- **你做什么。** 在插件页 **替我审批** 区块选择活跃主会话并点击 **启用**。停用只关闭代审批,不修改会话原生权限。启用保留 **Workspace Write + ask**,不注册官方 Full Access Auto。打开页面、刷新、保存模型配置都不会自动启用会话。子会话、重启及 UI Host 卸载不继承启用状态。
33
-
34
- **插件做什么。** 新增 `approvalReview: true`(默认为 `false`),或在插件页审核模式选择 **独立模型替我审批** 并保存。这一模式参考 `dsh-approval-review@0.5.1` 的独立应答者原理,不要求 POSIX 精确候选命令;可以审核 Windows 原生 `pwsh` 以及 `bash/write/edit` 发出的真实单次沙箱提权请求。仅绑定当前工具执行的真实请求,不依据自由文本、同名 callId 或旧日志批准;启用独立审批时,未知工具、远程、嵌套、子代理、不完整参数及无法绑定当前执行的请求均拒绝。模型无工具,仅收到完整有界动作、当前直接用户意图和附加约束。
35
-
36
- 模型必须提供结构化风险、用户授权、有界范围和理由;只有低/中风险、至少中等直接授权且范围有界才可能自动批准。高/严重风险、不确定、证据不足的未知脚本、非法结果、模型错误、超时、预算不足及授权失效均直接拒绝;明确拒绝绝不回退给其他应答者。默认快速 64 token 可能不足以生成结构化结果,可通过 profile 调整预算;截断时不会放行。
37
-
38
- 此模式是对原生审批链的显式委托,不是任意操作授权;`approval: never` 仍在链前拒绝。插件页固定显示「无法自动判断时 → 直接拒绝」,该策略不可修改也不保存,因为尚未核验 DSH 的仅人工审批通道。调用 waterfall `next()` 可能到达其他自动应答者,不等于人工回退。独立审批的非允许结果不委托下游。旧版精确规则兼容行为不变。本次源码修改不会自动卸载已安装插件或发布新版本。
39
-
40
- ## 审核模型设置
41
-
42
- 新版 bundle 包含核心与 UI Host 两个条目;设置和会话操作统一位于插件页,不替换输入框原生权限菜单。启用操作使用宿主预设,不走官方 Full Access 的 `registerAuto()`;原生 `approval: never` 仍不可绕过。
43
-
44
- 在插件页 **安全自动设置** 中选择快速/深度审核模型、各自思考强度及最多 4096 字符的额外审核提示词。模型目录和档位来自宿主;快速模型为空表示跟随本会话,深审为空表示关闭。选新模型清空旧档位,未列出的已保存配置不会被静默替换。原生模型不支持指定档位时失败关闭。提示词只能增加审核条件,不能替换固定安全规则或扩大授权。保存不调用模型、不改变会话权限、不重置预算;会使未完成的旧授权失效。思考模型若需要更高输出预算,请在 profile 调整 `fastOutputTokens/deepOutputTokens`。HTTP 模式面板只读,仍保留 profile 配置,不支持原生思考档位。
45
-
46
- UI Host 条目 `dsh-safe-auto-ui` 使用 `storageDomain` 持久保存审核偏好,覆盖同名 profile 模型字段;不保存会话授权。启用状态仅属于当前活跃会话对象:切回原生选项、外部权限变更、重启或 UI Host 卸载都会关闭自动审核,分叉及子会话不继承。UI 接管后,旧版 profile 的 smart/unattended 不会自动启用未选择的会话;单独加载核心 Host 条目时保留旧配置模式。卸载 Client 后原生权限控件恢复。
47
-
48
- ## 审批模型可以单独设置
49
-
50
- ### 默认:跟随当前对话
51
-
52
- `endpoint`、`fastProvider`、`fastModel` 均留空。每次需要模型审核时,读取请求会话已经接受的 `requestHeader().config` 的 provider/model;尚无请求 header 才使用同一 Agent 的 options。存在但不完整的 header 不会偷偷回退。对话下一轮接受了新模型,后续审核随之更新;不同会话不会共用一个全局模型选择。
53
-
54
- 直接复用 DSH 对应 provider 的适配器和凭据,**不用再填一遍 API Key**。只继承模型路由,不继承聊天历史、主 Agent 提示词、工具权限、回放状态、思考档位或输出预算。审批仍是独立、无工具的模型请求,使用自身的提示和成本上限。需要大量推理 token 的模型可能要提高审批输出上限;无法支持的参数应失败关闭,不能丢掉限制后执行。
15
+ 使用源码检出安装:
55
16
 
56
- ### 独立指定 DSH 模型
57
-
58
- 在同一插件配置中成对设置,填写 DSH 已配置的实际 provider/model ID:
59
-
60
- ```yaml
61
- fastProvider: your-review-provider
62
- fastModel: your-small-review-model
17
+ ```sh
18
+ pnpm install --frozen-lockfile
19
+ pnpm --filter @klarkxy/dsh-safe-auto test
20
+ dsh plugin --profile <profile> add ./plugins/dsh-safe-auto
63
21
  ```
64
22
 
65
- 可以和对话完全不同;对话切换模型不会影响这个固定审批模型。清空两项恢复跟随。provider 不存在、模型不可用、凭据错误等在独立审批模式中直接拒绝;旧版精确规则模式保留原有人工或拒绝行为,**不静默改用对话模型或其他服务**。
23
+ bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。之后输入框的权限菜单里会在原生档位旁出现第四个选项——选择 **安全自动** 即为本会话启用,选回任意原生档位即停用。在此之前没有任何自动行为:会话不继承启用状态,重启、切换权限或卸载都会撤销它。插件页只保留审核配置、安全说明和只读的预算边界,按页签分区。
66
24
 
67
- 可选深审也可单独指定,包括主审批模型继续跟随对话的情况:
25
+ > 输入框的权限控件是替换型插槽:安装 Safe Auto 期间由插件自己渲染这个控件(包含原生档位),选项才能出现在菜单里。如果宿主以后重新设计这个控件,插件的副本在新版本跟进前可能落后。
68
26
 
69
- ```yaml
70
- deepProvider: your-deep-review-provider
71
- deepModel: your-deep-review-model
72
- ```
73
-
74
- 只有快速审核返回 `review` 才调用深审。两项均为空表示不开启深审,不会默认再调用一次对话模型。独立审批模式中不确定直接拒绝;旧版精确规则模式仍是 Smart 回人工、无人值守拒绝。原生路由的 provider/model 必须成对填写。
27
+ ## 工作原理
75
28
 
76
- ### 保留独立 HTTP 端点
29
+ 1. 原生工具调用请求 `sandbox_permissions` 提权(`workspace-write` 或 `danger-full-access`)。
30
+ 2. 插件绑定当前活跃执行——agent、callId、signal、完整参数、cwd、沙箱策略,以及按时间排序的真人指令,包含后续限制和撤销。
31
+ 3. 完全按字面解析的 `bash` 命令,只有每次调用都符合精确正向语法才会不收集证据、不调模型直接放行:区分大小写的 POSIX 程序名、支持的选项和值、只含输入的操作数数量、安全重定向和受限环境前缀。未知选项、缩写、未列出的短选项组合、输出文件操作数及仅赋值的语句继续审核。`ls -la`、`cat input | jq .name`、`grep -rn pattern src`、`find . -name "*.md"`、`ps aux` 等普通读取保留快速通道;`pwsh` 不走此通道。
32
+ 4. 审核模型审查一次完整请求。Shell 调用会补充有界的工作区包配置和所引用本地脚本作为非可信证据;放行前重新核对路径与内容。
33
+ 5. 审核通过返回 `allowed-once`。请求本身符合范围时,模型拒绝、不确定、故障或预算耗尽会进入限时人工确认。窗口显示完整操作、请求权限、审核意见和倒计时;明确批准后再次核对绑定及证据,只放行这一调用。拒绝、关闭窗口或超时返回 `rejected`,不交给下游审批器。
77
34
 
78
- RC2 的配置继续有效:
79
-
80
- ```yaml
81
- endpoint: https://your-trusted-gateway.example/v1/chat/completions
82
- fastModel: your-http-review-model
83
- # deepModel: your-http-deep-model
84
- apiKeyEnv: DSH_SAFE_AUTO_API_KEY
85
- ```
35
+ 宿主禁止、结构性拒绝、证据变化、取消或请求失效不能被覆盖。人工确认需要 UI 条目和已认证的浏览器客户端;没有界面或把人工超时设为零时,保持原来的不放行处理。Headless 会话不会获得自动回退权限。
86
36
 
87
- 这是完整 OpenAI-compatible Chat Completions URL,可接兼容 lapp 网关。此模式不要填写 `fastProvider/deepProvider`;与原生路由混填会报错。只有 HTTP 模式读取上述 API Key 环境变量。仅允许 HTTPS 或 loopback HTTP,拒绝重定向、URL 凭据、查询参数和 fragment。恢复跟随时要同时清空 endpoint 和 HTTP fastModel,不能只删 endpoint。
37
+ 审核模型看到有界动作、按时间排序的真人指令和本地证据,不继承主代理提示词、隐藏推理或工具。授权按实际含义判断:完成开发任务所需的本地安装、构建和测试可以属于已授权工作,无须用户逐条点名命令。询问进度或说“继续”不会丢掉先前授权,后续限制仍然有效。只有低/中风险、至少中等授权且副作用有界才自动放行。
88
38
 
89
- 普通预检和单次提权都使用这套选择。每次审核固定两阶段路由;审核期间模型变化会作废自动放行结果,最终 guard 再次核对。模型服务失效不会导致安全 guard 一并卸载。切换模型不重置预算;已经明确拒绝的操作也不会因为换模型或用户意图变化被改成可再次争取放行。普通模型预检也会在审查前绑定动作、工作区、沙箱策略和直接用户意图,并在下游策略结束后的最终 guard 中拒绝过期授权。
39
+ 真人文本完整保留,合计最多 12 KiB。敏感文本、非文本约束或超限会阻止自动审查,不会静默丢掉限制;请求本身有效时,仍可在限时窗口中明确批准当前完整操作,不把这段历史发给模型。证据最多八个文件、每个 6 KiB、合计 12 KiB;受保护、越界、敏感或不可读内容会被标记并排除。证据并非完整安全证明:不会穷举依赖、导入代码或整个 workspace 的脚本,仍有实质不确定性时不得自动放行。
90
40
 
91
- ## 默认行为与单次提权
41
+ ## 配置
92
42
 
93
- 以下为 `approvalReview: false` 的旧版精确规则兼容行为,不是独立审批的回退策略。启用独立审批时,未知或未绑定请求、不允许的结果、错误、超时、预算耗尽及授权失效均拒绝,不回人工或下游审批链。
43
+ 全部可选;不配置时审核模型跟随当前对话。编辑 profile 条目的 `config` 并重载:
94
44
 
95
- `off` 不安装策略。`shadow` 只观察,不保护执行;**登记了普通候选命令后,即使没有独立 endpoint,也可能使用对话模型产生审核费用**。提权在 Shadow 中仍交原生审批,不自动审查或批准。安装时候选列表默认全空,不自动产生审核请求。
96
-
97
- `smart` 对普通工作区 `read/read_image/write/edit` 做零模型检查,保留其他原生策略;受保护凭据、安全配置和部分危险命令硬拒绝。未知情况交人工。`unattended` 可以批准符合条件的单次提权,但不确定和其他审批需求均拒绝。
98
-
99
- `escalationCandidates` 与 `shellCandidates` 独立,普通命令候选不授予沙箱外权限,默认 `[]`。例如:
100
-
101
- ```yaml
102
- escalationCandidates:
103
- - tool: write
104
- cwd: /absolute/canonical/project
105
- mode: danger-full-access
106
- filePath: /absolute/other-project/notes.txt
107
- - tool: edit
108
- cwd: /absolute/canonical/project
109
- mode: danger-full-access
110
- filePath: /absolute/other-project/notes.txt
111
- - tool: bash
112
- cwd: /absolute/canonical/project
113
- mode: danger-full-access
114
- command: git status --short
115
- escalationApprovalTtlMs: 30000
116
- escalationMaxTimeoutMs: 30000
117
- ```
45
+ | 键 | 默认 | 含义 |
46
+ | --- | --- | --- |
47
+ | `enabled` | `true` | 总开关。`false` 不挂载任何守卫。 |
48
+ | `provider` / `model` | *(跟随对话)* | 固定审核路由,用你的 DSH 模型 ID 成对配置。 |
49
+ | `reasoningEffort` | *(模型默认)* | 固定路由 advertised 的思考强度。 |
50
+ | `reviewerPrompt` | *(无)* | 额外审核约束(≤4096 字符);只能收紧,不能放宽。 |
51
+ | `timeoutMs` | `30000` | 单次审查超时。 |
52
+ | `humanApprovalTimeoutMs` | `60000` | 独立于模型审查的人工确认窗口;`0` 关闭,最多 300000 ms,只在 profile 配置。 |
53
+ | `maxInputBytes` | `32768` | 提示词与输入合计的 UTF-8 字节上限;已有显式配置保持原值。 |
54
+ | `outputTokens` | `1024` | 审核输出上限,含模型计入的思考预算。已有 profile 显式值保持不变;不完整或无效结论仍需人工确认。 |
55
+ | `maxReviewsPerTask` | `20` | 每个真人任务的审查次数上限。 |
56
+ | `consecutiveDenials` | `3` | 连续明确拒绝达到该值后熔断。不确定和故障重置拒绝计数,但仍消耗审查预算。 |
57
+ | `staticReadonly` | `true` | 可证明只读的 `bash` 提权不调模型直接放行;`false` 则一律送审核模型。 |
118
58
 
119
- 每条规则只有 tool/cwd/mode 和 filePath 或 command 四项,不允许前缀、通配符或整个目录授权。原生 DSH 使用 `sandbox_permissions: danger-full-access` 加 justification,不是 Codex 的 require_escalated。当前只支持 Workspace Write 到单次 Full Access。文件目标要是规范绝对路径且父目录已存在;链接、硬链接写入、受保护/系统目标及未知参数不自动放行。write/edit 分别登记;完整有界内容交给 Reviewer,超长或命中敏感检测时不截断后批准。
59
+ 未知键会直接校验失败,而不是被忽略。审核模型、思考强度和提示词也可以在插件页配置;保存的值覆盖 profile 路由,但永远不覆盖预算。
120
60
 
121
- **Bash 自动提权要求没有 jobs 服务**、可确认的沙箱 shell、不请求后台、显式正数 timeoutMs 且不超过配置上限,workdir 不变。加载 jobs 的 DSH 可能把超时前台任务转后台;这种组合仍走人工或无人值守拒绝,不会偷偷关闭 jobs。超时和一次性批准不能证明所有派生进程都已经退出。
61
+ ## 审核模型
122
62
 
123
- 只在匹配的原生 approval/request 内返回 allowed-once,由原生工具消费,不自行执行或修改会话权限。批准绑定 opaque token、异步上下文、Agent、callId、signal、完整参数、cwd、权限模式、直接用户意图和文件状态。并发相同 callId 不能互借;每次执行只消费一次,无跨调用批准缓存。审批 TTL 是决定新鲜度,不是进程 TTL、撤销或回滚;操作副作用不会自动撤销。详见 [ADR-0002](docs/ADR-0002.md)。
63
+ **默认:跟随对话。** `provider`/`model` 留空。每次审查从请求会话已接受的请求头解析 provider/model,复用 DSH 已配置的凭据——不需要额外 API key。继承的只有模型路由,不包括历史、提示词、工具或预算。
124
64
 
125
- **原生 approval: never 优先拒绝所有审批。** 启用自动提权时,原生服务仍需设为 ask,即使插件模式是 unattended。ask 表示分发给审批者,不代表一定有人在线。缺少原生审批服务时不提权;普通放行调用 `next()`,保留下游的拒绝与提示。不要叠加官方 Auto、Autogate 或其他自动 answerer;旧版规则模式的人工 fallback 假定下游是原生人工通道,启用独立审批时不使用该回退。
65
+ **固定模型。** 成对设置 `provider` 和 `model`,对话切换模型时审核路由保持不变。路由缺失或非法时直接拒绝,不做静默回退。
126
66
 
127
- ## 成本与隐私
67
+ ## 策略
128
68
 
129
- | 设置 | 默认值 | 含义 |
130
- | --- | --- | --- |
131
- | `timeoutMs`、`maxInputBytes` | `8000`、`8192` | 每阶段超时与提示/输入合计 UTF-8 上限 |
132
- | `fastOutputTokens`、`deepOutputTokens` | `64`、`256` | 原生 `maxTokens` 或 HTTP 输出上限 |
133
- | `tokenField` | `max_tokens` | 仅 HTTP 模式,可选 `max_completion_tokens` |
134
- | `fastCallsPerTask`、`deepCallsPerTask` | `20`、`3` | 每个直接用户任务的逻辑审核预留次数 |
135
- | `sessionBudgetUnits` | `100000` | 提示字节数 + 输出上限 + 每阶段 1024 预留 |
136
- | `consecutiveDenials`、`totalDenials` | `3`、`20` | 单任务/单会话的非允许审核熔断 |
69
+ | 请求 | 结果 |
70
+ | --- | --- |
71
+ | 绑定的 `write`/`edit`/`bash`/`pwsh` 单次提权,审查通过 | `allowed-once`,仅此一次 |
72
+ | 严格静态解析可证明只读的 `bash` 提权 | `allowed-once`,不调模型、不耗预算 |
73
+ | 受保护的凭据/安全文件、密钥、危险程序(完整解析的命令中任何位置) | 审查前硬拒绝 |
74
+ | 符合请求范围的模型拒绝(含风险意见)、不确定或审查故障 | 限时人工确认;未明确批准就不放行 |
75
+ | 未知工具、子代理、嵌套或未绑定请求 | 不自动放行 |
76
+ | 人工拒绝或确认超时 | 拒绝;再次执行须重新审查 |
77
+ | 证据变化、请求失效、审计故障或取消 | 不放行并给出终止原因 |
137
78
 
138
- 快速返回 allow/review/deny,深审返回 allow/ask/deny。错误 JSON、额外字段、工具调用、缺失 finish 和截断不能批准;原生 reasoning 内容也受响应大小限制。插件不主动做传输/语义重试;宿主适配器或中间件可能有自身传输策略,预留计数是逻辑审核请求,不是所有底层 HTTP 尝试。
79
+ 原生 `approval: never` 仍在任何应答者之前拒绝。不要与其他自动审批应答者叠加使用。
139
80
 
140
- 仅发送动作和最近直接人类文本,不发送完整历史、主 Agent 推理或工具结果。justification 不是授权。敏感检测是启发式;选定或跟随远端 provider 会发送这些有界输入,文件提权包含内容。固定配置失效时不偷偷更换数据目的地。
81
+ ## 从 0.1.x 迁移
141
82
 
142
- 普通预检和提权共享网络前原子预算,失败不退额。sessionBudgetUnits 默认 100000,按提示 UTF-8 字节数 + 输出上限 + 1024 预留,不是精确账单或主 Agent 总成本。原生缓存计数按 DSH 的互斥计量合并。新用户消息只重置任务计数,换模型不重置;重载/重启仍会重置内存计数。熔断停止的是审核,不是整个 Agent 循环。
83
+ - profile 键 `mode`、`workspaceRoots`、`shellCandidates`、`escalationCandidates`、`endpoint`、`apiKeyEnv`、`tokenField`、`fast*`/`deep*` 以及熔断 `sessionBudgetUnits`/`totalDenials` 已删除;仍携带这些键的 profile 会校验失败。0.1.x 的 `approvalReview: true` 加插件页启用,现在就是唯一行为。
84
+ - `fastProvider`/`fastModel`/`fastReasoningEffort` 更名为 `provider`/`model`/`reasoningEffort`;`fastOutputTokens` 更名为 `outputTokens`;`fastCallsPerTask` 更名为 `maxReviewsPerTask`。
85
+ - 0.1.x 面板保存的设置仍可加载(废弃键会被剥离),但审核路由回退为跟随对话——如果你用过固定模型,请在插件页重新选择。
143
86
 
144
- ## 验证与剩余范围
87
+ ## 边界与限制
145
88
 
146
- 运行 npm test、npm run build(JavaScript 语法检查与浏览器 bundle 构建,不是 TypeScript typecheck)、npm pack --dry-run 和全仓 pnpm check。测试包括路由/并发/失效/取消,以及真实 DSH LlmRuntime、ToolRuntime、ApprovalService 和受控适配器集成。CI 必须运行真实 DSH tests;缺依赖的离线本地环境可以明确跳过。Windows 上显式跳过 POSIX 专用文件授权与提权用例,并验证失败关闭行为,原生模型路由测试仍运行。若 Windows 沙箱阻止测试运行器创建子进程管道,可逐文件执行 `node --test --test-isolation=none test/<file>.test.js`。
89
+ - **不是经过审计的安全边界。** 审核方是语言模型,可能出错,尤其在对抗性上下文中。保留你原本依赖的原生沙箱、隔离和备份。
90
+ - **静态证明以操作者信任 PATH 和运行时为前提。** 它检查原始命令文本,不核验已安装二进制、shell 函数或环境运行时的完整性。显式程序路径、`.exe`/`.cmd` 后缀、大小写变体、可执行 pager/配置环境前缀和会持久化的赋值都不符合条件。解析器或语法缺陷仍可能造成错误证明;这不是运行时认证,也不保证绝对安全。无法证明的命令回到审核/人工确认,不新增硬拒绝。
91
+ - **引号不能绕过硬拒绝。** 保护路径和秘密检查先读取解码后的字面参数、环境及重定向值,包括相邻引号片段拼接;退出静态通道时仍执行这些检查,模型或人工确认不能覆盖。引号旁的未引用通配符仍使静态证明失败。Bash 的 `/dev/tcp`、`/dev/udp` 文件重定向回到审核,包括引用过的路径及编号 fd 输入重定向;普通文件输入、fd 合并和 `/dev/null` 输出保留原有规则。
92
+ - **Git 的子命令名不能证明只读。** 裸 `git status`、工作区 diff、`git ls-files --modified` 及其他工作区内容检查继续审核,因为刷新和内容转换可能执行配置中的 clean/process filter。支持的对象/索引读取必须在原始参数中带 `--no-pager --no-optional-locks --no-lazy-fetch -c core.fsmonitor=false`;暂存区 diff 还需 `--no-ext-diff --no-textconv --ignore-submodules=all`。历史读取另需 `--no-show-signature` 和受支持的固定格式,例如 `--oneline`。插件不会补参数或重写命令。精确的 `git version`、`git --no-pager config --get user.name` 是独立的窄范围读取;传输 helper、编辑器、filter 和混合配置修改都不能走快速通道。普通 `sort` 可能写临时文件,因此只保留其检查模式。
93
+ - **独立确认通道。** 当前 DSH 0.2.0-rc.2 的审批和问答链允许自动应答器。人工确认改用插件已认证的浏览器 HTTP 入口和不可预测、单次使用的请求 ID。Fetch Metadata 与宿主的来源、认证检查用于防跨站请求,并不证明物理真人点击;已认证客户端、其传输层和同进程插件仍然可信。不向模型注册审批工具。
94
+ - **服务端掌握时限。** 请求发布后开始计时,用单调时钟判定到期,只接受第一个有效答案。重复、迟到和跨会话回答均失败。停用、修改设置、卸载或取消会使待审批失效;请求仅存内存,重启不会恢复。兼容直接浏览器请求与已认证的 DSH 桌面传输;不符合要求的请求类型仍会被拒绝。
95
+ - **其他插件的原生审批保持原生流程。** 没有 Safe Auto 自有执行上下文时,Blueprint 顺序审批、Classmates 模型审批会继续交给后续处理器。已有自有上下文中的不匹配、过期、已领取请求,以及无上下文却冒用 `bash`/`pwsh`/`write`/`edit` 的请求仍然关闭放行。
96
+ - **覆盖范围止于原生单次提权。** 只审核从 `workspace-write` 放宽的 `write`/`edit`/`bash`/`pwsh`。其他工具、MCP、远程执行、子代理调用和常驻权限变更都在自动范围之外。
97
+ - **证据会复核,执行并非原子操作。** 放行前复核证据路径、版本和 SHA-256 摘要,但审批与执行之间仍可能发生文件变化。同进程插件仍然可信,卸载会移除守卫;实际隔离仍依赖外部手段及受限的凭据与出站。
98
+ - **不作任何保证。** 没有 fail-open 选项,没有持久审计数据库,也不承诺绝对安全或节省比例。
147
99
 
148
- 受控模型和 fixture 的 session/tool/policy 不是在线模型准确率、OS 沙箱或 authenticated Web/Headless 验收。剩余清单在 [ADR-0002](docs/ADR-0002.md)。日志区分 assessment、escalation 和实际 result,不记录原始命令/提示/Key,留存由宿主管理。
100
+ ## 验证
149
101
 
150
- ## 边界与限制
102
+ 在本包运行 `npm test`、`npm run build` 和 `npm pack --dry-run`,以及仓库级 `pnpm check`。测试覆盖路由、并发会话、原生流、上限、过期决定、模型服务移除、执行绑定,以及真实 Cordis/ToolRuntime/ApprovalService/LlmRuntime 契约。CI 要求安装 DSH 依赖;离线纯源码运行可跳过原生契约。如果 Windows 沙箱拦截测试运行器的子进程管道,用 `node --test --test-isolation=none test/<file>.test.js` 逐文件运行。
151
103
 
152
- - **不是经过审计的安全边界。** 精确规则路径(本地 POSIX/native 工具候选)和独立审批模式(含 Windows 原生提权)都只是候选实现,未经独立安全审计。先用 `shadow`,并保留你原本依赖的原生沙箱、隔离与备份。
153
- - **人工审批不是独立审核的回退。** 它只存在于旧版规则模式或未启用独立审批时。
154
- - **精确规则不等于更细的 OS 沙箱。** DSH workspace-write 只约束文件效果,不是网络隔离或全面敏感读取防护;单次 Full Access 确实移除该次 DSH 文件沙箱。
155
- - **精确规则模式不扩大授权名单。** `approvalReview: false` 时,候选列表为空不产生模型自动批准,Windows 文件自动放行和 PowerShell 精确规则提权仍不支持。独立审批模式需明确保存选择并启用会话,适用范围见上节。
156
- - **覆盖范围止于原生单次提权。** PTC/MCP、远程、子代理模型提权和 `grep/glob` 仍在自动放行范围之外,read-only 到 workspace-write 的放宽同样未纳入。精确规则模式仍排除 PowerShell 和复杂 Shell;独立审批模式可以审查原生 Shell 提权,但缺少决定性脚本证据直接拒绝。
157
- - **登记内容不被固定,同进程插件仍受信任。** 测试、构建、安装和 Git hooks 可运行任意代码,命令登记不固定其未来内容;卸载策略会一并移除其 guard。可信同进程插件、工具和执行提供方仍属于信任基础。路径重查不能消除 TOCTOU;无人值守需额外隔离凭据与网络。
158
- - **不承诺任何保证。** 没有失败放行选项,不提供独立只读探针或 Codex 全功能等价保证;没有持久化预算/审计库、跨调用批准缓存或 PI probe,也不承诺绝对安全或固定节省比例。
104
+ 原生契约测试使用受控适配器和夹具会话/工具,证明的是运行时集成,不是真实模型准确率、OS 隔离或已认证的 Web/Headless 验收;这些仍在 [ADR-0002 的清单](docs/ADR-0002.md)中。日志分离评估、结果和最终状态,不含原始命令、提示词或密钥;宿主留存由运维管理。
159
105
 
160
106
  ## 许可证
161
107
 
162
- 原始实现使用 [SATA License 2.1](LICENSE),参考社区设计但未直接复制其代码。
108
+ 原创实现基于 [SATA License 2.1](LICENSE)。社区设计启发了本工作;未打包其代码。
package/docs/ADR-0001.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ADR-0001: bounded preflight, not an escalation auto-answerer
2
2
 
3
- Status: historical RC1 decision, partially superseded by [ADR-0002](ADR-0002.md) in `0.1.0-rc.2`.
3
+ Status: historical RC1 decision, partially superseded by [ADR-0002](ADR-0002.md) in `0.1.0-rc.2`. **The preflight mechanism itself (ordinary-command review, workspace/shell candidates, shadow/smart/unattended modes) was removed in `0.2.0-rc.0`**; only the execution-bound approval review of ADR-0002 remains.
4
4
 
5
5
  **The no-auto-escalation statements below describe RC1, not the current candidate.** RC2 adds separately enrolled, execution-bound native `allowed-once` approvals, including unattended mode, without changing standing sandbox policy. Use ADR-0002 and the current READMEs for configuration and deployment acceptance. The original decision is retained here as history.
6
6
 
package/docs/ADR-0002.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ADR-0002: native, execution-bound one-shot escalation
2
2
 
3
- Status: implemented in `0.1.0-rc.2`; automated contracts verified; live-profile acceptance pending.
3
+ Status: implemented in `0.1.0-rc.2`; automated contracts verified; live-profile acceptance pending. Since `0.2.0-rc.0` this execution-bound approval review is the plugin's only mechanism; the exact-rule candidate enrollment described below was removed along with preflight.
4
4
 
5
5
  This partially supersedes [ADR-0001](ADR-0001.md): its prohibition on returning `allowed-once` and blanket unattended escalation rejection were an RC1 limitation, not the final design. Ordinary preflight, explicit envelopes, bounded review, no global permission writes and conservative failure handling remain in force.
6
6
 
package/docs/ADR-0003.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ADR-0003: conversation-following and independent reviewer routes
2
2
 
3
- Status: implemented in RC3. This supersedes the HTTP-only routing statements in ADR-0001/0002, not their remaining execution restrictions or deployment acceptance gates.
3
+ Status: implemented in RC3. This supersedes the HTTP-only routing statements in ADR-0001/0002, not their remaining execution restrictions or deployment acceptance gates. **`0.2.0-rc.0` narrowed the routing surface to a single reviewer route** (`provider`/`model`/`reasoningEffort`, defaulting to the conversation): the deep stage, the HTTP transport and the fast/deep split described below were removed.
4
4
 
5
5
  ## Requirement
6
6