@michengai/dsh-automation 0.1.66 → 1.0.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/lib/index.js CHANGED
@@ -21746,8 +21746,8 @@ async function executeAutomationRun(ctx, definition, run, config2) {
21746
21746
  setup: async (agentCtx, createdAgent) => {
21747
21747
  await ctx.agentPresets.mount(agentCtx, target.agentPreset);
21748
21748
  installModelSelection(agentCtx, { current: selection, assembled: void 0 });
21749
- const agent = createdAgent ?? agentCtx.agent;
21750
- if (agent === void 0) throw new Error("automation setup has no scoped Agent");
21749
+ if (createdAgent === void 0) throw new Error("automation setup has no scoped Agent");
21750
+ const agent = createdAgent;
21751
21751
  applyUnattendedPermission(ctx.permissionPresets, agent.session, target.permissionPreset);
21752
21752
  }
21753
21753
  }));
@@ -23364,7 +23364,7 @@ function registerAutomationTools(service, agent) {
23364
23364
  // src/plugin-updater.ts
23365
23365
  import { spawn } from "node:child_process";
23366
23366
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
23367
- import { readFile } from "node:fs/promises";
23367
+ import { readFile, rename, unlink, writeFile } from "node:fs/promises";
23368
23368
  import { homedir as homedir2 } from "node:os";
23369
23369
  import { basename, delimiter, dirname, isAbsolute, resolve } from "node:path";
23370
23370
  import { fileURLToPath } from "node:url";
@@ -23572,6 +23572,157 @@ async function status(options, target) {
23572
23572
  canAutoUpdate: target.canAutoUpdate
23573
23573
  };
23574
23574
  }
23575
+ function releaseAgeSpec(packageSpec) {
23576
+ const at = packageSpec.lastIndexOf("@");
23577
+ if (at <= 0) return void 0;
23578
+ const name2 = packageSpec.slice(0, at);
23579
+ const version2 = packageSpec.slice(at + 1);
23580
+ if (!isPackageName(name2) || !isReleaseVersion(version2)) return void 0;
23581
+ return { name: name2, version: version2 };
23582
+ }
23583
+ function isPackageName(name2) {
23584
+ return /^@[^/\s]+\/[^/\s]+$/.test(name2) || /^[^@/\s]+$/.test(name2);
23585
+ }
23586
+ function isReleaseVersion(version2) {
23587
+ return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(version2);
23588
+ }
23589
+ function unreadableReleaseAgeExclude() {
23590
+ return new Error("\u53D1\u5E03\u5E74\u9F84\u767D\u540D\u5355\u65E0\u6CD5\u5B89\u5168\u5408\u5E76\uFF0C\u5DF2\u505C\u6B62\u66F4\u65B0\uFF0C\u907F\u514D\u8FD9\u4E2A profile \u4E4B\u540E\u65E0\u6CD5\u5B89\u88C5\u63D2\u4EF6\u3002");
23591
+ }
23592
+ function excludeEntry(indent, name2, versions, comment = "") {
23593
+ const entry = `${indent}- '${name2}@${versions.join(" || ")}'`;
23594
+ return comment === "" ? entry : `${entry} ${comment}`;
23595
+ }
23596
+ function parseExcludeLine(line) {
23597
+ const dash = line.indexOf("-");
23598
+ if (!/^\s+-/.test(line) || dash < 0) return void 0;
23599
+ const indent = line.slice(0, dash);
23600
+ const raw = line.slice(dash + 1).trim();
23601
+ let body = raw;
23602
+ let comment = "";
23603
+ if (raw.startsWith("'") || raw.startsWith('"')) {
23604
+ const quote = raw[0] ?? "'";
23605
+ const end = raw.lastIndexOf(quote);
23606
+ if (end <= 0) return void 0;
23607
+ const rest = raw.slice(end + 1).trim();
23608
+ if (rest !== "" && !rest.startsWith("#")) return void 0;
23609
+ if (rest.startsWith("#")) comment = rest;
23610
+ body = raw.slice(1, end);
23611
+ } else if (raw.includes("#")) return void 0;
23612
+ if (body.includes("#")) return void 0;
23613
+ const versionAt = body.lastIndexOf("@");
23614
+ if (versionAt > 0) {
23615
+ const name2 = body.slice(0, versionAt);
23616
+ const versions = body.slice(versionAt + 1).split(" || ");
23617
+ if (isPackageName(name2) && versions.every(isReleaseVersion)) return { indent, name: name2, versions, comment };
23618
+ return void 0;
23619
+ }
23620
+ if (isPackageName(body) || /^@[^/\s]+\/\*$/.test(body)) return { indent, name: body, versions: void 0, comment };
23621
+ return void 0;
23622
+ }
23623
+ function mergeMinimumReleaseAgeExclude(yaml, packageSpec) {
23624
+ const spec = releaseAgeSpec(packageSpec);
23625
+ if (spec === void 0) throw new Error("\u66F4\u65B0\u7248\u672C\u65E0\u6CD5\u5199\u5165\u53D1\u5E03\u5E74\u9F84\u767D\u540D\u5355\uFF0C\u5DF2\u505C\u6B62\u66F4\u65B0\u3002");
23626
+ const eol = yaml.includes("\r\n") ? "\r\n" : "\n";
23627
+ const text = yaml.replaceAll("\r\n", "\n");
23628
+ const next = mergeReleaseAgeText(text, spec.name, spec.version);
23629
+ return eol === "\r\n" ? next.replaceAll("\n", "\r\n") : next;
23630
+ }
23631
+ function mergeReleaseAgeText(yaml, name2, version2) {
23632
+ if (/minimumReleaseAgeExclude:[^\n\r]/.test(yaml)) throw unreadableReleaseAgeExclude();
23633
+ const marker = /(?:^|\n)minimumReleaseAgeExclude:[ \t]*(?:\n|$)/.exec(yaml);
23634
+ if (marker === null) {
23635
+ const base = yaml.endsWith("\n") || yaml.length === 0 ? yaml : `${yaml}
23636
+ `;
23637
+ const gap = base.length === 0 || base.endsWith("\n\n") ? "" : "\n";
23638
+ return `${base}${gap}minimumReleaseAgeExclude:
23639
+ - '${name2}@${version2}'
23640
+ `;
23641
+ }
23642
+ const keyAt = (marker.index ?? 0) + (marker[0].startsWith("\n") ? 1 : 0);
23643
+ let cursor = keyAt + "minimumReleaseAgeExclude:".length;
23644
+ while (cursor < yaml.length && (yaml[cursor] === " " || yaml[cursor] === " ")) cursor += 1;
23645
+ if (yaml[cursor] !== "\n") throw unreadableReleaseAgeExclude();
23646
+ const bodyStart = cursor + 1;
23647
+ const lines = [];
23648
+ let bodyEnd = bodyStart;
23649
+ while (bodyEnd <= yaml.length) {
23650
+ const nextNl = yaml.indexOf("\n", bodyEnd);
23651
+ const lineEnd = nextNl === -1 ? yaml.length : nextNl;
23652
+ const line = yaml.slice(bodyEnd, lineEnd);
23653
+ const ended = line.trim() !== "" && !/^[ \t]*#/.test(line) && !/^[ \t]/.test(line);
23654
+ if (ended) break;
23655
+ if (line.trim() !== "" && !/^[ \t]*#/.test(line) && !/^[ \t]+-/.test(line)) throw unreadableReleaseAgeExclude();
23656
+ lines.push(line);
23657
+ if (nextNl === -1) {
23658
+ bodyEnd = yaml.length;
23659
+ break;
23660
+ }
23661
+ bodyEnd = nextNl + 1;
23662
+ if (bodyEnd === yaml.length) break;
23663
+ }
23664
+ let ours;
23665
+ const rewritten = lines.map((line, index) => {
23666
+ if (line.trim() === "" || /^[ \t]*#/.test(line)) return line;
23667
+ const parsed = parseExcludeLine(line);
23668
+ if (parsed === void 0) throw unreadableReleaseAgeExclude();
23669
+ if (parsed.name !== name2) return line;
23670
+ if (ours === void 0) {
23671
+ ours = { index, indent: parsed.indent, versions: parsed.versions, comment: parsed.comment };
23672
+ return line;
23673
+ }
23674
+ if (ours.versions !== void 0 && parsed.versions !== void 0) ours.versions = [...ours.versions, ...parsed.versions.filter((item) => !ours?.versions?.includes(item))];
23675
+ return "";
23676
+ });
23677
+ if (ours?.versions === void 0 && ours !== void 0) return yaml;
23678
+ const indent = ours?.indent ?? lines.find((line) => /^[ \t]+-/.test(line))?.match(/^([ \t]+)/)?.[1] ?? " ";
23679
+ const versions = ours?.versions === void 0 ? [version2] : ours.versions.includes(version2) ? ours.versions : [...ours.versions, version2];
23680
+ const entry = excludeEntry(indent, name2, versions, ours?.comment ?? "");
23681
+ if (ours === void 0) rewritten.push(entry);
23682
+ else rewritten[ours.index] = entry;
23683
+ const body = rewritten.filter((line) => line !== "").join("\n");
23684
+ const prefix = yaml.slice(0, bodyStart);
23685
+ const suffix = yaml.slice(bodyEnd);
23686
+ const joined = `${prefix}${body}${body.length === 0 || body.endsWith("\n") ? "" : "\n"}${suffix}`;
23687
+ return joined.endsWith("\n") ? joined : `${joined}
23688
+ `;
23689
+ }
23690
+ async function guardReleaseAgeExclude(profileDir, packageSpec) {
23691
+ const file2 = resolve(profileDir, "pnpm-workspace.yaml");
23692
+ const current = existsSync2(file2) ? await readFile(file2, "utf8") : "packages:\n - .\n";
23693
+ mergeMinimumReleaseAgeExclude(current, packageSpec);
23694
+ }
23695
+ async function replaceTextFile(file2, next) {
23696
+ const tmp = `${file2}.${process.pid}.tmp`;
23697
+ const backup = `${file2}.${process.pid}.bak`;
23698
+ await writeFile(tmp, next, "utf8");
23699
+ try {
23700
+ await rename(tmp, file2);
23701
+ return;
23702
+ } catch (error51) {
23703
+ const code = error51 && typeof error51 === "object" && "code" in error51 ? String(error51.code) : "";
23704
+ if (code !== "EEXIST" && code !== "EPERM" && code !== "EACCES") {
23705
+ await unlink(tmp).catch(() => void 0);
23706
+ throw error51;
23707
+ }
23708
+ }
23709
+ await unlink(backup).catch(() => void 0);
23710
+ await rename(file2, backup);
23711
+ try {
23712
+ await rename(tmp, file2);
23713
+ } catch (error51) {
23714
+ await rename(backup, file2).catch(() => void 0);
23715
+ await unlink(tmp).catch(() => void 0);
23716
+ throw error51;
23717
+ }
23718
+ await unlink(backup).catch(() => void 0);
23719
+ }
23720
+ async function recordReleaseAgeExclude(profileDir, packageSpec) {
23721
+ const file2 = resolve(profileDir, "pnpm-workspace.yaml");
23722
+ const current = existsSync2(file2) ? await readFile(file2, "utf8") : "packages:\n - .\n";
23723
+ const next = mergeMinimumReleaseAgeExclude(current, packageSpec);
23724
+ if (next !== current) await replaceTextFile(file2, next);
23725
+ }
23575
23726
  async function runCliInstall(target, packageSpec) {
23576
23727
  if (target.cliEntry === void 0) throw new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u81EA\u52A8\u66F4\u65B0\uFF0C\u8BF7\u4F7F\u7528\u624B\u5DE5\u66F4\u65B0\u547D\u4EE4\u3002");
23577
23728
  await new Promise((resolvePromise, reject) => {
@@ -23604,10 +23755,12 @@ async function runCliInstall(target, packageSpec) {
23604
23755
  });
23605
23756
  }
23606
23757
  async function install(target, packageSpec) {
23758
+ await guardReleaseAgeExclude(target.profileDir, packageSpec);
23607
23759
  if (target.desktopPnpm !== void 0) {
23608
23760
  const handle = target.desktopPnpm.runPlugin(["add", "--config.minimumReleaseAge=0", packageSpec, "--registry=https://registry.npmjs.org/"], target.profileDir);
23609
23761
  const result = await handle.done;
23610
23762
  if (result.exitCode !== 0) throw new Error(`\u66F4\u65B0\u8FDB\u7A0B\u9000\u51FA\u7801 ${String(result.exitCode)}\u3002`);
23763
+ await recordReleaseAgeExclude(target.profileDir, packageSpec);
23611
23764
  return;
23612
23765
  }
23613
23766
  if (target.packageManager !== void 0) {
@@ -23640,14 +23793,19 @@ async function install(target, packageSpec) {
23640
23793
  else reject(new Error(detail.trim() || `\u66F4\u65B0\u8FDB\u7A0B\u9000\u51FA\u7801 ${String(code)}`));
23641
23794
  });
23642
23795
  });
23796
+ await recordReleaseAgeExclude(target.profileDir, packageSpec);
23643
23797
  return;
23644
23798
  }
23645
23799
  if (target.pluginManager !== void 0) {
23646
23800
  const result = await target.pluginManager.installBundle(packageSpec);
23647
- if (result.application === "applied" || result.application === "restart-required" || result.application === "overridden") return;
23801
+ if (result.application === "applied" || result.application === "restart-required" || result.application === "overridden") {
23802
+ await recordReleaseAgeExclude(target.profileDir, packageSpec);
23803
+ return;
23804
+ }
23648
23805
  throw new Error(result.error?.message || result.packageResult?.output || "\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B\u670D\u52A1\u7AEF\u65E5\u5FD7\u3002");
23649
23806
  }
23650
- return runCliInstall(target, packageSpec);
23807
+ await runCliInstall(target, packageSpec);
23808
+ await recordReleaseAgeExclude(target.profileDir, packageSpec);
23651
23809
  }
23652
23810
  function json3(response, statusCode, value) {
23653
23811
  response.writeHead(statusCode, { "content-type": "application/json; charset=utf-8", "cache-control": "no-store" });
@@ -42,13 +42,11 @@ export interface ClientContext {
42
42
  readonly rpc: ClientRpc;
43
43
  };
44
44
  sessions?: {
45
- open?(id: string): void;
46
45
  refresh?: () => Promise<void>;
47
46
  list?: {
48
47
  getSnapshot(): {
49
48
  ids?: readonly string[];
50
49
  byId?: Record<string, unknown>;
51
- current?: string | null;
52
50
  };
53
51
  };
54
52
  };
@@ -2,7 +2,7 @@ export type HostIcon = (props: {
2
2
  readonly size?: number;
3
3
  readonly className?: string;
4
4
  }) => JSX.Element | null;
5
- /** 0.1.7 把尺寸从组件名里拿掉了。旧宿主仍导出带尺寸的名字,缺哪个就用另一个。没有对应导出时返回 undefined,调用方再退回自绘。 */
5
+ /** 没有对应导出时返回 undefined,调用方再退回自绘。 */
6
6
  export declare function pickHostExport(source: Readonly<Record<string, unknown>>, name: string): unknown;
7
7
  /** 宿主图标渲染出 null 时改用自绘。 */
8
8
  export declare function hostOrFallback(icon: HostIcon, fallback: HostIcon): HostIcon;
@@ -14,10 +14,13 @@ export declare const IconSearchOutline: HostIcon;
14
14
  export declare const IconCloseFill: HostIcon;
15
15
  export declare const IconSlidersTwoOutline: HostIcon;
16
16
  export declare const IconFolderClose: HostIcon;
17
+ export declare const IconFolderOpen: HostIcon;
18
+ export declare const IconTriangleRightFill: HostIcon;
19
+ export declare const IconUnarchiveOutline: HostIcon;
17
20
  export declare const IconWorkspaceTreeOutline: HostIcon;
18
21
  export declare const IconFlatListOutline: HostIcon;
19
22
  export declare const IconChevronsUpDownOutline: HostIcon;
20
23
  export declare const IconClockOutline: HostIcon;
24
+ export declare const IconCopyOutline: HostIcon;
25
+ export declare const IconArchiveOffOutline: HostIcon;
21
26
  export declare const IconArchiveCheckOutline: HostIcon;
22
- /** 0.1.7 的 Menu 会渲染 children。更早的 Menu 只认 items。样式和列表功能不再按宿主版本分叉。 */
23
- export declare function hostMenuRendersChildren(): boolean;
@@ -9,6 +9,8 @@ export declare function InfoIcon(props: IconProps): JSX.Element;
9
9
  export declare function ClockIcon(props: IconProps): JSX.Element;
10
10
  export declare function ChatIcon(props: IconProps): JSX.Element;
11
11
  export declare function GithubIcon(props: IconProps): JSX.Element;
12
+ /** 与技能管理器标题旁的问题反馈同一支 16px 笔,避免宿主图标把按钮撑高。 */
13
+ export declare function FeedbackIcon(props: IconProps): JSX.Element;
12
14
  export declare function FolderIcon(props: IconProps): JSX.Element;
13
15
  export declare function SparkleIcon(props: IconProps): JSX.Element;
14
16
  export declare function UnarchiveOutlineIcon(props: IconProps): JSX.Element;
@@ -25,7 +25,8 @@ export declare const en: {
25
25
  readonly "sidebar.sortManual": "Manual";
26
26
  readonly "sidebar.sortTime": "Last updated";
27
27
  readonly "sidebar.filterBy": "Filter sessions";
28
- readonly "sidebar.showArchived": "Show archived";
28
+ readonly "sidebar.hideArchived": "Hide archived";
29
+ readonly "sidebar.showArchived": "All conversations (show archived)";
29
30
  readonly "sidebar.onlyArchived": "Archived only";
30
31
  readonly "header.lead": "Plan automatic tasks, or trigger them by hand. Describe the recurring work in any chat to create it quickly.";
31
32
  readonly "header.githubProject": "GitHub";
@@ -49,6 +50,7 @@ export declare const en: {
49
50
  readonly "session.fork": "Fork session";
50
51
  readonly "session.archive": "Archive session";
51
52
  readonly "session.unarchive": "Restore";
53
+ readonly "session.copySessionId": "Copy Session ID";
52
54
  readonly "session.moreActions": "More actions for {title}";
53
55
  readonly "session.groupActions": "Actions for {name}";
54
56
  readonly "session.taskSettings": "Task settings";
@@ -59,6 +61,13 @@ export declare const en: {
59
61
  readonly "session.archiveGroupFailed": "Some conversations could not be archived: {message}";
60
62
  readonly "session.archiveGroupClose": "Close";
61
63
  readonly "session.archiveGroupCancel": "Cancel";
64
+ readonly "session.unarchiveGroup": "Restore all conversations";
65
+ readonly "session.unarchiveGroupConfirm": "Restore all";
66
+ readonly "session.unarchiveGroupDescription": "Restore all {count} conversations for “{name}”.";
67
+ readonly "session.unarchiveGroupPending": "Restoring conversations…";
68
+ readonly "session.unarchiveGroupFailed": "Some conversations could not be restored: {message}";
69
+ readonly "session.unarchiveGroupClose": "Close";
70
+ readonly "session.unarchiveGroupCancel": "Cancel";
62
71
  readonly "session.deleteSession": "Delete session";
63
72
  readonly "session.deleteSessionConfirm": "Delete session";
64
73
  readonly "session.deleteSessionDescription": "This permanently deletes session “{name}”, its child agents (including any that are still running), and all of its records (conversation, stats, cache). This cannot be undone.";
@@ -109,6 +118,7 @@ export declare const en: {
109
118
  readonly "form.workspace": "Workspace";
110
119
  readonly "form.fieldWorkspace": "Workspace";
111
120
  readonly "form.fieldModel": "Model";
121
+ readonly "form.providerAccount": "DeepSeek account";
112
122
  readonly "form.fieldEffort": "Reasoning";
113
123
  readonly "form.fieldPermission": "Permission";
114
124
  readonly "form.slashHint": "Type / to insert a skill";
@@ -0,0 +1,30 @@
1
+ import * as React from 'react';
2
+ export interface MenuSelectOption {
3
+ value: string;
4
+ label: React.ReactNode;
5
+ /** 当 label 是复杂 ReactNode 时作为 aria-label 和纯文本回退 */
6
+ text?: string;
7
+ disabled?: boolean;
8
+ danger?: boolean;
9
+ }
10
+ export interface MenuSelectGroup {
11
+ id: string;
12
+ label: string;
13
+ options: readonly MenuSelectOption[];
14
+ }
15
+ export interface MenuSelectProps {
16
+ value: string;
17
+ label?: string;
18
+ placeholder?: string;
19
+ options?: readonly MenuSelectOption[];
20
+ groups?: readonly MenuSelectGroup[];
21
+ footer?: readonly MenuSelectOption[];
22
+ onChange: (value: string) => void;
23
+ onFooter?: (id: string) => void;
24
+ disabled?: boolean;
25
+ compact?: boolean;
26
+ className?: string;
27
+ listClassName?: string;
28
+ }
29
+ /** 宿主 Menu 下拉。分组用标签行,底部动作走 footer,不走选择值。 */
30
+ export declare function MenuSelect(props: MenuSelectProps): React.ReactElement;
@@ -26,3 +26,5 @@ export declare function scheduledGroupShowsActiveFolder(sessionIds: readonly str
26
26
  export declare function scheduledSessionOmitsStatusSlot(flat: boolean, running: boolean): boolean;
27
27
  /** 串行归档,避免多个 workspace 状态写入相互覆盖。 */
28
28
  export declare function archiveScheduledGroup(sessionIds: readonly string[], archiveSession: (sessionId: string) => void | Promise<void>): Promise<void>;
29
+ /** 串行恢复,避免多个 workspace 状态写入相互覆盖。 */
30
+ export declare function unarchiveScheduledGroup(sessionIds: readonly string[], unarchiveSession: (sessionId: string) => void | Promise<void>): Promise<void>;
@@ -4,7 +4,7 @@ type SlotRenderer = (name: string, props?: Record<string, unknown>, opts?: {
4
4
  readonly hookContext?: unknown;
5
5
  readonly only?: string;
6
6
  }) => ReactNode;
7
- /** 旧宿主的 renderSlot 在条目未声明该子插槽时抛 SlotOwnershipError。接住它,避免定时页整页失败。 */
7
+ /** 宿主 renderSlot 在条目未声明该子插槽时抛 SlotOwnershipError。接住它,避免定时页整页失败。 */
8
8
  export declare function renderOwnedSlot(renderSlot: SlotRenderer | undefined, name: string, props?: Record<string, unknown>, opts?: {
9
9
  readonly hookContext?: unknown;
10
10
  readonly only?: string;
@@ -32,7 +32,7 @@ export declare function scheduledSessionHoverStatuses(input: {
32
32
  readonly runningSubagentCount?: number;
33
33
  readonly completed?: boolean;
34
34
  }, t: Translate): SessionHoverStatus[];
35
- /** 0.1.7 会话标题在悬停时匀速滚到末尾,并交给样式做两端淡出。 */
35
+ /** 会话标题在悬停时匀速滚到末尾,并交给样式做两端淡出。 */
36
36
  export declare function placeSessionTitle(title: HTMLElement, left: number, range: number): void;
37
37
  export declare function restSessionTitle(title: HTMLElement): void;
38
38
  export declare function startSessionTitleMarquee(title: HTMLElement | null, frame: {
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { Input as HostInput } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ /** 和技能行一致的 22px 描边图标按钮。尺寸写在 style 上,不靠额外 CSS 覆盖宿主按钮。 */
4
+ export declare const rowIconStyle: React.CSSProperties;
5
+ /** 宿主没有多行输入。行数由 rows 控制,不再接收 Ant 的 autoSize。 */
6
+ export declare const TextArea: React.ForwardRefExoticComponent<React.TextareaHTMLAttributes<HTMLTextAreaElement> & React.RefAttributes<HTMLTextAreaElement>>;
7
+ export declare const Input: typeof HostInput;
8
+ /** 宿主 Modal 点遮罩会调用 onClose。捕获阶段拦住指定弹窗的遮罩点击,保留「点遮罩不关」。 */
9
+ export declare function blockHostModalBackdrop(event: MouseEvent, dialogClass: string): void;
@@ -110,22 +110,18 @@ export declare function hasCodexUiSidebar(entries: readonly unknown[] | undefine
110
110
  export interface SessionListState {
111
111
  readonly ids?: readonly string[];
112
112
  readonly byId?: Record<string, NativeSessionLike>;
113
- readonly current?: string | null;
114
113
  }
115
114
  export declare function filterTaskSessionState<T extends SessionListState>(state: T | undefined, scheduledIds?: ReadonlySet<string>): T;
116
115
  export interface WorkspaceListState {
117
116
  readonly items?: readonly NativeWorkspaceLike[];
118
117
  readonly archivedSessionIds?: readonly string[];
119
118
  }
120
- /** 旧宿主读 list.current;alpha.2 主视图改由 retainedBy.mainView 标记。 */
119
+ /** 0.2 主视图由 retainedBy.mainView 标记。 */
121
120
  export declare function resolveCurrentSessionId(snapshot: SessionListState | undefined): string | null;
122
121
  export interface ClientSessionOpenAccess {
123
122
  readonly uiWorkspace?: {
124
123
  openSession(id: string): void;
125
124
  };
126
- readonly sessions?: {
127
- open?(id: string): void;
128
- };
129
125
  readonly get?: (name: string) => unknown;
130
126
  readonly reflect?: {
131
127
  get?: (name: string) => unknown;
@@ -134,7 +130,7 @@ export interface ClientSessionOpenAccess {
134
130
  /** 不硬读 ctx.uiWorkspace:Cordis 未 inject 时读属性会抛,只能 reflect.get / get。 */
135
131
  export declare function resolveClientSessionOpenAccess(ctx: ClientSessionOpenAccess): ClientSessionOpenAccess;
136
132
  export declare function canOpenClientSession(access: ClientSessionOpenAccess): boolean;
137
- /** 官方 alpha.2 走 uiWorkspace.openSession;旧宿主继续 sessions.open。不硬注入 uiWorkspace。 */
133
+ /** 支持范围内的宿主都用 uiWorkspace.openSession。不硬读未注入的属性。 */
138
134
  export declare function openClientSession(access: ClientSessionOpenAccess, id: string): void;
139
135
  export declare function openScheduledSession(id: string, openRuntime?: (sessionId: string) => void, openHost?: (sessionId: string) => void): boolean;
140
136
  export interface EnsureOpenScheduledSessionInput {
@@ -1,6 +1,6 @@
1
1
  import type { Translate } from './contracts.js';
2
2
  import { type AutomationSortDirection, type AutomationSortKey, type SortPreferenceStorage } from './helpers.js';
3
- /** 设置页与侧栏总览共用的排序菜单。当前项可以存成默认。 */
3
+ /** 设置页与侧栏总览共用的排序菜单。当前项可以存成默认。基于官方原语 Menu 重构。 */
4
4
  export declare function SortMenu({ t, storage, storageKey, sortKey, sortDirection, onSelect, iconOnly, className, }: {
5
5
  readonly t: Translate;
6
6
  readonly storage?: SortPreferenceStorage;
@@ -8,7 +8,6 @@ export declare function SortMenu({ t, storage, storageKey, sortKey, sortDirectio
8
8
  readonly sortKey: AutomationSortKey;
9
9
  readonly sortDirection: AutomationSortDirection;
10
10
  readonly onSelect: (key: AutomationSortKey, direction: AutomationSortDirection) => void;
11
- readonly compact?: boolean;
12
11
  readonly iconOnly?: boolean;
13
12
  readonly className?: string;
14
13
  }): JSX.Element;
@@ -1,37 +1,20 @@
1
1
  /** 定时任务表单里新增工作区:只探测宿主服务,不硬读未注入的 ctx.workspaces。 */
2
- export declare class AddedWorkspaceMissingError extends Error {
2
+ export declare class WorkspacePickerUnavailableError extends Error {
3
+ readonly code = "workspace/picker-unavailable";
3
4
  constructor();
4
5
  }
5
- export interface HostWorkspaceCreator {
6
- pickDirectory(): Promise<string | undefined>;
7
- create(path: string): Promise<unknown>;
8
- }
9
- export interface WorkspaceProbe {
10
- readonly get?: (name: string) => unknown;
11
- readonly reflect?: {
12
- readonly get?: (name: string) => unknown;
13
- };
14
- }
15
- export declare function workspacePathKey(path: string): string;
16
- export declare function workspaceIdForPath(workspaces: readonly {
17
- readonly id: string;
18
- readonly path: string;
19
- }[], path: string): string | undefined;
20
- export declare function createdWorkspaceId(workspaces: readonly {
21
- readonly id: string;
22
- readonly path: string;
23
- }[], path: string): string;
24
- /** 只探测选目录。桌面优先用原生窗口;否则再调宿主服务。 */
25
- export declare function resolveDirectoryPicker(ctx: WorkspaceProbe): {
26
- pickDirectory(): Promise<string | undefined>;
27
- } | undefined;
28
- /** @deprecated 测试兼容。创建不再要求客户端 workspaces.create。 */
29
- export declare function resolveHostWorkspaceCreator(ctx: WorkspaceProbe): HostWorkspaceCreator | undefined;
30
- export declare function addRegisteredWorkspace(input: {
31
- readonly creator: HostWorkspaceCreator;
32
- readonly refresh: () => Promise<void>;
33
- readonly listed: () => readonly {
34
- readonly id: string;
35
- readonly path: string;
36
- }[];
37
- }): Promise<string | undefined>;
6
+ /**
7
+ * 在运行期探测宿主服务。Cordis 未 inject 时直接读属性会抛,所以先走 reflect.get,
8
+ * 再走 ctx.get;两者都不可用时才回退到普通属性读取。
9
+ * reflect.get 存在却返回 undefined 时不越过它硬读属性,避免读未注入的服务。
10
+ */
11
+ export declare function probeService(ctx: unknown, name: string): unknown;
12
+ /** 统一解析宿主选目录的返回值:字符串、{ path }、{ filePaths },取消则 undefined。 */
13
+ export declare function parsePickedPath(value: unknown): string | undefined;
14
+ /** 让宿主登记工作区;宿主没有该方法或拒绝时返回 false,调用方改走运行时登记。 */
15
+ export declare function createHostWorkspace(ctx: unknown, path: string): Promise<boolean>;
16
+ /**
17
+ * 选目录:桌面壳的原生窗口优先,其次依次尝试宿主暴露的选目录服务。
18
+ * 一个都不存在时抛 WorkspacePickerUnavailableError,让调用方决定如何提示。
19
+ */
20
+ export declare function pickHostDirectory(ctx: unknown): Promise<string | undefined>;
@@ -41,7 +41,7 @@ export interface ExecutorConfig {
41
41
  }
42
42
  /** 先应用官方预设的完整语义,再让无人值守审批 fail-closed。 */
43
43
  export declare function applyUnattendedPermission(presets: PermissionPresetService, session: unknown, permission: AutomationDefinition['permissionPreset']): void;
44
- /** 新宿主读 deriveMessages 投影;旧宿主和测试夹具再回退事件数组或弃用的同步快照。 */
44
+ /** 优先读 deriveMessages;没有投影时再读 snapshotEvents。数组入参只给测试夹具。 */
45
45
  export declare function hasAutomationSource(hint?: SessionOwnershipHint): boolean;
46
46
  /** 已弃用的同步历史读取,只给 session/event 没有增量或不完整时兜底。 */
47
47
  export declare function readSessionEvents(session: SessionEventReader): readonly SessionEventLike[];
@@ -64,5 +64,8 @@ export declare function resolveUpdateRuntime(ctx: {
64
64
  }): Runtime;
65
65
  export declare function shouldNotifyParent(target: Runtime, send?: unknown): boolean;
66
66
  export declare function isNewerVersion(currentValue: string, candidateValue: string): boolean;
67
+ /** 把刚安装的精确版本并进 profile 白名单。pnpm 每个包名只认第一条,所以必须并进已有 union。 */
68
+ export declare function mergeMinimumReleaseAgeExclude(yaml: string, packageSpec: string): string;
69
+ export declare function recordReleaseAgeExclude(profileDir: string, packageSpec: string): Promise<void>;
67
70
  export declare function registerPluginUpdater(ctx: Context, options: PluginUpdaterOptions): () => void;
68
71
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michengai/dsh-automation",
3
- "version": "0.1.66",
3
+ "version": "1.0.0",
4
4
  "description": "DSH Automation — 在独立 DSH Session 中按计划执行和管理编码任务 · Schedule and manage coding tasks in isolated DSH sessions",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.22.0",
@@ -68,28 +68,27 @@
68
68
  "test:matrix": "pnpm build && node scripts/test-version-matrix.mjs"
69
69
  },
70
70
  "dependencies": {
71
- "antd": "^6.6.5",
72
71
  "luxon": "^3.7.2",
73
72
  "zod": "^4.1.5"
74
73
  },
75
74
  "peerDependencies": {
76
- "@deepseek-ai/cordis": ">=4.0.1 <5.0.0 || 4.0.5-alpha.1 || 4.0.5-alpha.2",
77
- "@deepseek-ai/dsh-agent": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
78
- "@deepseek-ai/dsh-agent-default-model": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
79
- "@deepseek-ai/dsh-client-connection": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
80
- "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
81
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
82
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
83
- "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
84
- "@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
85
- "@deepseek-ai/dsh-llm": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
86
- "@deepseek-ai/dsh-permission-presets": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
87
- "@deepseek-ai/dsh-session": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
88
- "@deepseek-ai/dsh-storage-domain": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
89
- "@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
90
- "@deepseek-ai/dsh-user-approval": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
91
- "@deepseek-ai/dsh-workspace": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.2 || 0.2.1-alpha.3",
92
- "@deepseek-ai/schemastery": ">=3.18.1 <4.0.0 || 3.18.5-alpha.1 || 3.18.5-alpha.2",
75
+ "@deepseek-ai/cordis": ">=4.0.1 <5.0.0",
76
+ "@deepseek-ai/dsh-agent": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
77
+ "@deepseek-ai/dsh-agent-default-model": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
78
+ "@deepseek-ai/dsh-client-connection": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
79
+ "@deepseek-ai/dsh-client-locale": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
80
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
81
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
82
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
83
+ "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
84
+ "@deepseek-ai/dsh-llm": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
85
+ "@deepseek-ai/dsh-permission-presets": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
86
+ "@deepseek-ai/dsh-session": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
87
+ "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
88
+ "@deepseek-ai/dsh-tools": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
89
+ "@deepseek-ai/dsh-user-approval": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
90
+ "@deepseek-ai/dsh-workspace": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2",
91
+ "@deepseek-ai/schemastery": ">=3.18.1 <4.0.0",
93
92
  "react": "^18.2.0"
94
93
  },
95
94
  "peerDependenciesMeta": {
@@ -98,28 +97,28 @@
98
97
  }
99
98
  },
100
99
  "devDependencies": {
101
- "@deepseek-ai/cordis": "4.0.5-alpha.2",
102
- "@deepseek-ai/cordis-plugin-include": "1.0.10-alpha.2",
103
- "@deepseek-ai/dsh-agent": "0.2.1-alpha.3",
104
- "@deepseek-ai/dsh-agent-default-model": "0.2.1-alpha.3",
105
- "@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.3",
106
- "@deepseek-ai/dsh-agent-preset-registry": "0.2.1-alpha.3",
107
- "@deepseek-ai/dsh-client-connection": "0.2.1-alpha.3",
108
- "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.3",
109
- "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-alpha.3",
110
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.3",
111
- "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.3",
112
- "@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.3",
113
- "@deepseek-ai/dsh-llm": "0.2.1-alpha.3",
114
- "@deepseek-ai/dsh-permission-presets": "0.2.1-alpha.3",
115
- "@deepseek-ai/dsh-session": "0.2.1-alpha.3",
116
- "@deepseek-ai/dsh-session-projection": "0.2.1-alpha.3",
117
- "@deepseek-ai/dsh-storage-domain": "0.2.1-alpha.3",
118
- "@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.3",
119
- "@deepseek-ai/dsh-tools": "0.2.1-alpha.3",
120
- "@deepseek-ai/dsh-user-approval": "0.2.1-alpha.3",
121
- "@deepseek-ai/dsh-workspace": "0.2.1-alpha.3",
122
- "@deepseek-ai/schemastery": "3.18.5-alpha.2",
100
+ "@deepseek-ai/cordis": "4.0.5",
101
+ "@deepseek-ai/cordis-plugin-include": "1.0.10",
102
+ "@deepseek-ai/dsh-agent": "0.2.1-rc.2",
103
+ "@deepseek-ai/dsh-agent-default-model": "0.2.1-rc.2",
104
+ "@deepseek-ai/dsh-agent-loop": "0.2.1-rc.2",
105
+ "@deepseek-ai/dsh-agent-preset-registry": "0.2.1-rc.2",
106
+ "@deepseek-ai/dsh-client-connection": "0.2.1-rc.2",
107
+ "@deepseek-ai/dsh-client-locale": "0.2.1-rc.2",
108
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-rc.2",
109
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.2",
110
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.1-rc.2",
111
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-rc.2",
112
+ "@deepseek-ai/dsh-llm": "0.2.1-rc.2",
113
+ "@deepseek-ai/dsh-permission-presets": "0.2.1-rc.2",
114
+ "@deepseek-ai/dsh-session": "0.2.1-rc.2",
115
+ "@deepseek-ai/dsh-session-projection": "0.2.1-rc.2",
116
+ "@deepseek-ai/dsh-storage-domain": "0.2.1-rc.2",
117
+ "@deepseek-ai/dsh-system-prompt": "0.2.1-rc.2",
118
+ "@deepseek-ai/dsh-tools": "0.2.1-rc.2",
119
+ "@deepseek-ai/dsh-user-approval": "0.2.1-rc.2",
120
+ "@deepseek-ai/dsh-workspace": "0.2.1-rc.2",
121
+ "@deepseek-ai/schemastery": "3.18.5",
123
122
  "@types/js-yaml": "4.0.9",
124
123
  "@types/luxon": "^3.7.1",
125
124
  "@types/node": "^22.0.0",
@@ -1,2 +0,0 @@
1
- import type { Locale } from 'antd/es/locale/index.js';
2
- export declare function antdLocale(active: 'zh' | 'en'): Locale;