dsh-use-codex 0.3.0 → 0.4.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/README.en.md +10 -0
- package/README.md +18 -3
- package/lib/index.js +73 -6
- package/package.json +5 -2
package/README.en.md
CHANGED
|
@@ -262,6 +262,16 @@ Reports:
|
|
|
262
262
|
- timeout and output limits
|
|
263
263
|
- a summary of the most recent run in the current DSH process
|
|
264
264
|
|
|
265
|
+
### `codex_danger`
|
|
266
|
+
|
|
267
|
+
Runtime toggle for `danger-full-access` (effective when the host config sets `allowDangerFullAccess: true`).
|
|
268
|
+
|
|
269
|
+
| Param | Type | Required | Description |
|
|
270
|
+
|---|---|---|---|
|
|
271
|
+
| `enabled` | `boolean` | yes | `true` enables danger mode (default sandbox becomes `danger-full-access`), `false` disables it (back to `workspace-write`) |
|
|
272
|
+
|
|
273
|
+
When enabled, the **next** `codex_run` defaults to `danger-full-access` (no sandbox: unrestricted read/write, network access, arbitrary commands). This only changes the default; an explicit `sandbox` argument is untouched. The state persists across DSH restarts.
|
|
274
|
+
|
|
265
275
|
### `codex_switch`
|
|
266
276
|
|
|
267
277
|
| Argument | Type | Required | Description |
|
package/README.md
CHANGED
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
## 功能特性
|
|
30
30
|
|
|
31
31
|
- **自然语言委派**:在 DSH 中说“让 Codex 做……”或“交给 Codex 执行……”。
|
|
32
|
-
-
|
|
32
|
+
- **四个内置工具**:任务执行、状态检查、危险模式开关、即时启停开关。
|
|
33
33
|
- **工作目录白名单**:只允许 Codex 在显式授权的真实目录中运行。
|
|
34
34
|
- **软链逃逸防护**:同时解析工作目录与白名单的真实路径。
|
|
35
35
|
- **默认安全沙箱**:默认使用 Codex 的 `workspace-write` 模式。
|
|
36
|
-
- **危险模式双重授权**:`danger-full-access`
|
|
36
|
+
- **危险模式双重授权**:`danger-full-access` 必须由宿主配置 `allowDangerFullAccess: true` 允许,再由 `codex_danger` 运行时开关打开。
|
|
37
37
|
- **无 shell 拼接**:任务正文作为单个 argv 参数传递,避免 shell 注入。
|
|
38
38
|
- **进程组清理**:超时或取消时终止完整 Codex 进程组。
|
|
39
39
|
- **输出限长**:限制 stdout/stderr,避免单次结果淹没会话。
|
|
@@ -248,7 +248,12 @@ DSH 的模型会按需调用 `codex_run`。任务应写清目标、范围、约
|
|
|
248
248
|
| `sandbox` | `string` | 否 | `read-only`、`workspace-write` 或 `danger-full-access` |
|
|
249
249
|
| `timeoutSec` | `number` | 否 | 本次超时,不能超过插件配置的 `timeoutSec` |
|
|
250
250
|
|
|
251
|
-
|
|
251
|
+
默认沙箱由两层开关共同决定:
|
|
252
|
+
|
|
253
|
+
1. **宿主配置** `allowDangerFullAccess: true|false`(profile 补丁,重启生效)——这是硬性许可,`false` 时任何方式都无法使用 `danger-full-access`
|
|
254
|
+
2. **运行时开关** `codex_danger`(即时生效,持久化到状态文件)——宿主允许后,用它切换"默认沙箱"是 `danger-full-access` 还是 `workspace-write`
|
|
255
|
+
|
|
256
|
+
省略 `sandbox` 参数时:宿主允许且 `codex_danger` 处于打开状态 → `danger-full-access`;否则 → `workspace-write`。显式传入的 `sandbox` 始终优先于默认值。
|
|
252
257
|
|
|
253
258
|
### `codex_status`
|
|
254
259
|
|
|
@@ -262,6 +267,16 @@ DSH 的模型会按需调用 `codex_run`。任务应写清目标、范围、约
|
|
|
262
267
|
- 超时与输出限制
|
|
263
268
|
- 当前 DSH 进程内最近一次调用的结果摘要
|
|
264
269
|
|
|
270
|
+
### `codex_danger`
|
|
271
|
+
|
|
272
|
+
切换 `danger-full-access` 的运行时开关(宿主 `allowDangerFullAccess: true` 时有效)。
|
|
273
|
+
|
|
274
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
275
|
+
|---|---|---|---|
|
|
276
|
+
| `enabled` | `boolean` | 是 | `true` 打开危险模式(默认沙箱变 `danger-full-access`),`false` 关闭(回到 `workspace-write`) |
|
|
277
|
+
|
|
278
|
+
打开后**下一次** `codex_run` 默认以 `danger-full-access` 运行(无沙箱:可读写任意路径、访问网络、执行任意命令)。此开关只影响默认沙箱,不影响显式传入的 `sandbox` 参数。状态持久化,重启 DSH 后保留。
|
|
279
|
+
|
|
265
280
|
### `codex_switch`
|
|
266
281
|
|
|
267
282
|
| 参数 | 类型 | 必填 | 说明 |
|
package/lib/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 安全边界:
|
|
5
5
|
* 1. 工作目录必须是白名单内的真实绝对路径;软链逃逸会被拒绝。
|
|
6
|
-
* 2.
|
|
6
|
+
* 2. 沙箱默认 workspace-write;宿主配置 allowDangerFullAccess 后可用 codex_danger 运行时开关切到 danger-full-access。
|
|
7
7
|
* 3. 不经过 shell,任务作为单个 argv 传给 Codex。
|
|
8
8
|
* 4. 超时或取消时终止 Codex 进程组,并限制输出大小。
|
|
9
9
|
* 5. 不持久化任务正文、工作目录或输出;状态文件只记录即时开关。
|
|
@@ -220,6 +220,31 @@ function textTool({ name: toolName, description, parameters, timeoutMs, execute
|
|
|
220
220
|
};
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
/** Settings-page schema builder; returns null when schemastery is unavailable. */
|
|
224
|
+
let _Config = null;
|
|
225
|
+
try {
|
|
226
|
+
const { default: z } = await import('@deepseek-ai/schemastery');
|
|
227
|
+
_Config = z.object({
|
|
228
|
+
enabled: z.boolean().default(true)
|
|
229
|
+
.description('启动时是否注册 Codex 委派工具(改为 false 并重启可完全停用)。'),
|
|
230
|
+
bin: z.string().default('codex')
|
|
231
|
+
.description('Codex CLI 可执行文件路径;留空用 PATH 中的 codex。'),
|
|
232
|
+
defaultCwd: z.string().default('')
|
|
233
|
+
.description('默认工作目录;留空用 DSH 进程当前目录。'),
|
|
234
|
+
allowedRoots: z.array(z.string()).role('textarea').default([])
|
|
235
|
+
.description('允许 Codex 工作的目录白名单,每行一个绝对路径。'),
|
|
236
|
+
allowDangerFullAccess: z.boolean().default(false)
|
|
237
|
+
.description('完全权限总许可:开启后可用 codex_danger 开关让 codex_run 默认以 danger-full-access(无沙箱)运行。关闭则任何方式都无法使用危险模式。'),
|
|
238
|
+
timeoutSec: z.number().min(1).max(3600).step(1).default(900)
|
|
239
|
+
.description('单次任务超时上限(秒)。'),
|
|
240
|
+
maxOutputChars: z.number().min(1000).max(200000).step(500).default(20000)
|
|
241
|
+
.description('返回输出的最大字符数。'),
|
|
242
|
+
}).description('Codex 委派');
|
|
243
|
+
} catch {}
|
|
244
|
+
|
|
245
|
+
/** DSH settings UI renders this panel; null schema = no settings page. */
|
|
246
|
+
export const Config = _Config;
|
|
247
|
+
|
|
223
248
|
export function apply(ctx, config = {}) {
|
|
224
249
|
if (config.enabled === false) {
|
|
225
250
|
ctx.logger?.info?.('[use-codex] disabled by configuration');
|
|
@@ -266,6 +291,13 @@ export function apply(ctx, config = {}) {
|
|
|
266
291
|
}
|
|
267
292
|
|
|
268
293
|
const enabledNow = () => readState().enabled !== false;
|
|
294
|
+
// Runtime danger-mode switch: defaults to the host config; codex_danger toggles it per session.
|
|
295
|
+
const dangerNow = () => {
|
|
296
|
+
const state = readState();
|
|
297
|
+
if (typeof state.dangerFullAccess === 'boolean') return state.dangerFullAccess;
|
|
298
|
+
return allowDanger;
|
|
299
|
+
};
|
|
300
|
+
const defaultSandbox = () => (dangerNow() ? 'danger-full-access' : 'workspace-write');
|
|
269
301
|
let lastRun = null;
|
|
270
302
|
|
|
271
303
|
const resolveRunCwd = (input) => {
|
|
@@ -287,7 +319,7 @@ export function apply(ctx, config = {}) {
|
|
|
287
319
|
description:
|
|
288
320
|
'让本机 OpenAI Codex CLI 执行一段独立任务并返回结果。'
|
|
289
321
|
+ '当用户说“让 Codex 做……”“交给 Codex 执行……”,或希望把编码、排障、批量文件处理任务委派出去时调用。'
|
|
290
|
-
+ '工作目录必须在 DSH
|
|
322
|
+
+ '工作目录必须在 DSH 配置的白名单内;默认沙箱由宿主配置与运行时开关共同决定;失败时如实返回失败原因。',
|
|
291
323
|
parameters: {
|
|
292
324
|
type: 'object',
|
|
293
325
|
additionalProperties: false,
|
|
@@ -305,7 +337,7 @@ export function apply(ctx, config = {}) {
|
|
|
305
337
|
sandbox: {
|
|
306
338
|
type: 'string',
|
|
307
339
|
enum: ['read-only', 'workspace-write', 'danger-full-access'],
|
|
308
|
-
description: 'Codex
|
|
340
|
+
description: 'Codex 沙箱模式;省略时用 defaultSandbox()(宿主 allowDangerFullAccess 与 codex_danger 运行时开关共同决定)。',
|
|
309
341
|
},
|
|
310
342
|
timeoutSec: {
|
|
311
343
|
type: 'number',
|
|
@@ -324,13 +356,16 @@ export function apply(ctx, config = {}) {
|
|
|
324
356
|
if (!task) return '❌ 任务不能为空。';
|
|
325
357
|
if (task.length > MAX_TASK_CHARS) return `❌ 任务过长,最多 ${MAX_TASK_CHARS} 字符。`;
|
|
326
358
|
|
|
327
|
-
const sandbox = String(args?.sandbox ||
|
|
359
|
+
const sandbox = String(args?.sandbox || defaultSandbox());
|
|
328
360
|
if (!['read-only', 'workspace-write', 'danger-full-access'].includes(sandbox)) {
|
|
329
361
|
return `❌ 不支持的沙箱模式:${sandbox}`;
|
|
330
362
|
}
|
|
331
363
|
if (sandbox === 'danger-full-access' && !allowDanger) {
|
|
332
364
|
return '❌ danger-full-access 未获宿主配置许可,拒绝执行。';
|
|
333
365
|
}
|
|
366
|
+
if (sandbox === 'danger-full-access' && !dangerNow()) {
|
|
367
|
+
return '🛡 danger-full-access 已被 codex_danger 关闭;请先用 codex_danger 打开,或显式传 workspace-write。';
|
|
368
|
+
}
|
|
334
369
|
|
|
335
370
|
let cwd;
|
|
336
371
|
try {
|
|
@@ -412,7 +447,7 @@ export function apply(ctx, config = {}) {
|
|
|
412
447
|
`📦 Codex:${version.ok ? version.stdout : `不可用(${version.error || version.stderr || version.code})`}`,
|
|
413
448
|
`🔑 认证:${login.stdout || login.stderr || (login.ok ? '未知' : login.code)}`,
|
|
414
449
|
`📁 白名单:${allowedRoots.length ? allowedRoots.join('、') : '(空)'}`,
|
|
415
|
-
`🛡 危险模式:${allowDanger ? '
|
|
450
|
+
`🛡 危险模式:${allowDanger ? (dangerNow() ? '允许且当前打开' : '允许但当前关闭') : '禁止'}`,
|
|
416
451
|
`⏱ 超时上限:${maxTimeoutSec}s`,
|
|
417
452
|
`📏 输出上限:${maxOutputChars} 字符`,
|
|
418
453
|
];
|
|
@@ -424,6 +459,38 @@ export function apply(ctx, config = {}) {
|
|
|
424
459
|
},
|
|
425
460
|
}),
|
|
426
461
|
|
|
462
|
+
textTool({
|
|
463
|
+
name: 'codex_danger',
|
|
464
|
+
description: '切换 danger-full-access 运行时开关。'
|
|
465
|
+
+ '仅在宿主配置 allowDangerFullAccess: true 时有效;'
|
|
466
|
+
+ '打开后 codex_run 默认使用 danger-full-access(无沙箱),关闭则回到 workspace-write。'
|
|
467
|
+
+ '此开关影响下一次 codex_run 的默认沙箱,不影响显式传入的 sandbox 参数。',
|
|
468
|
+
parameters: {
|
|
469
|
+
type: 'object',
|
|
470
|
+
additionalProperties: false,
|
|
471
|
+
properties: {
|
|
472
|
+
enabled: {
|
|
473
|
+
type: 'boolean',
|
|
474
|
+
description: 'true 为打开危险模式(默认沙箱变 danger-full-access),false 为关闭(回到 workspace-write)。',
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
required: ['enabled'],
|
|
478
|
+
},
|
|
479
|
+
timeoutMs: 10_000,
|
|
480
|
+
async execute(args) {
|
|
481
|
+
if (!allowDanger) {
|
|
482
|
+
return '❌ 宿主配置未开启 allowDangerFullAccess,此开关无效。';
|
|
483
|
+
}
|
|
484
|
+
const danger = args?.enabled === true;
|
|
485
|
+
if (!writeState({ dangerFullAccess: danger })) {
|
|
486
|
+
return '❌ 无法写入 Codex 危险模式状态,请检查 DSH 状态目录权限。';
|
|
487
|
+
}
|
|
488
|
+
return danger
|
|
489
|
+
? '🔓 危险模式已打开:codex_run 默认沙箱为 danger-full-access。'
|
|
490
|
+
: '🛡 危险模式已关闭:codex_run 默认沙箱为 workspace-write。';
|
|
491
|
+
},
|
|
492
|
+
}),
|
|
493
|
+
|
|
427
494
|
textTool({
|
|
428
495
|
name: 'codex_switch',
|
|
429
496
|
description: '即时打开或关闭 Codex 委派,不需要重启 DSH;关闭后 codex_run 会拒绝执行。',
|
|
@@ -458,7 +525,7 @@ export function apply(ctx, config = {}) {
|
|
|
458
525
|
}
|
|
459
526
|
}
|
|
460
527
|
|
|
461
|
-
ctx.logger?.info?.(`[use-codex] registered ${tools.length} tools; allowed roots=${allowedRoots.length}; enabled=${enabledNow()}`);
|
|
528
|
+
ctx.logger?.info?.(`[use-codex] registered ${tools.length} tools; allowed roots=${allowedRoots.length}; enabled=${enabledNow()}; danger=${dangerNow()}`);
|
|
462
529
|
}
|
|
463
530
|
|
|
464
531
|
export default { name, inject, apply };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-use-codex",
|
|
3
3
|
"displayName": "DSH Use Codex",
|
|
4
|
-
"description": "通过 DeepSeek Harness 工具调用本机 Codex CLI
|
|
5
|
-
"version": "0.
|
|
4
|
+
"description": "通过 DeepSeek Harness 工具调用本机 Codex CLI 执行独立任务;danger-full-access 支持宿主许可 + 运行时开关双重授权。",
|
|
5
|
+
"version": "0.4.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|
|
8
8
|
"exports": {
|
|
@@ -52,5 +52,8 @@
|
|
|
52
52
|
"homepage": "https://github.com/chaorenzeng/dsh-use-codex#readme",
|
|
53
53
|
"bugs": {
|
|
54
54
|
"url": "https://github.com/chaorenzeng/dsh-use-codex/issues"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@deepseek-ai/schemastery": "^3.18.4"
|
|
55
58
|
}
|
|
56
59
|
}
|