dsh-plugin-pwsh7 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/LICENSE +21 -21
- package/README.md +219 -186
- package/README.zh.md +208 -176
- package/cordis.patch.yml +16 -16
- package/icon.svg +28 -28
- package/index.js +126 -126
- package/lib/executors/pwsh.mjs +20 -20
- package/lib/install.mjs +978 -978
- package/lib/paths.mjs +327 -327
- package/lib/shipped.mjs +115 -115
- package/lib/state.mjs +129 -129
- package/lib/status.mjs +187 -187
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +62 -60
package/lib/status.mjs
CHANGED
|
@@ -1,187 +1,187 @@
|
|
|
1
|
-
// Status and self-diagnosis for the Windows PowerShell 7 router.
|
|
2
|
-
//
|
|
3
|
-
// `status` is read-only: it resolves the pwsh executable, probes its version, and reports the
|
|
4
|
-
// current sandbox policy. `diagnose` actually runs commands through PowerShell 7 under the
|
|
5
|
-
// current policy, so a sandbox/grant problem is observed instead of guessed.
|
|
6
|
-
|
|
7
|
-
import { probePwsh } from './paths.mjs';
|
|
8
|
-
import { describeShippedResolution, shipped } from './shipped.mjs';
|
|
9
|
-
|
|
10
|
-
const MAX_OUTPUT_BYTES = 32_000;
|
|
11
|
-
const SPILL_BYTES = 4 * 1024 * 1024;
|
|
12
|
-
|
|
13
|
-
function readStream(reader) {
|
|
14
|
-
try {
|
|
15
|
-
const read = reader.readFrom(0);
|
|
16
|
-
return { text: read.text, truncated: read.lossy === true, spillPath: read.spillPath };
|
|
17
|
-
} catch (error) {
|
|
18
|
-
return { text: '', error: String(error instanceof Error ? error.message : error) };
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function currentPolicy(ctx, exec) {
|
|
23
|
-
const service = ctx.get('sandboxPolicy');
|
|
24
|
-
if (service === undefined) return undefined;
|
|
25
|
-
try {
|
|
26
|
-
const session = exec?.agent?.session;
|
|
27
|
-
return service.resolve(session === undefined ? {} : { session });
|
|
28
|
-
} catch {
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function currentCwd(ctx, exec) {
|
|
34
|
-
try {
|
|
35
|
-
const workingDirectory = ctx.get('workingDirectory');
|
|
36
|
-
if (workingDirectory !== undefined && exec?.agent !== undefined) {
|
|
37
|
-
return await workingDirectory.ensure(exec.agent, exec.signal);
|
|
38
|
-
}
|
|
39
|
-
const session = exec?.agent?.session;
|
|
40
|
-
if (workingDirectory !== undefined && session !== undefined) return workingDirectory.get(session);
|
|
41
|
-
} catch {
|
|
42
|
-
// Fall through to the process directory.
|
|
43
|
-
}
|
|
44
|
-
return process.cwd();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function spawnAndWait(ctx, argv, { cwd, signal, graceMs = 5000 }) {
|
|
48
|
-
const subprocess = ctx.get('subprocess');
|
|
49
|
-
if (subprocess === undefined) throw new Error('pwsh7-router: ctx.subprocess is not available');
|
|
50
|
-
const handle = subprocess.spawn({
|
|
51
|
-
argv,
|
|
52
|
-
cwd,
|
|
53
|
-
stdio: {
|
|
54
|
-
stdin: 'ignore',
|
|
55
|
-
stdout: { maxBytes: MAX_OUTPUT_BYTES, spill: { maxBytes: SPILL_BYTES } },
|
|
56
|
-
stderr: { maxBytes: MAX_OUTPUT_BYTES, spill: { maxBytes: SPILL_BYTES } },
|
|
57
|
-
},
|
|
58
|
-
graceMs,
|
|
59
|
-
...(signal === undefined ? {} : { signal }),
|
|
60
|
-
});
|
|
61
|
-
const outcome = await handle.done;
|
|
62
|
-
return {
|
|
63
|
-
exitCode: outcome.exitCode,
|
|
64
|
-
signal: outcome.signal,
|
|
65
|
-
stdout: readStream(handle.collected.stdout),
|
|
66
|
-
stderr: readStream(handle.collected.stderr),
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function terse(text, limit = 800) {
|
|
71
|
-
const normalized = String(text ?? '').replace(/\r\n/g, '\n').trim();
|
|
72
|
-
return normalized.length > limit ? `${normalized.slice(0, limit)}\n…` : normalized;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function runThroughExecutorPath(ctx, argv, { mode, policy, cwd, signal, label }) {
|
|
76
|
-
const record = { label, argv, mode, ok: false };
|
|
77
|
-
try {
|
|
78
|
-
let prepared;
|
|
79
|
-
let spawnArgv = argv;
|
|
80
|
-
if (mode !== 'danger-full-access') {
|
|
81
|
-
const sandbox = ctx.get('sandbox');
|
|
82
|
-
if (sandbox === undefined) throw new Error('pwsh7-router: ctx.sandbox is not available');
|
|
83
|
-
prepared = await sandbox.confine(argv, policy, signal ?? new AbortController().signal);
|
|
84
|
-
record.enforcement = prepared.enforcement;
|
|
85
|
-
spawnArgv = prepared.argv;
|
|
86
|
-
}
|
|
87
|
-
Object.assign(record, await spawnAndWait(ctx, spawnArgv, { cwd, signal }));
|
|
88
|
-
record.ok = record.exitCode === 0;
|
|
89
|
-
if (!record.ok && prepared !== undefined) {
|
|
90
|
-
try {
|
|
91
|
-
const sandbox = shipped('@deepseek-ai/dsh-sandbox');
|
|
92
|
-
record.denied = sandbox.matchesSignature(record.exitCode, record.stderr?.text ?? '', prepared.denialSignatures ?? []);
|
|
93
|
-
record.runnerFailure = sandbox.classifyRunnerFailure(record.exitCode, record.stderr?.text ?? '', prepared.runnerFailureRules ?? []);
|
|
94
|
-
} catch {
|
|
95
|
-
record.denied = false;
|
|
96
|
-
}
|
|
97
|
-
if (record.runnerFailure !== undefined) {
|
|
98
|
-
record.hint = `The Windows sandbox runner failed before the command ran (${terse(record.runnerFailure, 300)}). `
|
|
99
|
-
+ 'Run the bundled diagnose-windows-sandbox-acl skill against the workspace root, or switch this session to full access.';
|
|
100
|
-
} else if (record.denied) {
|
|
101
|
-
record.hint = `A file operation was denied under ${mode} mode. Writes are only expected inside the workspace`
|
|
102
|
-
+ (mode === 'read-only' ? ' and none are expected in read-only.' : '; use the tool\'s sandbox_permissions escalation for a genuinely wider need.');
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
} catch (error) {
|
|
106
|
-
record.error = String(error instanceof Error ? error.message : error);
|
|
107
|
-
if (/SetNamedSecurityInfoW|grantWrite|Win32 5/i.test(record.error)) {
|
|
108
|
-
record.hint = 'The Windows sandbox could not provision the workspace write grant. '
|
|
109
|
-
+ 'Run the bundled diagnose-windows-sandbox-acl skill on the workspace root, or switch this session to full access.';
|
|
110
|
-
} else if (/SANDBOX_UNAVAILABLE/i.test(record.error)) {
|
|
111
|
-
record.hint = 'No usable sandbox runner for this platform/mode, so the command was not run. '
|
|
112
|
-
+ 'Switching to full access or fixing the sandbox runner is required.';
|
|
113
|
-
} else if (/not found/i.test(record.error)) {
|
|
114
|
-
record.hint = 'Install PowerShell 7 with the shell_router tool (action "install").';
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return record;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** Human/model readable status, including the async version probe. */
|
|
121
|
-
export async function describeStatus(ctx, state, exec) {
|
|
122
|
-
const lines = [`pwsh7-router (${state.platform})`];
|
|
123
|
-
if (state.pwsh.found) {
|
|
124
|
-
const probe = await probePwsh(state.pwsh.path);
|
|
125
|
-
lines.push(`PowerShell 7: ${state.pwsh.path}${probe.ok ? ` (${probe.version})` : ' (probe failed)'}`);
|
|
126
|
-
if (!probe.ok && probe.output) lines.push(` probe output: ${terse(probe.output, 300)}`);
|
|
127
|
-
} else {
|
|
128
|
-
lines.push('PowerShell 7: NOT FOUND — run shell_router action "install" (per-user, no admin), set DSH_PWSH_PATH, or install manually.');
|
|
129
|
-
}
|
|
130
|
-
lines.push(`config: ${state.configPath}`);
|
|
131
|
-
if (Array.isArray(state.notes) && state.notes.length > 0) lines.push(`notes: ${state.notes.join('; ')}`);
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
const policy = currentPolicy(ctx, exec);
|
|
135
|
-
lines.push(`sandbox: ${policy === undefined ? 'unknown (no sandboxPolicy service)' : `${policy.mode} (workspace ${policy.workspaceRoot})`}`);
|
|
136
|
-
} catch {
|
|
137
|
-
lines.push('sandbox: unknown');
|
|
138
|
-
}
|
|
139
|
-
const shipped = describeShippedResolution();
|
|
140
|
-
lines.push(`shipped packages: ${shipped.ok ? 'ok' : `unavailable (${shipped.error})`}`);
|
|
141
|
-
return lines.join('\n');
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** Run PowerShell 7 commands under the current policy. */
|
|
145
|
-
export async function runDiagnosis(ctx, state, exec) {
|
|
146
|
-
const policy = currentPolicy(ctx, exec);
|
|
147
|
-
const mode = policy?.mode ?? 'unknown';
|
|
148
|
-
const cwd = await currentCwd(ctx, exec);
|
|
149
|
-
const results = [];
|
|
150
|
-
|
|
151
|
-
if (state.pwsh.found) {
|
|
152
|
-
results.push(await runThroughExecutorPath(
|
|
153
|
-
ctx,
|
|
154
|
-
[state.pwsh.path, '-NoLogo', '-NoProfile', '-NonInteractive', '-Command',
|
|
155
|
-
'$PSVersionTable.PSVersion.ToString(); $PSHOME; (Get-Location).Path'],
|
|
156
|
-
{ mode, policy, cwd, signal: exec?.signal, label: 'pwsh version' },
|
|
157
|
-
));
|
|
158
|
-
results.push(await runThroughExecutorPath(
|
|
159
|
-
ctx,
|
|
160
|
-
[state.pwsh.path, '-NoLogo', '-NoProfile', '-NonInteractive', '-Command',
|
|
161
|
-
'"ok" | Set-Content .pwsh7-write-probe -ErrorAction Stop; Remove-Item .pwsh7-write-probe -ErrorAction Stop; "workspace-write-ok"'],
|
|
162
|
-
{ mode, policy, cwd, signal: exec?.signal, label: 'pwsh workspace write' },
|
|
163
|
-
));
|
|
164
|
-
} else {
|
|
165
|
-
results.push({ label: 'pwsh', ok: false, error: 'PowerShell 7 not found', hint: 'Run shell_router action "install" or install PowerShell 7 manually.' });
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const hints = results.filter((record) => record.hint !== undefined).map((record) => record.hint);
|
|
169
|
-
const lines = [
|
|
170
|
-
`pwsh7-router diagnose (sandbox mode: ${mode}${mode === 'danger-full-access' ? ', commands run unconfined' : ''})`,
|
|
171
|
-
`cwd: ${cwd}`,
|
|
172
|
-
];
|
|
173
|
-
results.forEach((record, index) => {
|
|
174
|
-
const status = record.ok ? 'ok' : 'FAILED';
|
|
175
|
-
const exit = record.exitCode !== undefined && record.exitCode !== null ? ` (exit ${record.exitCode})` : '';
|
|
176
|
-
lines.push(`\n[${index + 1}] ${record.label}: ${status}${exit}`);
|
|
177
|
-
if (record.error !== undefined) lines.push(`error: ${terse(record.error)}`);
|
|
178
|
-
if (record.stdout?.text) lines.push(`stdout: ${terse(record.stdout.text)}`);
|
|
179
|
-
if (record.stderr?.text) lines.push(`stderr: ${terse(record.stderr.text)}`);
|
|
180
|
-
if (record.denied === true) lines.push('denied: yes');
|
|
181
|
-
if (record.runnerFailure !== undefined) lines.push(`runner failure: ${terse(record.runnerFailure, 300)}`);
|
|
182
|
-
if (record.hint !== undefined) lines.push(`hint: ${record.hint}`);
|
|
183
|
-
});
|
|
184
|
-
if (hints.length > 0) lines.push(`\nnext: ${hints[0]}`);
|
|
185
|
-
const ok = results.every((record) => record.ok === true);
|
|
186
|
-
return { ok, summary: lines.join('\n'), details: { mode, cwd, results } };
|
|
187
|
-
}
|
|
1
|
+
// Status and self-diagnosis for the Windows PowerShell 7 router.
|
|
2
|
+
//
|
|
3
|
+
// `status` is read-only: it resolves the pwsh executable, probes its version, and reports the
|
|
4
|
+
// current sandbox policy. `diagnose` actually runs commands through PowerShell 7 under the
|
|
5
|
+
// current policy, so a sandbox/grant problem is observed instead of guessed.
|
|
6
|
+
|
|
7
|
+
import { probePwsh } from './paths.mjs';
|
|
8
|
+
import { describeShippedResolution, shipped } from './shipped.mjs';
|
|
9
|
+
|
|
10
|
+
const MAX_OUTPUT_BYTES = 32_000;
|
|
11
|
+
const SPILL_BYTES = 4 * 1024 * 1024;
|
|
12
|
+
|
|
13
|
+
function readStream(reader) {
|
|
14
|
+
try {
|
|
15
|
+
const read = reader.readFrom(0);
|
|
16
|
+
return { text: read.text, truncated: read.lossy === true, spillPath: read.spillPath };
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return { text: '', error: String(error instanceof Error ? error.message : error) };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function currentPolicy(ctx, exec) {
|
|
23
|
+
const service = ctx.get('sandboxPolicy');
|
|
24
|
+
if (service === undefined) return undefined;
|
|
25
|
+
try {
|
|
26
|
+
const session = exec?.agent?.session;
|
|
27
|
+
return service.resolve(session === undefined ? {} : { session });
|
|
28
|
+
} catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function currentCwd(ctx, exec) {
|
|
34
|
+
try {
|
|
35
|
+
const workingDirectory = ctx.get('workingDirectory');
|
|
36
|
+
if (workingDirectory !== undefined && exec?.agent !== undefined) {
|
|
37
|
+
return await workingDirectory.ensure(exec.agent, exec.signal);
|
|
38
|
+
}
|
|
39
|
+
const session = exec?.agent?.session;
|
|
40
|
+
if (workingDirectory !== undefined && session !== undefined) return workingDirectory.get(session);
|
|
41
|
+
} catch {
|
|
42
|
+
// Fall through to the process directory.
|
|
43
|
+
}
|
|
44
|
+
return process.cwd();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function spawnAndWait(ctx, argv, { cwd, signal, graceMs = 5000 }) {
|
|
48
|
+
const subprocess = ctx.get('subprocess');
|
|
49
|
+
if (subprocess === undefined) throw new Error('pwsh7-router: ctx.subprocess is not available');
|
|
50
|
+
const handle = subprocess.spawn({
|
|
51
|
+
argv,
|
|
52
|
+
cwd,
|
|
53
|
+
stdio: {
|
|
54
|
+
stdin: 'ignore',
|
|
55
|
+
stdout: { maxBytes: MAX_OUTPUT_BYTES, spill: { maxBytes: SPILL_BYTES } },
|
|
56
|
+
stderr: { maxBytes: MAX_OUTPUT_BYTES, spill: { maxBytes: SPILL_BYTES } },
|
|
57
|
+
},
|
|
58
|
+
graceMs,
|
|
59
|
+
...(signal === undefined ? {} : { signal }),
|
|
60
|
+
});
|
|
61
|
+
const outcome = await handle.done;
|
|
62
|
+
return {
|
|
63
|
+
exitCode: outcome.exitCode,
|
|
64
|
+
signal: outcome.signal,
|
|
65
|
+
stdout: readStream(handle.collected.stdout),
|
|
66
|
+
stderr: readStream(handle.collected.stderr),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function terse(text, limit = 800) {
|
|
71
|
+
const normalized = String(text ?? '').replace(/\r\n/g, '\n').trim();
|
|
72
|
+
return normalized.length > limit ? `${normalized.slice(0, limit)}\n…` : normalized;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function runThroughExecutorPath(ctx, argv, { mode, policy, cwd, signal, label }) {
|
|
76
|
+
const record = { label, argv, mode, ok: false };
|
|
77
|
+
try {
|
|
78
|
+
let prepared;
|
|
79
|
+
let spawnArgv = argv;
|
|
80
|
+
if (mode !== 'danger-full-access') {
|
|
81
|
+
const sandbox = ctx.get('sandbox');
|
|
82
|
+
if (sandbox === undefined) throw new Error('pwsh7-router: ctx.sandbox is not available');
|
|
83
|
+
prepared = await sandbox.confine(argv, policy, signal ?? new AbortController().signal);
|
|
84
|
+
record.enforcement = prepared.enforcement;
|
|
85
|
+
spawnArgv = prepared.argv;
|
|
86
|
+
}
|
|
87
|
+
Object.assign(record, await spawnAndWait(ctx, spawnArgv, { cwd, signal }));
|
|
88
|
+
record.ok = record.exitCode === 0;
|
|
89
|
+
if (!record.ok && prepared !== undefined) {
|
|
90
|
+
try {
|
|
91
|
+
const sandbox = shipped('@deepseek-ai/dsh-sandbox');
|
|
92
|
+
record.denied = sandbox.matchesSignature(record.exitCode, record.stderr?.text ?? '', prepared.denialSignatures ?? []);
|
|
93
|
+
record.runnerFailure = sandbox.classifyRunnerFailure(record.exitCode, record.stderr?.text ?? '', prepared.runnerFailureRules ?? []);
|
|
94
|
+
} catch {
|
|
95
|
+
record.denied = false;
|
|
96
|
+
}
|
|
97
|
+
if (record.runnerFailure !== undefined) {
|
|
98
|
+
record.hint = `The Windows sandbox runner failed before the command ran (${terse(record.runnerFailure, 300)}). `
|
|
99
|
+
+ 'Run the bundled diagnose-windows-sandbox-acl skill against the workspace root, or switch this session to full access.';
|
|
100
|
+
} else if (record.denied) {
|
|
101
|
+
record.hint = `A file operation was denied under ${mode} mode. Writes are only expected inside the workspace`
|
|
102
|
+
+ (mode === 'read-only' ? ' and none are expected in read-only.' : '; use the tool\'s sandbox_permissions escalation for a genuinely wider need.');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
record.error = String(error instanceof Error ? error.message : error);
|
|
107
|
+
if (/SetNamedSecurityInfoW|grantWrite|Win32 5/i.test(record.error)) {
|
|
108
|
+
record.hint = 'The Windows sandbox could not provision the workspace write grant. '
|
|
109
|
+
+ 'Run the bundled diagnose-windows-sandbox-acl skill on the workspace root, or switch this session to full access.';
|
|
110
|
+
} else if (/SANDBOX_UNAVAILABLE/i.test(record.error)) {
|
|
111
|
+
record.hint = 'No usable sandbox runner for this platform/mode, so the command was not run. '
|
|
112
|
+
+ 'Switching to full access or fixing the sandbox runner is required.';
|
|
113
|
+
} else if (/not found/i.test(record.error)) {
|
|
114
|
+
record.hint = 'Install PowerShell 7 with the shell_router tool (action "install").';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return record;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Human/model readable status, including the async version probe. */
|
|
121
|
+
export async function describeStatus(ctx, state, exec) {
|
|
122
|
+
const lines = [`pwsh7-router (${state.platform})`];
|
|
123
|
+
if (state.pwsh.found) {
|
|
124
|
+
const probe = await probePwsh(state.pwsh.path);
|
|
125
|
+
lines.push(`PowerShell 7: ${state.pwsh.path}${probe.ok ? ` (${probe.version})` : ' (probe failed)'}`);
|
|
126
|
+
if (!probe.ok && probe.output) lines.push(` probe output: ${terse(probe.output, 300)}`);
|
|
127
|
+
} else {
|
|
128
|
+
lines.push('PowerShell 7: NOT FOUND — run shell_router action "install" (per-user, no admin), set DSH_PWSH_PATH, or install manually.');
|
|
129
|
+
}
|
|
130
|
+
lines.push(`config: ${state.configPath}`);
|
|
131
|
+
if (Array.isArray(state.notes) && state.notes.length > 0) lines.push(`notes: ${state.notes.join('; ')}`);
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const policy = currentPolicy(ctx, exec);
|
|
135
|
+
lines.push(`sandbox: ${policy === undefined ? 'unknown (no sandboxPolicy service)' : `${policy.mode} (workspace ${policy.workspaceRoot})`}`);
|
|
136
|
+
} catch {
|
|
137
|
+
lines.push('sandbox: unknown');
|
|
138
|
+
}
|
|
139
|
+
const shipped = describeShippedResolution();
|
|
140
|
+
lines.push(`shipped packages: ${shipped.ok ? 'ok' : `unavailable (${shipped.error})`}`);
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Run PowerShell 7 commands under the current policy. */
|
|
145
|
+
export async function runDiagnosis(ctx, state, exec) {
|
|
146
|
+
const policy = currentPolicy(ctx, exec);
|
|
147
|
+
const mode = policy?.mode ?? 'unknown';
|
|
148
|
+
const cwd = await currentCwd(ctx, exec);
|
|
149
|
+
const results = [];
|
|
150
|
+
|
|
151
|
+
if (state.pwsh.found) {
|
|
152
|
+
results.push(await runThroughExecutorPath(
|
|
153
|
+
ctx,
|
|
154
|
+
[state.pwsh.path, '-NoLogo', '-NoProfile', '-NonInteractive', '-Command',
|
|
155
|
+
'$PSVersionTable.PSVersion.ToString(); $PSHOME; (Get-Location).Path'],
|
|
156
|
+
{ mode, policy, cwd, signal: exec?.signal, label: 'pwsh version' },
|
|
157
|
+
));
|
|
158
|
+
results.push(await runThroughExecutorPath(
|
|
159
|
+
ctx,
|
|
160
|
+
[state.pwsh.path, '-NoLogo', '-NoProfile', '-NonInteractive', '-Command',
|
|
161
|
+
'"ok" | Set-Content .pwsh7-write-probe -ErrorAction Stop; Remove-Item .pwsh7-write-probe -ErrorAction Stop; "workspace-write-ok"'],
|
|
162
|
+
{ mode, policy, cwd, signal: exec?.signal, label: 'pwsh workspace write' },
|
|
163
|
+
));
|
|
164
|
+
} else {
|
|
165
|
+
results.push({ label: 'pwsh', ok: false, error: 'PowerShell 7 not found', hint: 'Run shell_router action "install" or install PowerShell 7 manually.' });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const hints = results.filter((record) => record.hint !== undefined).map((record) => record.hint);
|
|
169
|
+
const lines = [
|
|
170
|
+
`pwsh7-router diagnose (sandbox mode: ${mode}${mode === 'danger-full-access' ? ', commands run unconfined' : ''})`,
|
|
171
|
+
`cwd: ${cwd}`,
|
|
172
|
+
];
|
|
173
|
+
results.forEach((record, index) => {
|
|
174
|
+
const status = record.ok ? 'ok' : 'FAILED';
|
|
175
|
+
const exit = record.exitCode !== undefined && record.exitCode !== null ? ` (exit ${record.exitCode})` : '';
|
|
176
|
+
lines.push(`\n[${index + 1}] ${record.label}: ${status}${exit}`);
|
|
177
|
+
if (record.error !== undefined) lines.push(`error: ${terse(record.error)}`);
|
|
178
|
+
if (record.stdout?.text) lines.push(`stdout: ${terse(record.stdout.text)}`);
|
|
179
|
+
if (record.stderr?.text) lines.push(`stderr: ${terse(record.stderr.text)}`);
|
|
180
|
+
if (record.denied === true) lines.push('denied: yes');
|
|
181
|
+
if (record.runnerFailure !== undefined) lines.push(`runner failure: ${terse(record.runnerFailure, 300)}`);
|
|
182
|
+
if (record.hint !== undefined) lines.push(`hint: ${record.hint}`);
|
|
183
|
+
});
|
|
184
|
+
if (hints.length > 0) lines.push(`\nnext: ${hints[0]}`);
|
|
185
|
+
const ok = results.every((record) => record.ok === true);
|
|
186
|
+
return { ok, summary: lines.join('\n'), details: { mode, cwd, results } };
|
|
187
|
+
}
|
package/locale/en.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"meta": {
|
|
3
|
-
"title": "Windows PowerShell 7 Router",
|
|
4
|
-
"description": "Routes DSH's pwsh tool to PowerShell 7 on Windows, with per-user detection/installation and a sandbox-aware executor."
|
|
5
|
-
}
|
|
6
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "Windows PowerShell 7 Router",
|
|
4
|
+
"description": "Routes DSH's pwsh tool to PowerShell 7 on Windows, with per-user detection/installation and a sandbox-aware executor."
|
|
5
|
+
}
|
|
6
|
+
}
|
package/locale/zh.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"meta": {
|
|
3
|
-
"title": "Windows PowerShell 7 路由",
|
|
4
|
-
"description": "把 DSH 的 pwsh 工具路由到 PowerShell 7,支持自动检测/安装与沙箱模式。"
|
|
5
|
-
}
|
|
6
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "Windows PowerShell 7 路由",
|
|
4
|
+
"description": "把 DSH 的 pwsh 工具路由到 PowerShell 7,支持自动检测/安装与沙箱模式。"
|
|
5
|
+
}
|
|
6
|
+
}
|
package/package.json
CHANGED
|
@@ -1,60 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dsh-plugin-pwsh7",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Windows DeepSeek Harness bundle that routes the pwsh tool to PowerShell 7, with per-user detection, automatic installation, and a sandbox-aware executor.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"author": "drliuhuan",
|
|
8
|
-
"main": "index.js",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": "./index.js",
|
|
11
|
-
"./pwsh-executor": "./lib/executors/pwsh.mjs",
|
|
12
|
-
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
13
|
-
"./locale/*.json": "./locale/*.json",
|
|
14
|
-
"./icon": "./icon.svg",
|
|
15
|
-
"./package.json": "./package.json"
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"index.js",
|
|
19
|
-
"lib",
|
|
20
|
-
"cordis.patch.yml",
|
|
21
|
-
"locale/*.json",
|
|
22
|
-
"icon.svg",
|
|
23
|
-
"README.md",
|
|
24
|
-
"README.zh.md",
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"powershell
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-plugin-pwsh7",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Windows DeepSeek Harness bundle that routes the pwsh tool to PowerShell 7, with per-user detection, automatic installation, and a sandbox-aware executor.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "drliuhuan",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./index.js",
|
|
11
|
+
"./pwsh-executor": "./lib/executors/pwsh.mjs",
|
|
12
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
13
|
+
"./locale/*.json": "./locale/*.json",
|
|
14
|
+
"./icon": "./icon.svg",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"index.js",
|
|
19
|
+
"lib",
|
|
20
|
+
"cordis.patch.yml",
|
|
21
|
+
"locale/*.json",
|
|
22
|
+
"icon.svg",
|
|
23
|
+
"README.md",
|
|
24
|
+
"README.zh.md",
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"keywords": [
|
|
29
|
+
"deepseek-harness",
|
|
30
|
+
"dsh-plugin",
|
|
31
|
+
"powershell",
|
|
32
|
+
"powershell-7",
|
|
33
|
+
"pwsh",
|
|
34
|
+
"windows",
|
|
35
|
+
"shell",
|
|
36
|
+
"sandbox"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=22"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/drliuhuan/dsh-plugin-pwsh7.git"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/drliuhuan/dsh-plugin-pwsh7#readme",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/drliuhuan/dsh-plugin-pwsh7/issues"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public",
|
|
51
|
+
"registry": "https://registry.npmjs.org/",
|
|
52
|
+
"provenance": true
|
|
53
|
+
},
|
|
54
|
+
"dsh": {
|
|
55
|
+
"bundle": {
|
|
56
|
+
"patch": "./cordis.patch.yml"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"test": "node --test test/paths.test.mjs test/install.test.mjs"
|
|
61
|
+
}
|
|
62
|
+
}
|