iterate-plugin 3.5.7 → 3.7.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 +97 -22
- package/README.zh-CN.md +79 -19
- package/dist/approval-gate.js +143 -23
- package/dist/atomic-fs.js +148 -17
- package/dist/config-loader.js +516 -35
- package/dist/config-write.js +83 -22
- package/dist/evidence.js +141 -87
- package/dist/file-lock.js +193 -0
- package/dist/index.js +61 -28
- package/dist/jobs.js +56 -11
- package/dist/live.js +54 -14
- package/dist/meta-review.js +132 -28
- package/dist/method-scope.js +31 -8
- package/dist/review-scope.js +32 -9
- package/dist/review.js +96 -17
- package/dist/session-hooks.js +61 -14
- package/dist/skill-prompt.js +396 -66
- package/dist/tools/checkpoint.js +85 -19
- package/dist/tools/config.js +44 -2
- package/dist/tools/context.js +22 -5
- package/dist/tools/decision-log.js +106 -28
- package/dist/tools/defense-events.js +90 -31
- package/dist/tools/defense-store.js +28 -3
- package/dist/tools/experience-bank.js +108 -43
- package/dist/tools/experience-store.js +54 -4
- package/dist/tools/fix.js +347 -119
- package/dist/tools/history.js +68 -14
- package/dist/tools/present.js +80 -0
- package/dist/tools/prune.js +150 -53
- package/dist/tools/quality-gate.js +52 -2
- package/dist/tools/quality-store.js +17 -1
- package/dist/tools/review.js +158 -7
- package/dist/tools/transcript.js +173 -36
- package/dist/tools/triage.js +67 -12
- package/dist/tools/validate.js +115 -24
- package/dist/transcript.js +267 -4
- package/dist/working-directory.js +114 -0
- package/lib/client.js +1912 -512
- package/lib/parse.js +1001 -103
- package/package.json +16 -9
- package/src/approval-gate.ts +160 -23
- package/src/atomic-fs.ts +152 -17
- package/src/client/i18n.ts +517 -0
- package/src/client/index.ts +1031 -369
- package/src/client/session-cache.ts +54 -0
- package/src/config-loader.ts +549 -36
- package/src/config-write.ts +108 -26
- package/src/evidence.ts +194 -92
- package/src/file-lock.ts +211 -0
- package/src/index.ts +60 -29
- package/src/jobs.ts +63 -12
- package/src/live.ts +50 -12
- package/src/meta-review.ts +151 -34
- package/src/method-scope.ts +31 -8
- package/src/review-scope.ts +33 -10
- package/src/review.ts +96 -17
- package/src/session-hooks.ts +60 -13
- package/src/skill-prompt.ts +396 -66
- package/src/tools/checkpoint.ts +81 -19
- package/src/tools/config.ts +44 -2
- package/src/tools/context.ts +25 -5
- package/src/tools/decision-log.ts +114 -23
- package/src/tools/defense-events.ts +87 -31
- package/src/tools/defense-store.ts +30 -3
- package/src/tools/experience-bank.ts +112 -44
- package/src/tools/experience-store.ts +54 -5
- package/src/tools/fix.ts +258 -20
- package/src/tools/history.ts +74 -15
- package/src/tools/present.ts +89 -0
- package/src/tools/prune.ts +154 -51
- package/src/tools/quality-gate.ts +57 -2
- package/src/tools/quality-store.ts +18 -1
- package/src/tools/review.ts +155 -6
- package/src/tools/transcript.ts +178 -36
- package/src/tools/triage.ts +70 -13
- package/src/tools/validate.ts +138 -32
- package/src/transcript.ts +279 -4
- package/src/types.ts +29 -1
- package/src/working-directory.ts +126 -0
package/src/session-hooks.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Wires the {@link decideApproval} policy gate to dsh's `tools/pre-execute`
|
|
5
5
|
* waterfall. This is the AUTHORITATIVE approval seam for destructive iterate
|
|
6
|
-
* tools (`iterate_fix` / `iterate_rollback` / `iterate_prune` with dryRun:false
|
|
6
|
+
* tools (`iterate_fix` / `iterate_rollback` / `iterate_prune` with dryRun:false
|
|
7
|
+
* / `iterate_config` with operation:"write"):
|
|
7
8
|
*
|
|
8
9
|
* - `allow` policy → the call runs.
|
|
9
10
|
* - `deny` policy → the call is refused (fail-closed), surfaced as an
|
|
@@ -13,11 +14,19 @@
|
|
|
13
14
|
* plus the human-readable reason) so durable
|
|
14
15
|
* projections can route it distinctly from a normal
|
|
15
16
|
* tool failure.
|
|
16
|
-
* - `ask` policy → return `{ kind: 'ask', reason }`;
|
|
17
|
-
* scheduler routes it through the
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* on the
|
|
17
|
+
* - `ask` policy → return `{ kind: 'ask', reason, displayReason }`;
|
|
18
|
+
* dsh's own scheduler routes it through the
|
|
19
|
+
* `approval` service (see
|
|
20
|
+
* `@deepseek-ai/dsh-user-approval`), which prompts
|
|
21
|
+
* the human and audits an approve/deny pair on the
|
|
22
|
+
* session. `reason` is the audited English summary;
|
|
23
|
+
* `displayReason` (dsh 0.2.x) is the localized
|
|
24
|
+
* prompt text. LANGUAGE RULE: human-facing text
|
|
25
|
+
* follows the project `language` (zh|en); every
|
|
26
|
+
* structured/durable field (deny reason,
|
|
27
|
+
* `info.reason`, decision-log entries, console
|
|
28
|
+
* logs) stays English so machine matchers never
|
|
29
|
+
* depend on a locale.
|
|
21
30
|
* - canceled → if the caller aborted the invocation before
|
|
22
31
|
* dispatch, return `{ kind: 'cancel' }` (the
|
|
23
32
|
* canonical 0.1.6-alpha.1 cancellation result) so a
|
|
@@ -31,13 +40,22 @@
|
|
|
31
40
|
*
|
|
32
41
|
* Safety properties:
|
|
33
42
|
* - Read-only tools and non-iterate tools are always allowed (the gate only
|
|
34
|
-
* inspects the
|
|
43
|
+
* inspects the four gated iterate toolnames, and of those only prune
|
|
44
|
+
* `dryRun:false` and `iterate_config` `operation:"write"` — a config read
|
|
45
|
+
* or a dry-run prune short-circuits to allow inside the policy gate).
|
|
46
|
+
* - The approval policy is read from the SESSION workspace whenever a
|
|
47
|
+
* session cwd is known — the model-controlled `path` argument can never
|
|
48
|
+
* choose where the human's policy comes from (it is only consulted when
|
|
49
|
+
* there is no session cwd at all). Otherwise `path:` could point at an
|
|
50
|
+
* `approval: allow` directory to self-grant, or dodge a `deny` in the
|
|
51
|
+
* workspace.
|
|
35
52
|
* - If the project root / observatory config cannot be resolved, the policy
|
|
36
53
|
* degrades to `ask` (fail-safe: destructive writes always require consent).
|
|
37
54
|
*/
|
|
38
55
|
|
|
39
56
|
import { loadEffectiveConfig, resolveProjectRoot } from './config-loader.ts'
|
|
40
57
|
import { decideApproval, isDestructiveIterateTool } from './approval-gate.ts'
|
|
58
|
+
import { sessionCwdOf } from './working-directory.ts'
|
|
41
59
|
import type { Context } from '@deepseek-ai/cordis'
|
|
42
60
|
import type { ToolErrorInfo, ToolExecution, PreToolDecision } from '@deepseek-ai/dsh-tools'
|
|
43
61
|
|
|
@@ -81,8 +99,14 @@ export function gateDecision(exec: ToolExecution): PreToolDecision {
|
|
|
81
99
|
return { kind: 'cancel' }
|
|
82
100
|
}
|
|
83
101
|
|
|
84
|
-
// Resolve the project root
|
|
85
|
-
//
|
|
102
|
+
// Resolve the project root whose observatory policy governs this call.
|
|
103
|
+
// SECURITY: the policy source must NOT be model-controlled. `path` is a
|
|
104
|
+
// model argument, so reading the policy from the path-resolved root let a
|
|
105
|
+
// call point `path:` at a directory with `approval: allow` (self-grant) or
|
|
106
|
+
// dodge a human's `deny` in the session workspace. When the session cwd is
|
|
107
|
+
// known, the SESSION workspace's config is authoritative and `path` is
|
|
108
|
+
// ignored; the path-resolved root is only the fallback when there is no
|
|
109
|
+
// session cwd at all (headless/tests). The `ask` default stays fail-closed.
|
|
86
110
|
let argPath: string | undefined
|
|
87
111
|
let sessionCwd: string | undefined
|
|
88
112
|
try {
|
|
@@ -91,21 +115,33 @@ export function gateDecision(exec: ToolExecution): PreToolDecision {
|
|
|
91
115
|
const p = (args as Record<string, unknown>).path
|
|
92
116
|
if (typeof p === 'string') argPath = p
|
|
93
117
|
}
|
|
94
|
-
|
|
118
|
+
// Effective session directory (see ./working-directory.ts): a session whose
|
|
119
|
+
// directory was switched via dsh 0.2.1-alpha.2's `working_directory` tool
|
|
120
|
+
// must have its POLICY read from the workspace it is now in — `header.cwd`
|
|
121
|
+
// alone would read the original project's approval policy.
|
|
122
|
+
sessionCwd = sessionCwdOf(exec)
|
|
95
123
|
} catch {
|
|
96
124
|
// hostile/proxied exec — fall through with both undefined (defaults to ask)
|
|
97
125
|
}
|
|
98
|
-
|
|
126
|
+
// Passing sessionCwd as BOTH the input and the anchor makes the root the
|
|
127
|
+
// session cwd itself (no server-cwd fallback can sneak in), anchored there.
|
|
128
|
+
const resolved = sessionCwd
|
|
129
|
+
? resolveProjectRoot(sessionCwd, sessionCwd)
|
|
130
|
+
: resolveProjectRoot(argPath, sessionCwd)
|
|
99
131
|
let policy: 'ask' | 'deny' | 'allow' = 'ask'
|
|
132
|
+
// Project language for the HUMAN-FACING ask prompt only (see the header's
|
|
133
|
+
// language rule: structured deny/audit text stays English).
|
|
134
|
+
let language: 'zh' | 'en' = 'en'
|
|
100
135
|
if (resolved.ok) {
|
|
101
136
|
const { config } = loadEffectiveConfig(resolved.root)
|
|
102
137
|
const p = config.observatory?.approval
|
|
103
138
|
if (p === 'deny') policy = 'deny'
|
|
104
139
|
else if (p === 'allow') policy = 'allow'
|
|
105
140
|
// anything else (including a corrupt/missing `ask`) → 'ask'
|
|
141
|
+
if (config.language === 'zh') language = 'zh'
|
|
106
142
|
}
|
|
107
143
|
|
|
108
|
-
const decision = decideApproval(exec, policy)
|
|
144
|
+
const decision = decideApproval(exec, policy, language)
|
|
109
145
|
if (decision.kind === 'deny') {
|
|
110
146
|
return {
|
|
111
147
|
kind: 'deny',
|
|
@@ -114,11 +150,19 @@ export function gateDecision(exec: ToolExecution): PreToolDecision {
|
|
|
114
150
|
...DENY_INFO,
|
|
115
151
|
// ToolErrorInfo.reason (0.1.6-alpha.1): raw user-facing detail kept in
|
|
116
152
|
// durable state; the model-facing text still only sees `reason` above.
|
|
153
|
+
// Deliberately the ENGLISH structured reason, never the localized
|
|
154
|
+
// prompt — durable projections must match on a stable string.
|
|
117
155
|
reason: decision.reason,
|
|
118
156
|
},
|
|
119
157
|
}
|
|
120
158
|
}
|
|
121
|
-
|
|
159
|
+
// dsh 0.2.x: `displayReason` is the localized prompt text (en + the
|
|
160
|
+
// configured locale); `reason` stays the audited English summary. Both are
|
|
161
|
+
// forwarded so the approval UI can show the full localized explanation
|
|
162
|
+
// (including the WARNING line for gate-disabling config writes).
|
|
163
|
+
if (decision.kind === 'ask') {
|
|
164
|
+
return { kind: 'ask', reason: decision.reason, displayReason: decision.displayReason }
|
|
165
|
+
}
|
|
122
166
|
return { kind: 'allow' }
|
|
123
167
|
}
|
|
124
168
|
|
|
@@ -139,6 +183,9 @@ export function registerSessionHooks(ctx: Context): void {
|
|
|
139
183
|
return Promise.resolve({
|
|
140
184
|
kind: 'ask',
|
|
141
185
|
reason: 'iterate approval gate unavailable — require consent',
|
|
186
|
+
// Fail-safe path: no config was read, so the localized prompt falls
|
|
187
|
+
// back to English (displayReason requires at least an `en` entry).
|
|
188
|
+
displayReason: { en: 'iterate approval gate unavailable — require consent' },
|
|
142
189
|
})
|
|
143
190
|
}
|
|
144
191
|
if (decision.kind === 'ask') {
|