@michengai/dsh-automation 0.1.11 → 0.1.13
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/docs/00-/344/272/244/346/216/245/345/205/245/345/217/243/01-/351/241/271/347/233/256/346/246/202/350/247/210.md +1 -1
- package/lib/client.js +37 -1
- package/lib/client.js.map +3 -3
- package/lib/index.js +25 -44
- package/lib/types/client/create-modal-logic.d.ts +3 -0
- package/lib/types/executor.d.ts +1 -1
- package/lib/types/permission-presets.d.ts +0 -6
- package/lib/types/rpc.d.ts +3 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -21547,21 +21547,6 @@ function automationSessionTitle(taskName, iso) {
|
|
|
21547
21547
|
return `${formatRunStamp(iso)} - ${taskName}`;
|
|
21548
21548
|
}
|
|
21549
21549
|
|
|
21550
|
-
// src/permission-presets.ts
|
|
21551
|
-
function normalizePermissionPreset(input, names) {
|
|
21552
|
-
if (typeof input !== "string") return void 0;
|
|
21553
|
-
const raw = input.trim();
|
|
21554
|
-
if (raw === "") return void 0;
|
|
21555
|
-
const value = raw === "full-access" ? "danger-full-access" : raw;
|
|
21556
|
-
return names.includes(value) ? value : void 0;
|
|
21557
|
-
}
|
|
21558
|
-
function isUnattendedPermissionSafe(name2, presets) {
|
|
21559
|
-
const normalized = normalizePermissionPreset(name2, presets.names);
|
|
21560
|
-
if (normalized === void 0) return false;
|
|
21561
|
-
const sandbox = presets.resolve?.(normalized).sandbox;
|
|
21562
|
-
return (sandbox ?? normalized) !== "danger-full-access";
|
|
21563
|
-
}
|
|
21564
|
-
|
|
21565
21550
|
// src/executor.ts
|
|
21566
21551
|
var UNATTENDED_TOOL_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
21567
21552
|
"run_code",
|
|
@@ -21605,9 +21590,6 @@ function unattendedToolGuardReason(name2, args) {
|
|
|
21605
21590
|
return UNATTENDED_TOOL_ALLOWLIST.has(name2) ? void 0 : `\u5DE5\u5177 '${name2}' \u4E0D\u5728\u65E0\u4EBA\u503C\u5B88\u81EA\u52A8\u5316\u5141\u8BB8\u5217\u8868\u4E2D\u3002`;
|
|
21606
21591
|
}
|
|
21607
21592
|
function applyUnattendedPermission(presets, session, permission) {
|
|
21608
|
-
if (!isUnattendedPermissionSafe(permission, presets)) {
|
|
21609
|
-
throw new Error("\u65E0\u4EBA\u503C\u5B88\u81EA\u52A8\u5316\u62D2\u7EDD\u5B8C\u5168\u6587\u4EF6\u7CFB\u7EDF\u8BBF\u95EE\u6743\u9650\u3002");
|
|
21610
|
-
}
|
|
21611
21593
|
presets.set(session, permission);
|
|
21612
21594
|
setApprovalPolicy(session, "never");
|
|
21613
21595
|
}
|
|
@@ -21791,6 +21773,15 @@ function pinAutomationSessionTitle(ctx, session, title) {
|
|
|
21791
21773
|
}
|
|
21792
21774
|
}
|
|
21793
21775
|
|
|
21776
|
+
// src/permission-presets.ts
|
|
21777
|
+
function normalizePermissionPreset(input, names) {
|
|
21778
|
+
if (typeof input !== "string") return void 0;
|
|
21779
|
+
const raw = input.trim();
|
|
21780
|
+
if (raw === "") return void 0;
|
|
21781
|
+
const value = raw === "full-access" ? "danger-full-access" : raw;
|
|
21782
|
+
return names.includes(value) ? value : void 0;
|
|
21783
|
+
}
|
|
21784
|
+
|
|
21794
21785
|
// src/service.ts
|
|
21795
21786
|
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
21796
21787
|
var OPTION_CACHE_TTL_MS = 3e4;
|
|
@@ -21858,20 +21849,17 @@ var AutomationService = class _AutomationService {
|
|
|
21858
21849
|
});
|
|
21859
21850
|
}
|
|
21860
21851
|
permissionNames() {
|
|
21861
|
-
|
|
21862
|
-
return presets.names.filter((name2) => isUnattendedPermissionSafe(name2, presets));
|
|
21852
|
+
return this.permissionPresets().names;
|
|
21863
21853
|
}
|
|
21864
21854
|
permissionOptions() {
|
|
21865
21855
|
const presets = this.permissionPresets();
|
|
21866
|
-
return
|
|
21856
|
+
return presets.names.map((name2) => presets.optionOf(name2));
|
|
21867
21857
|
}
|
|
21868
21858
|
defaultPermission() {
|
|
21869
21859
|
const presets = this.permissionPresets();
|
|
21870
21860
|
const value = normalizePermissionPreset(presets.defaultPreset, presets.names);
|
|
21871
|
-
if (value
|
|
21872
|
-
|
|
21873
|
-
if (fallback === void 0) throw new Error("Host \u6CA1\u6709\u53EF\u7528\u4E8E\u65E0\u4EBA\u503C\u5B88\u4EFB\u52A1\u7684\u5B89\u5168\u6743\u9650\u9884\u8BBE\u3002");
|
|
21874
|
-
return fallback;
|
|
21861
|
+
if (value === void 0) throw new Error("Host \u7684\u9ED8\u8BA4\u6743\u9650\u9884\u8BBE\u4E0D\u5728\u5B98\u65B9\u6743\u9650\u5217\u8868\u4E2D\u3002");
|
|
21862
|
+
return value;
|
|
21875
21863
|
}
|
|
21876
21864
|
async dispose() {
|
|
21877
21865
|
this.stopping = true;
|
|
@@ -22353,9 +22341,6 @@ var AutomationService = class _AutomationService {
|
|
|
22353
22341
|
if (input === void 0) return this.defaultPermission();
|
|
22354
22342
|
const value = normalizePermissionPreset(input, presets.names);
|
|
22355
22343
|
if (value === void 0) throw new AutomationRequestError(`unknown permission preset '${input}'`);
|
|
22356
|
-
if (!isUnattendedPermissionSafe(value, presets)) {
|
|
22357
|
-
throw new AutomationRequestError("\u65E0\u4EBA\u503C\u5B88\u81EA\u52A8\u5316\u4E0D\u5141\u8BB8\u4F7F\u7528\u5B8C\u5168\u6587\u4EF6\u7CFB\u7EDF\u8BBF\u95EE\u6743\u9650\u3002");
|
|
22358
|
-
}
|
|
22359
22344
|
return value;
|
|
22360
22345
|
}
|
|
22361
22346
|
/** 把旧版 full-access 及已移除的预设收敛到 Host 当前可用列表。 */
|
|
@@ -22363,23 +22348,12 @@ var AutomationService = class _AutomationService {
|
|
|
22363
22348
|
const presets = this.permissionPresets();
|
|
22364
22349
|
const fallback = this.defaultPermission();
|
|
22365
22350
|
for (const [id, definition] of this.definitions.entries()) {
|
|
22366
|
-
const
|
|
22367
|
-
|
|
22368
|
-
|
|
22369
|
-
if (permissionPreset2 === definition.permissionPreset && !unsafe) continue;
|
|
22370
|
-
await this.definitions.put(id, {
|
|
22371
|
-
...definition,
|
|
22372
|
-
permissionPreset: permissionPreset2,
|
|
22373
|
-
...unsafe ? {
|
|
22374
|
-
status: "paused",
|
|
22375
|
-
revision: definition.revision + 1,
|
|
22376
|
-
updatedAt: toIso()
|
|
22377
|
-
} : {}
|
|
22378
|
-
});
|
|
22351
|
+
const permissionPreset2 = normalizePermissionPreset(definition.permissionPreset, presets.names) ?? fallback;
|
|
22352
|
+
if (permissionPreset2 === definition.permissionPreset) continue;
|
|
22353
|
+
await this.definitions.put(id, { ...definition, permissionPreset: permissionPreset2 });
|
|
22379
22354
|
}
|
|
22380
22355
|
for (const [id, run] of this.runs.entries()) {
|
|
22381
|
-
const
|
|
22382
|
-
const permissionPreset2 = normalized !== void 0 && isUnattendedPermissionSafe(normalized, presets) ? normalized : fallback;
|
|
22356
|
+
const permissionPreset2 = normalizePermissionPreset(run.targetSnapshot.permissionPreset, presets.names) ?? fallback;
|
|
22383
22357
|
if (permissionPreset2 === run.targetSnapshot.permissionPreset) continue;
|
|
22384
22358
|
await this.runs.put(id, {
|
|
22385
22359
|
...run,
|
|
@@ -22537,6 +22511,9 @@ var WEEKDAYS = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"];
|
|
|
22537
22511
|
var RpcRequestError = class extends Error {
|
|
22538
22512
|
name = "RpcRequestError";
|
|
22539
22513
|
};
|
|
22514
|
+
function isBadRequest(error51) {
|
|
22515
|
+
return error51 instanceof RpcRequestError || error51 instanceof AutomationRequestError;
|
|
22516
|
+
}
|
|
22540
22517
|
function record2(value, label) {
|
|
22541
22518
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
22542
22519
|
throw new RpcRequestError(`${label} must be an object`);
|
|
@@ -22607,7 +22584,7 @@ function errorResult(error51, aborted2 = false) {
|
|
|
22607
22584
|
};
|
|
22608
22585
|
}
|
|
22609
22586
|
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
22610
|
-
const badRequest = error51
|
|
22587
|
+
const badRequest = isBadRequest(error51);
|
|
22611
22588
|
return {
|
|
22612
22589
|
ok: false,
|
|
22613
22590
|
error: {
|
|
@@ -22755,6 +22732,10 @@ function registerAutomationRpc(ctx, service) {
|
|
|
22755
22732
|
throw new RpcRequestError(`unknown automation endpoint '${endpoint}'`);
|
|
22756
22733
|
}
|
|
22757
22734
|
} catch (error51) {
|
|
22735
|
+
if (!signal.aborted && !isBadRequest(error51)) {
|
|
22736
|
+
const detail = error51 instanceof Error ? error51.stack ?? error51.message : String(error51);
|
|
22737
|
+
ctx.logger.warn(`dsh-automation: RPC '${endpoint}' failed: ${detail}`);
|
|
22738
|
+
}
|
|
22758
22739
|
return errorResult(error51, signal.aborted);
|
|
22759
22740
|
}
|
|
22760
22741
|
}, { authority: "loopback" });
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
+
import type { AutomationPermission } from './protocol.js';
|
|
1
2
|
/** 新建/编辑弹窗只允许取消或 ESC 关闭,点旁边不能关。 */
|
|
2
3
|
export declare function shouldCloseCreateModal(reason: 'backdrop' | 'escape' | 'cancel'): boolean;
|
|
4
|
+
/** 与 Chat 一致:从其他权限切换到完全访问时显示风险确认。 */
|
|
5
|
+
export declare function shouldConfirmFullAccess(current: AutomationPermission, next: AutomationPermission): boolean;
|
package/lib/types/executor.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** 已认领 run 的独立 Agent 执行边界。 */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
-
import {
|
|
3
|
+
import type { PermissionPresetService } from './permission-presets.ts';
|
|
4
4
|
import type { AutomationDefinition, AutomationRun } from './types.ts';
|
|
5
5
|
interface SessionEventLike {
|
|
6
6
|
readonly seq: number;
|
|
@@ -8,13 +8,7 @@ export interface PermissionPresetService {
|
|
|
8
8
|
readonly names: readonly string[];
|
|
9
9
|
readonly defaultPreset: string;
|
|
10
10
|
optionOf(name: string): PermissionOption;
|
|
11
|
-
resolve?(name: string): {
|
|
12
|
-
readonly sandbox: 'read-only' | 'workspace-write' | 'danger-full-access';
|
|
13
|
-
readonly approval: 'ask' | 'never';
|
|
14
|
-
};
|
|
15
11
|
set(session: unknown, name: string): void;
|
|
16
12
|
}
|
|
17
13
|
/** 兼容旧版插件曾保存的 full-access 名称,其余值必须来自 Host 当前列表。 */
|
|
18
14
|
export declare function normalizePermissionPreset(input: unknown, names: readonly string[]): string | undefined;
|
|
19
|
-
/** 无人值守任务禁止完全文件系统访问;自定义预设也按其真实 sandbox 语义判断。 */
|
|
20
|
-
export declare function isUnattendedPermissionSafe(name: string, presets: PermissionPresetService): boolean;
|
package/lib/types/rpc.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/** 仅 loopback 的 Web 客户端 RPC 适配器。 */
|
|
2
2
|
import { type AutomationService } from './service.ts';
|
|
3
3
|
interface RpcContext {
|
|
4
|
+
readonly logger: {
|
|
5
|
+
warn(message: string): void;
|
|
6
|
+
};
|
|
4
7
|
readonly connection: {
|
|
5
8
|
readonly rpc: {
|
|
6
9
|
handle(channel: string, handler: (endpoint: string, payload: unknown, signal: AbortSignal) => Promise<unknown>, options: {
|