@co0ontty/wand 4.89.5 → 4.90.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 +5 -3
- package/dist/agent-dispatch.js +4 -9
- package/dist/ai-team-employee-binding.js +10 -9
- package/dist/ai-team-runner.d.ts +2 -1
- package/dist/ai-team-runner.js +38 -2
- package/dist/ai-team-types.js +3 -2
- package/dist/ai-text-runner.d.ts +61 -0
- package/dist/ai-text-runner.js +653 -0
- package/dist/avatar-input.d.ts +2 -0
- package/dist/avatar-input.js +19 -0
- package/dist/bounded-process-output.d.ts +5 -0
- package/dist/bounded-process-output.js +9 -0
- package/dist/build-info.json +3 -3
- package/dist/command-error.d.ts +6 -0
- package/dist/command-error.js +8 -0
- package/dist/config.js +11 -42
- package/dist/conversation-service.d.ts +12 -2
- package/dist/conversation-service.js +104 -25
- package/dist/conversation-session-preview.d.ts +2 -0
- package/dist/conversation-session-preview.js +4 -0
- package/dist/decision-client.js +22 -6
- package/dist/decision-expert-employee.js +2 -2
- package/dist/decision-expert-identity.d.ts +1 -1
- package/dist/decision-expert-identity.js +1 -1
- package/dist/decision-expert-service.d.ts +1 -0
- package/dist/decision-expert-service.js +82 -76
- package/dist/decision-hardware.js +4 -3
- package/dist/decision-types.d.ts +4 -0
- package/dist/decision-types.js +4 -0
- package/dist/deployment-lock.d.ts +13 -0
- package/dist/deployment-lock.js +189 -0
- package/dist/employee-text.js +1 -1
- package/dist/fixed-employee-avatar.d.ts +7 -0
- package/dist/fixed-employee-avatar.js +13 -0
- package/dist/git-quick-commit.d.ts +5 -40
- package/dist/git-quick-commit.js +8 -636
- package/dist/hr-employee-identity.d.ts +5 -0
- package/dist/hr-employee-identity.js +5 -0
- package/dist/hr-employee.d.ts +5 -0
- package/dist/hr-employee.js +21 -0
- package/dist/middleware/path-safety.js +1 -1
- package/dist/milestone-scope.js +1 -1
- package/dist/model-auto-assign.d.ts +1 -1
- package/dist/model-auto-assign.js +1 -1
- package/dist/models.d.ts +4 -0
- package/dist/models.js +21 -1
- package/dist/npm-update-utils.js +5 -44
- package/dist/pi-auto-resources.js +6 -3
- package/dist/plush-avatar.d.ts +10 -1
- package/dist/plush-avatar.js +13 -1
- package/dist/plush-cat-appearance.d.ts +97 -0
- package/dist/plush-cat-appearance.js +118 -0
- package/dist/plush-cat-whiskers.d.ts +6 -0
- package/dist/plush-cat-whiskers.js +42 -0
- package/dist/process-manager.d.ts +22 -21
- package/dist/process-manager.js +49 -83
- package/dist/prompt-optimizer.d.ts +1 -1
- package/dist/prompt-optimizer.js +1 -1
- package/dist/render-host.js +1 -19
- package/dist/scheduled-task-service.d.ts +41 -0
- package/dist/scheduled-task-service.js +294 -0
- package/dist/scheduled-task-state.d.ts +11 -0
- package/dist/scheduled-task-state.js +65 -0
- package/dist/scheduled-task-time.d.ts +4 -0
- package/dist/scheduled-task-time.js +82 -0
- package/dist/scheduled-task-types.d.ts +71 -0
- package/dist/scheduled-task-types.js +1 -0
- package/dist/server-ai-team-routes.js +3 -17
- package/dist/server-employee-routes.d.ts +3 -0
- package/dist/server-employee-routes.js +20 -38
- package/dist/server-file-routes.js +44 -1
- package/dist/server-pi-recommendation-routes.js +13 -4
- package/dist/server-request.d.ts +2 -0
- package/dist/server-request.js +9 -0
- package/dist/server-resume-routes.js +1 -1
- package/dist/server-scheduled-task-routes.d.ts +4 -0
- package/dist/server-scheduled-task-routes.js +34 -0
- package/dist/server-session-routes.d.ts +5 -13
- package/dist/server-session-routes.js +35 -70
- package/dist/server-task-routes.d.ts +6 -21
- package/dist/server-task-routes.js +25 -120
- package/dist/server-team-dispatch-routes.js +12 -2
- package/dist/server-workspace-routes.d.ts +1 -1
- package/dist/server-workspace-routes.js +33 -78
- package/dist/server.js +55 -20
- package/dist/session-model.d.ts +15 -0
- package/dist/session-model.js +23 -0
- package/dist/session-registry.d.ts +5 -1
- package/dist/session-registry.js +20 -11
- package/dist/session-request.d.ts +9 -0
- package/dist/session-request.js +27 -0
- package/dist/session-topic.d.ts +1 -1
- package/dist/session-topic.js +1 -1
- package/dist/session-transport.d.ts +3 -1
- package/dist/session-transport.js +11 -5
- package/dist/silicon-employee-draft.d.ts +2 -2
- package/dist/silicon-employee-draft.js +3 -3
- package/dist/socket-probe.d.ts +2 -0
- package/dist/socket-probe.js +20 -0
- package/dist/storage-schedules.d.ts +20 -0
- package/dist/storage-schedules.js +78 -0
- package/dist/storage-schema.d.ts +3 -0
- package/dist/storage-schema.js +702 -0
- package/dist/storage.d.ts +42 -8
- package/dist/storage.js +182 -715
- package/dist/structured-claude-adapter.js +12 -0
- package/dist/structured-claude-protocol.d.ts +4 -0
- package/dist/structured-claude-protocol.js +18 -4
- package/dist/structured-codex-adapter.js +11 -0
- package/dist/structured-exec-pump.js +79 -38
- package/dist/structured-failure.d.ts +21 -0
- package/dist/structured-failure.js +14 -0
- package/dist/structured-gemini-adapter.js +12 -2
- package/dist/structured-grok-adapter.js +12 -2
- package/dist/structured-opencode-adapter.js +8 -1
- package/dist/structured-qoder-adapter.js +14 -0
- package/dist/structured-session-manager.d.ts +13 -18
- package/dist/structured-session-manager.js +147 -517
- package/dist/system-employee.d.ts +1 -1
- package/dist/system-employee.js +1 -1
- package/dist/task-archive-policy.js +1 -1
- package/dist/task-read-model.d.ts +27 -0
- package/dist/task-read-model.js +47 -0
- package/dist/task-retention.d.ts +1 -1
- package/dist/task-retention.js +1 -1
- package/dist/task-title-service.d.ts +30 -0
- package/dist/task-title-service.js +122 -0
- package/dist/task-title.d.ts +1 -1
- package/dist/task-title.js +1 -1
- package/dist/terminal-daemon-client.js +1 -18
- package/dist/user-memory.js +1 -1
- package/dist/web-ui/asset-runtime.d.ts +12 -0
- package/dist/web-ui/asset-runtime.js +6 -0
- package/dist/web-ui/composer-avatar-activity.d.ts +6 -0
- package/dist/web-ui/composer-avatar-activity.js +29 -0
- package/dist/web-ui/content/ai-teams.js +13 -13
- package/dist/web-ui/content/module-manifest.json +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chat-render-PY6DIXNZ.js +24 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-2YZLCGYN.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-6CFHW3FA.js +111 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-6XQEBIEX.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-DDSO7OX7.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-G3CXNMA2.js +20 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-LGVAPHRS.js +36 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-NURCNMRU.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-PCMFGZKX.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-QRNA4D7E.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-TMRPHNJO.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-WC7RK7LP.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-YOXXNXOX.js +2 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-YX475LXO.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/employee-card-MDWKU4V3.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-56WPSON2.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-5QOHKHNC.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-AWIJ5L2K.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-BOZLGIT5.js +69 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-EZV22Q7Y.js +4 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-IW43Z5ZF.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-JT7NIUQL.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-JWEIDB55.js +3 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-OU5TRYH6.js +2 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-PRSTCPVE.js +5 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-TWPJI3HE.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-WZGJSNML.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-X6KQVFD6.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-YKCQFMQR.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-bridge-2LZX6UUZ.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/library-bridge-MQFJGTGY.js +4 -0
- package/dist/web-ui/content/modules/5478be410b112154/page-T3VUCU2W.js +3 -0
- package/dist/web-ui/content/modules/5478be410b112154/panel-HJBGBBPY.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/runtime.js +920 -0
- package/dist/web-ui/content/modules/5478be410b112154/sha256-ANXV72UC.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/task-board-host-AVMDIHIV.js +2 -0
- package/dist/web-ui/content/modules/5478be410b112154/workspace-agent-picker-KI7QVSK3.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/workspace-window-L542FGP2.js +1 -0
- package/dist/web-ui/content/plush-avatar.js +177 -177
- package/dist/web-ui/content/scripts.js +1 -994
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/content/tailwind.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +32 -0
- package/dist/web-ui/embedded-assets.js +10 -8
- package/dist/web-ui/markdown.d.ts +3 -2
- package/dist/web-ui/markdown.js +61 -48
- package/dist/web-ui/message-file-target.d.ts +13 -0
- package/dist/web-ui/message-file-target.js +85 -0
- package/dist/web-ui/provider-identity.d.ts +1 -1
- package/dist/web-ui/provider-identity.js +3 -4
- package/dist/web-ui/react/local-preview/controller.d.ts +2 -0
- package/dist/web-ui/react/local-preview/controller.js +12 -0
- package/dist/web-ui/scripts.d.ts +10 -0
- package/dist/web-ui/scripts.js +42 -5
- package/package.json +6 -3
- package/browser-extension/icons/wand-128.png +0 -0
- package/browser-extension/icons/wand-16.png +0 -0
- package/browser-extension/icons/wand-32.png +0 -0
- package/browser-extension/icons/wand-48.png +0 -0
- package/dist/web-ui/content/licenses/codex-LICENSE.txt +0 -21
|
@@ -45,10 +45,29 @@ export interface ProcessManagerOptions {
|
|
|
45
45
|
/** 本地决策入口;只有带首条提示词创建终端会话时用来结算「智能分配」。 */
|
|
46
46
|
resolveDecisionEvaluate?: () => ((value: unknown, caller: string, signal?: AbortSignal) => Promise<DecisionResult>) | undefined;
|
|
47
47
|
}
|
|
48
|
+
export interface ProcessStartOptions extends Pick<SessionSnapshot, "employeeId" | "employeeName" | "employeeAvatar"> {
|
|
49
|
+
resumedFromSessionId?: string;
|
|
50
|
+
autoRecovered?: boolean;
|
|
51
|
+
worktreeEnabled?: boolean;
|
|
52
|
+
provider?: SessionProvider;
|
|
53
|
+
model?: string;
|
|
54
|
+
reuseId?: string;
|
|
55
|
+
cols?: number;
|
|
56
|
+
rows?: number;
|
|
57
|
+
thinkingEffort?: SessionSnapshot["thinkingEffort"];
|
|
58
|
+
sessionSource?: SessionSource;
|
|
59
|
+
automationId?: string;
|
|
60
|
+
workspaceId?: string;
|
|
61
|
+
workspaceTaskId?: string;
|
|
62
|
+
interactiveShell?: boolean;
|
|
63
|
+
systemPrompt?: string;
|
|
64
|
+
}
|
|
48
65
|
export declare class ProcessManager extends EventEmitter {
|
|
49
66
|
private readonly config;
|
|
50
67
|
private readonly storage;
|
|
51
68
|
private readonly sessions;
|
|
69
|
+
/** Own the full start handshake, including model resolution and late host replies. */
|
|
70
|
+
private readonly startingSessions;
|
|
52
71
|
private readonly logger;
|
|
53
72
|
private readonly providerHistory;
|
|
54
73
|
/** Quiet window for the non-Claude PTY turn tracker. */
|
|
@@ -59,8 +78,6 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
59
78
|
private readonly probePtyForegrounds;
|
|
60
79
|
private readonly free;
|
|
61
80
|
private readonly resolveDecisionEvaluate;
|
|
62
|
-
/** 24h archive scan timer */
|
|
63
|
-
private archiveTimer;
|
|
64
81
|
/** 前台进程组采样定时器(见 samplePtyForegrounds) */
|
|
65
82
|
private ptyForegroundTimer;
|
|
66
83
|
/** 采样是 async 的,避免慢 ps 重叠成多个进程 */
|
|
@@ -129,24 +146,8 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
129
146
|
/** Stop all live work and flush pending state before storage is closed. */
|
|
130
147
|
dispose(): void;
|
|
131
148
|
private emitEvent;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
resumedFromSessionId?: string;
|
|
135
|
-
autoRecovered?: boolean;
|
|
136
|
-
worktreeEnabled?: boolean;
|
|
137
|
-
provider?: SessionProvider;
|
|
138
|
-
model?: string;
|
|
139
|
-
reuseId?: string;
|
|
140
|
-
cols?: number;
|
|
141
|
-
rows?: number;
|
|
142
|
-
thinkingEffort?: SessionSnapshot["thinkingEffort"];
|
|
143
|
-
sessionSource?: SessionSource;
|
|
144
|
-
automationId?: string;
|
|
145
|
-
workspaceId?: string;
|
|
146
|
-
workspaceTaskId?: string;
|
|
147
|
-
interactiveShell?: boolean;
|
|
148
|
-
systemPrompt?: string;
|
|
149
|
-
} & Pick<SessionSnapshot, "employeeId" | "employeeName" | "employeeAvatar">): Promise<SessionSnapshot>;
|
|
149
|
+
start(command: string, cwd: string | undefined, mode: ExecutionMode, initialInput?: string, opts?: ProcessStartOptions): Promise<SessionSnapshot>;
|
|
150
|
+
private startSession;
|
|
150
151
|
list(): SessionSnapshot[];
|
|
151
152
|
/** Return lightweight snapshots for the session list (no output/messages). */
|
|
152
153
|
listSlim(): SessionSnapshot[];
|
|
@@ -172,6 +173,7 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
172
173
|
get(id: string): SessionSnapshot | null;
|
|
173
174
|
/** Return only a session owned by this manager, without the SQLite fallback used by get(). */
|
|
174
175
|
getOwned(id: string): SessionSnapshot | null;
|
|
176
|
+
getOwnedSlim(id: string): SessionSnapshot | null;
|
|
175
177
|
getPtyTranscript(id: string): string | null;
|
|
176
178
|
/**
|
|
177
179
|
* Set the Claude model for an existing PTY session. Persists the selection
|
|
@@ -256,7 +258,6 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
256
258
|
* Use this at critical points (exit, stop, delete) to ensure no data loss.
|
|
257
259
|
*/
|
|
258
260
|
private flushPersist;
|
|
259
|
-
private archiveExpiredSessions;
|
|
260
261
|
private assertCommandAllowed;
|
|
261
262
|
/**
|
|
262
263
|
* @deprecated Only retained for non-Claude-CLI sessions without ptyBridge.
|
package/dist/process-manager.js
CHANGED
|
@@ -27,7 +27,6 @@ import { describePtySpawnFailure } from "./ensure-node-pty-helper.js";
|
|
|
27
27
|
import { resolveSessionProvider, resolveSystemAiContext } from "./session-ai-context.js";
|
|
28
28
|
import { resolveSessionCwd } from "./session-cwd.js";
|
|
29
29
|
import { inferProviderFromCommand, isSessionProvider, providerCliCommand } from "./session-provider.js";
|
|
30
|
-
import { RETENTION_IDLE_MS } from "./retention.js";
|
|
31
30
|
import { PtyTerminalState } from "./pty-terminal-state.js";
|
|
32
31
|
import { isPtySubmitInput } from "./pty-turn-activity.js";
|
|
33
32
|
import { samplePtyForegrounds } from "./pty-foreground.js";
|
|
@@ -486,9 +485,6 @@ function restoreTerminalState(state) {
|
|
|
486
485
|
}
|
|
487
486
|
return terminal;
|
|
488
487
|
}
|
|
489
|
-
const MAX_SESSIONS = 200;
|
|
490
|
-
// 会话空闲 7 天后在这里自动归档,再由保留期扫描于 7 天后清理。任务窗口在设置里单独配置。
|
|
491
|
-
const ARCHIVE_AFTER_MS = RETENTION_IDLE_MS;
|
|
492
488
|
const CONFIRM_WINDOW_SIZE = 800;
|
|
493
489
|
/**
|
|
494
490
|
* Quiet window for the non-Claude PTY turn tracker: a submitted turn stays busy
|
|
@@ -555,6 +551,8 @@ export class ProcessManager extends EventEmitter {
|
|
|
555
551
|
config;
|
|
556
552
|
storage;
|
|
557
553
|
sessions = new Map();
|
|
554
|
+
/** Own the full start handshake, including model resolution and late host replies. */
|
|
555
|
+
startingSessions = new Map();
|
|
558
556
|
logger;
|
|
559
557
|
providerHistory = new ProviderHistoryScanner();
|
|
560
558
|
/** Quiet window for the non-Claude PTY turn tracker. */
|
|
@@ -565,8 +563,6 @@ export class ProcessManager extends EventEmitter {
|
|
|
565
563
|
probePtyForegrounds;
|
|
566
564
|
free;
|
|
567
565
|
resolveDecisionEvaluate;
|
|
568
|
-
/** 24h archive scan timer */
|
|
569
|
-
archiveTimer = null;
|
|
570
566
|
/** 前台进程组采样定时器(见 samplePtyForegrounds) */
|
|
571
567
|
ptyForegroundTimer = null;
|
|
572
568
|
/** 采样是 async 的,避免慢 ps 重叠成多个进程 */
|
|
@@ -698,16 +694,6 @@ export class ProcessManager extends EventEmitter {
|
|
|
698
694
|
this.orphanRecoveredCount += 1;
|
|
699
695
|
}
|
|
700
696
|
}
|
|
701
|
-
this.archiveExpiredSessions();
|
|
702
|
-
this.archiveTimer = setInterval(() => {
|
|
703
|
-
try {
|
|
704
|
-
this.archiveExpiredSessions();
|
|
705
|
-
}
|
|
706
|
-
catch (err) {
|
|
707
|
-
console.error(`[ProcessManager] archive scan failed: ${String(err)}`);
|
|
708
|
-
}
|
|
709
|
-
}, 60 * 1000);
|
|
710
|
-
this.archiveTimer.unref?.();
|
|
711
697
|
this.ptyForegroundTimer = setInterval(() => { void this.samplePtyForegrounds(); }, this.ptyForegroundSampleMs);
|
|
712
698
|
this.ptyForegroundTimer.unref?.();
|
|
713
699
|
}
|
|
@@ -1113,10 +1099,6 @@ export class ProcessManager extends EventEmitter {
|
|
|
1113
1099
|
this.disposed = true;
|
|
1114
1100
|
// 静默心跳不跨服务关闭存活;每个会话的 timer 也在 cleanupRecord 里单独撤销。
|
|
1115
1101
|
this.ptyHeartbeat.dispose();
|
|
1116
|
-
if (this.archiveTimer) {
|
|
1117
|
-
clearInterval(this.archiveTimer);
|
|
1118
|
-
this.archiveTimer = null;
|
|
1119
|
-
}
|
|
1120
1102
|
if (this.ptyForegroundTimer) {
|
|
1121
1103
|
clearInterval(this.ptyForegroundTimer);
|
|
1122
1104
|
this.ptyForegroundTimer = null;
|
|
@@ -1157,54 +1139,24 @@ export class ProcessManager extends EventEmitter {
|
|
|
1157
1139
|
return;
|
|
1158
1140
|
this.emit("process", event);
|
|
1159
1141
|
}
|
|
1160
|
-
cleanupOldSessions() {
|
|
1161
|
-
// Only clean up when well over the limit
|
|
1162
|
-
if (this.sessions.size < MAX_SESSIONS)
|
|
1163
|
-
return;
|
|
1164
|
-
const now = Date.now();
|
|
1165
|
-
const STALE_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
1166
|
-
const removable = [];
|
|
1167
|
-
for (const [id, record] of this.sessions) {
|
|
1168
|
-
// Only remove archived, non-running sessions older than 7 days
|
|
1169
|
-
if (record.status === "running")
|
|
1170
|
-
continue;
|
|
1171
|
-
if (!record.archived)
|
|
1172
|
-
continue;
|
|
1173
|
-
const ref = record.endedAt ?? record.startedAt;
|
|
1174
|
-
const refMs = Date.parse(ref);
|
|
1175
|
-
if (Number.isFinite(refMs) && now - refMs > STALE_MS) {
|
|
1176
|
-
removable.push(id);
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
// Sort oldest first and remove enough to get back under the limit
|
|
1180
|
-
const toRemove = removable
|
|
1181
|
-
.sort((a, b) => {
|
|
1182
|
-
const ra = this.sessions.get(a);
|
|
1183
|
-
const rb = this.sessions.get(b);
|
|
1184
|
-
return (ra?.endedAt || "").localeCompare(rb?.endedAt || "");
|
|
1185
|
-
})
|
|
1186
|
-
.slice(0, this.sessions.size - MAX_SESSIONS + 1);
|
|
1187
|
-
for (const id of toRemove) {
|
|
1188
|
-
const record = this.sessions.get(id);
|
|
1189
|
-
if (record) {
|
|
1190
|
-
this.logger.deleteSession(id);
|
|
1191
|
-
if (record.provider === "claude") {
|
|
1192
|
-
this.deleteClaudeCache(record);
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
this.sessions.delete(id);
|
|
1196
|
-
this.terminalHost.forget(id);
|
|
1197
|
-
this.lastPersistedMessageState.delete(id);
|
|
1198
|
-
this.dirtySessions.delete(id);
|
|
1199
|
-
this.storage.deleteSession(id);
|
|
1200
|
-
}
|
|
1201
|
-
if (toRemove.length > 0) {
|
|
1202
|
-
this.providerHistory.invalidate();
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
1142
|
async start(command, cwd, mode, initialInput, opts) {
|
|
1206
1143
|
if (this.disposed)
|
|
1207
1144
|
throw new Error("ProcessManager has been disposed.");
|
|
1145
|
+
const id = opts?.reuseId || randomUUID();
|
|
1146
|
+
// Host operations are keyed by session id, not by the manager record. A
|
|
1147
|
+
// second handshake must not adopt/forget a cancelled first incarnation.
|
|
1148
|
+
if (this.startingSessions.has(id))
|
|
1149
|
+
throw new Error("终端启动仍在进行,请等待本次启动结束后再恢复。");
|
|
1150
|
+
const start = { cancelled: false };
|
|
1151
|
+
this.startingSessions.set(id, start);
|
|
1152
|
+
try {
|
|
1153
|
+
return await this.startSession(id, start, command, cwd, mode, initialInput, opts);
|
|
1154
|
+
}
|
|
1155
|
+
finally {
|
|
1156
|
+
this.startingSessions.delete(id);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
async startSession(id, start, command, cwd, mode, initialInput, opts) {
|
|
1208
1160
|
if (isOpenRouterFreeSelector(opts?.model))
|
|
1209
1161
|
throw new Error("免费分组仅支持 Pi 结构化对话。");
|
|
1210
1162
|
if (!opts?.interactiveShell)
|
|
@@ -1252,7 +1204,8 @@ export class ProcessManager extends EventEmitter {
|
|
|
1252
1204
|
if (preferredModels.some(isOpenRouterFreeSelector))
|
|
1253
1205
|
throw new Error("免费模型分组仅支持 Pi 结构化对话。");
|
|
1254
1206
|
const baseCwd = resolveSessionCwd(cwd, this.config.defaultCwd);
|
|
1255
|
-
|
|
1207
|
+
if (this.disposed || start.cancelled)
|
|
1208
|
+
throw new Error("终端启动已取消。");
|
|
1256
1209
|
// When a session is being resumed under the same id, capture its prior
|
|
1257
1210
|
// structured messages so the new bridge can present them as the chat
|
|
1258
1211
|
// history. We deliberately do NOT carry over rawOutput — `claude --resume`
|
|
@@ -1407,7 +1360,6 @@ export class ProcessManager extends EventEmitter {
|
|
|
1407
1360
|
if (initialClaudeSessionId && (provider === "claude" || provider === "codex")) {
|
|
1408
1361
|
this.providerHistory.invalidate(provider);
|
|
1409
1362
|
}
|
|
1410
|
-
this.cleanupOldSessions();
|
|
1411
1363
|
let child;
|
|
1412
1364
|
try {
|
|
1413
1365
|
const attached = await this.terminalHost.createOrAttach({
|
|
@@ -1434,6 +1386,20 @@ export class ProcessManager extends EventEmitter {
|
|
|
1434
1386
|
throw new Error("Terminal host did not return a running process");
|
|
1435
1387
|
}
|
|
1436
1388
|
child = attached.process;
|
|
1389
|
+
if (this.disposed || start.cancelled || this.sessions.get(id) !== record) {
|
|
1390
|
+
// Explicit stop/delete still owns cancellation. Ordinary server shutdown
|
|
1391
|
+
// only detaches persistent hosts: the next server must be able to adopt
|
|
1392
|
+
// this in-progress spawn from the durable provisional record.
|
|
1393
|
+
if (start.cancelled || !this.terminalHost.persistent) {
|
|
1394
|
+
try {
|
|
1395
|
+
child.kill();
|
|
1396
|
+
}
|
|
1397
|
+
catch { /* best-effort cancellation */ }
|
|
1398
|
+
}
|
|
1399
|
+
if (!this.disposed)
|
|
1400
|
+
this.terminalHost.forget(id);
|
|
1401
|
+
throw new Error("终端启动已取消。");
|
|
1402
|
+
}
|
|
1437
1403
|
record.output = attached.state.output;
|
|
1438
1404
|
record.storedOutput = attached.state.output;
|
|
1439
1405
|
record.ptyOutputSeq = attached.state.seq;
|
|
@@ -1445,6 +1411,11 @@ export class ProcessManager extends EventEmitter {
|
|
|
1445
1411
|
this.initializeClaudeBridge(record, attached.state.output);
|
|
1446
1412
|
}
|
|
1447
1413
|
catch (err) {
|
|
1414
|
+
// stop/delete/dispose already committed the authoritative state. Neither
|
|
1415
|
+
// a late success nor failure may remove or resurrect that state.
|
|
1416
|
+
if (this.disposed || start.cancelled || this.sessions.get(id) !== record) {
|
|
1417
|
+
throw new Error("终端启动已取消。");
|
|
1418
|
+
}
|
|
1448
1419
|
console.error("[ProcessManager] terminal spawn failed", { sessionId: id, error: String(err) });
|
|
1449
1420
|
this.cleanupRecord(record, false);
|
|
1450
1421
|
this.sessions.delete(id);
|
|
@@ -1749,6 +1720,11 @@ export class ProcessManager extends EventEmitter {
|
|
|
1749
1720
|
result.output = record.storedOutput;
|
|
1750
1721
|
return result;
|
|
1751
1722
|
}
|
|
1723
|
+
getOwnedSlim(id) {
|
|
1724
|
+
this.terminalHost.flush?.();
|
|
1725
|
+
const record = this.sessions.get(id);
|
|
1726
|
+
return record ? this.snapshotSlim(record) : null;
|
|
1727
|
+
}
|
|
1752
1728
|
getPtyTranscript(id) {
|
|
1753
1729
|
return this.logger.readPtyOutputTail(id);
|
|
1754
1730
|
}
|
|
@@ -2004,6 +1980,9 @@ export class ProcessManager extends EventEmitter {
|
|
|
2004
1980
|
}
|
|
2005
1981
|
stop(id) {
|
|
2006
1982
|
const record = this.mustGet(id);
|
|
1983
|
+
const start = this.startingSessions.get(id);
|
|
1984
|
+
if (start)
|
|
1985
|
+
start.cancelled = true;
|
|
2007
1986
|
if (record.status !== "running") {
|
|
2008
1987
|
return this.snapshot(record);
|
|
2009
1988
|
}
|
|
@@ -2109,6 +2088,9 @@ export class ProcessManager extends EventEmitter {
|
|
|
2109
2088
|
}
|
|
2110
2089
|
delete(id) {
|
|
2111
2090
|
const record = this.mustGet(id);
|
|
2091
|
+
const start = this.startingSessions.get(id);
|
|
2092
|
+
if (start)
|
|
2093
|
+
start.cancelled = true;
|
|
2112
2094
|
// Always clear pending timers
|
|
2113
2095
|
// 会话删除后迟到的回合回调要失效,静默心跳也不能再给不存在的会话发事件。
|
|
2114
2096
|
this.ptyHeartbeat.cancel(id);
|
|
@@ -2563,22 +2545,6 @@ export class ProcessManager extends EventEmitter {
|
|
|
2563
2545
|
messagesDirty: forceFullSave,
|
|
2564
2546
|
});
|
|
2565
2547
|
}
|
|
2566
|
-
archiveExpiredSessions() {
|
|
2567
|
-
const now = Date.now();
|
|
2568
|
-
for (const record of this.sessions.values()) {
|
|
2569
|
-
if (record.archived || record.status === "running") {
|
|
2570
|
-
continue;
|
|
2571
|
-
}
|
|
2572
|
-
const referenceTime = record.endedAt ?? record.startedAt;
|
|
2573
|
-
const endedAtMs = Date.parse(referenceTime);
|
|
2574
|
-
if (!Number.isFinite(endedAtMs) || now - endedAtMs < ARCHIVE_AFTER_MS) {
|
|
2575
|
-
continue;
|
|
2576
|
-
}
|
|
2577
|
-
record.archived = true;
|
|
2578
|
-
record.archivedAt = new Date(now).toISOString();
|
|
2579
|
-
this.persist(record);
|
|
2580
|
-
}
|
|
2581
|
-
}
|
|
2582
2548
|
assertCommandAllowed(command) {
|
|
2583
2549
|
if (!isCommandAllowedByPrefixes(command, this.config.allowedCommandPrefixes)) {
|
|
2584
2550
|
throw new Error("Command is not allowed by current configuration.");
|
package/dist/prompt-optimizer.js
CHANGED
package/dist/render-host.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
3
|
-
import
|
|
3
|
+
import { probeUnixSocket as isSocketListening } from "./socket-probe.js";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { getErrorMessage } from "./error-utils.js";
|
|
6
6
|
import { isExecutableFile, readRenderBinaryVersion, resolveRenderBinaryPath } from "./render-binary.js";
|
|
@@ -351,24 +351,6 @@ function reapUnreadyRender(pid) {
|
|
|
351
351
|
const timer = setTimeout(() => signal("SIGKILL"), 500);
|
|
352
352
|
timer.unref?.();
|
|
353
353
|
}
|
|
354
|
-
/** 对端是否真的在监听:区分「活着但拒绝 adopt」与「上一轮崩溃留下的孤儿 socket 文件」。 */ function isSocketListening(socketPath) {
|
|
355
|
-
return new Promise((resolve) => {
|
|
356
|
-
const socket = net.createConnection(socketPath);
|
|
357
|
-
let settled = false;
|
|
358
|
-
const finish = (alive) => {
|
|
359
|
-
if (settled)
|
|
360
|
-
return;
|
|
361
|
-
settled = true;
|
|
362
|
-
clearTimeout(timer);
|
|
363
|
-
socket.destroy();
|
|
364
|
-
resolve(alive);
|
|
365
|
-
};
|
|
366
|
-
socket.once("connect", () => finish(true));
|
|
367
|
-
socket.once("error", () => finish(false));
|
|
368
|
-
const timer = setTimeout(() => finish(false), 300);
|
|
369
|
-
timer.unref?.();
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
354
|
function readLiveRenderPid(pidPath) {
|
|
373
355
|
let pid;
|
|
374
356
|
try {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ConversationService } from "./conversation-service.js";
|
|
2
|
+
import type { ScheduledTaskDetail, ScheduledTaskSummary } from "./scheduled-task-types.js";
|
|
3
|
+
import type { WandStorage } from "./storage.js";
|
|
4
|
+
import type { ProcessEvent, SessionSnapshot } from "./types.js";
|
|
5
|
+
export declare class ScheduledTaskConflictError extends Error {
|
|
6
|
+
}
|
|
7
|
+
export declare class ScheduledTaskNotFoundError extends Error {
|
|
8
|
+
}
|
|
9
|
+
/** Scheduling owns durable occurrences; employee execution and retries remain in the normal conversation protocol. */
|
|
10
|
+
export declare class ScheduledTaskService {
|
|
11
|
+
private readonly deps;
|
|
12
|
+
private timer;
|
|
13
|
+
private pendingTick;
|
|
14
|
+
private disposed;
|
|
15
|
+
private readonly liveAcceptedRuns;
|
|
16
|
+
constructor(deps: {
|
|
17
|
+
storage: WandStorage;
|
|
18
|
+
conversations: Pick<ConversationService, "send" | "receipt">;
|
|
19
|
+
getSession(id: string): SessionSnapshot | null;
|
|
20
|
+
defaultCwd?: () => string | undefined;
|
|
21
|
+
now?: () => Date;
|
|
22
|
+
});
|
|
23
|
+
private now;
|
|
24
|
+
private requireEmployee;
|
|
25
|
+
private requireWorkspaceCwd;
|
|
26
|
+
private executionDirectory;
|
|
27
|
+
private requireTask;
|
|
28
|
+
private runView;
|
|
29
|
+
private summary;
|
|
30
|
+
list(includeCancelled?: boolean): ScheduledTaskSummary[];
|
|
31
|
+
get(id: string): ScheduledTaskDetail;
|
|
32
|
+
create(value: unknown): ScheduledTaskSummary;
|
|
33
|
+
update(id: string, value: unknown): ScheduledTaskSummary;
|
|
34
|
+
private reconcile;
|
|
35
|
+
/** Capture the original turn's terminal fact before a user can start another turn in the same session. */
|
|
36
|
+
ingestSessionEvent(event: ProcessEvent): void;
|
|
37
|
+
tick(): Promise<void>;
|
|
38
|
+
private runTick;
|
|
39
|
+
start(intervalMs?: number): void;
|
|
40
|
+
dispose(): Promise<void>;
|
|
41
|
+
}
|