@co0ontty/wand 4.83.1 → 4.84.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 +4 -0
- package/dist/agent-dispatch.js +5 -1
- package/dist/ai-team-availability.d.ts +1 -1
- package/dist/ai-team-prompts.js +13 -4
- package/dist/ai-team-runner.d.ts +80 -5
- package/dist/ai-team-runner.js +332 -55
- package/dist/ai-team-types.d.ts +92 -5
- package/dist/ai-team-types.js +9 -2
- package/dist/build-info.json +3 -3
- package/dist/cli-api.d.ts +1 -0
- package/dist/cli-api.js +3 -0
- package/dist/cli.js +18 -1
- package/dist/commit-task-archive.d.ts +3 -1
- package/dist/commit-task-archive.js +21 -10
- package/dist/config.d.ts +1 -1
- package/dist/config.js +73 -0
- package/dist/conversation-mentions.d.ts +16 -0
- package/dist/conversation-mentions.js +32 -0
- package/dist/conversation-service.d.ts +90 -0
- package/dist/conversation-service.js +759 -0
- package/dist/conversation-session-preview.d.ts +9 -0
- package/dist/conversation-session-preview.js +47 -0
- package/dist/conversation-task-preview.d.ts +5 -0
- package/dist/conversation-task-preview.js +8 -0
- package/dist/conversation-types.d.ts +80 -0
- package/dist/conversation-types.js +7 -0
- package/dist/core-extension-host.d.ts +27 -0
- package/dist/core-extension-host.js +138 -0
- package/dist/core-runner.d.ts +86 -0
- package/dist/core-runner.js +757 -0
- package/dist/core-status-cli.d.ts +9 -0
- package/dist/core-status-cli.js +280 -0
- package/dist/core-turn-tracker.d.ts +12 -0
- package/dist/core-turn-tracker.js +36 -0
- package/dist/decision-runner.d.ts +6 -0
- package/dist/decision-runner.js +3 -1
- package/dist/decision-tool.d.ts +2 -0
- package/dist/decision-tool.js +49 -22
- package/dist/env-utils.d.ts +7 -3
- package/dist/env-utils.js +30 -5
- package/dist/git-quick-commit.d.ts +5 -0
- package/dist/git-quick-commit.js +9 -3
- package/dist/git-utils.js +2 -1
- package/dist/harness-engine.d.ts +110 -0
- package/dist/harness-engine.js +331 -0
- package/dist/mission-diff.js +2 -1
- package/dist/model-auto-assign.d.ts +50 -0
- package/dist/model-auto-assign.js +163 -0
- package/dist/model-group-runner.d.ts +4 -0
- package/dist/model-group-runner.js +72 -0
- package/dist/model-groups.d.ts +38 -0
- package/dist/model-groups.js +138 -0
- package/dist/models.d.ts +12 -0
- package/dist/models.js +102 -8
- package/dist/npm-update-utils.js +2 -1
- package/dist/openrouter-free-cli.d.ts +25 -0
- package/dist/openrouter-free-cli.js +109 -0
- package/dist/openrouter-free-models.d.ts +85 -0
- package/dist/openrouter-free-models.js +458 -0
- package/dist/openrouter-free-selection.d.ts +5 -0
- package/dist/openrouter-free-selection.js +7 -0
- package/dist/path-repair.d.ts +10 -0
- package/dist/path-repair.js +50 -5
- package/dist/pi-auto-resources.d.ts +12 -0
- package/dist/pi-auto-resources.js +151 -0
- package/dist/pi-execution-types.d.ts +48 -0
- package/dist/pi-execution-types.js +1 -0
- package/dist/pi-execution.d.ts +9 -0
- package/dist/pi-execution.js +187 -0
- package/dist/pi-extension-resources.d.ts +13 -0
- package/dist/pi-extension-resources.js +71 -0
- package/dist/pi-openrouter-free-bridge.d.ts +2 -0
- package/dist/pi-openrouter-free-bridge.js +80 -0
- package/dist/pi-resource-bridge.d.ts +2 -0
- package/dist/pi-resource-bridge.js +73 -0
- package/dist/pi-resource-catalog.d.ts +18 -0
- package/dist/pi-resource-catalog.js +82 -0
- package/dist/pi-resource-recommendation.d.ts +29 -0
- package/dist/pi-resource-recommendation.js +169 -0
- package/dist/pi-resource-run.d.ts +8 -0
- package/dist/pi-resource-run.js +28 -0
- package/dist/pi-session-settings.d.ts +157 -0
- package/dist/pi-session-settings.js +166 -0
- package/dist/platform-action-catalog.d.ts +24 -0
- package/dist/platform-action-catalog.js +141 -0
- package/dist/platform-action-service.d.ts +37 -0
- package/dist/platform-action-service.js +138 -0
- package/dist/platform-action-types.d.ts +125 -0
- package/dist/platform-action-types.js +7 -0
- package/dist/process-manager.d.ts +21 -1
- package/dist/process-manager.js +168 -15
- package/dist/provider-catalog.js +1 -1
- package/dist/provider-cli-updater.js +29 -8
- package/dist/provider-history-scanner.d.ts +9 -0
- package/dist/provider-history-scanner.js +107 -1
- package/dist/retention.d.ts +19 -7
- package/dist/retention.js +171 -28
- package/dist/server-ai-team-routes.js +6 -2
- package/dist/server-conversation-routes.d.ts +5 -0
- package/dist/server-conversation-routes.js +91 -0
- package/dist/server-employee-routes.d.ts +2 -0
- package/dist/server-employee-routes.js +85 -11
- package/dist/server-pi-recommendation-routes.d.ts +13 -0
- package/dist/server-pi-recommendation-routes.js +67 -0
- package/dist/server-resume-routes.js +1 -1
- package/dist/server-session-routes.d.ts +4 -3
- package/dist/server-session-routes.js +182 -37
- package/dist/server-settings-routes.d.ts +5 -0
- package/dist/server-settings-routes.js +46 -0
- package/dist/server-task-routes.js +49 -4
- package/dist/server-team-dispatch-routes.d.ts +19 -0
- package/dist/server-team-dispatch-routes.js +71 -0
- package/dist/server-update-routes.d.ts +1 -1
- package/dist/server-update-routes.js +10 -5
- package/dist/server-workspace-routes.js +44 -24
- package/dist/server.d.ts +1 -0
- package/dist/server.js +148 -30
- package/dist/session-ai-context.d.ts +5 -1
- package/dist/session-ai-context.js +9 -4
- package/dist/session-registry.d.ts +4 -0
- package/dist/session-registry.js +47 -13
- package/dist/session-transport.js +8 -1
- package/dist/settings-web-access.d.ts +15 -0
- package/dist/settings-web-access.js +37 -0
- package/dist/silicon-employee-defaults.d.ts +29 -0
- package/dist/silicon-employee-defaults.js +41 -0
- package/dist/silicon-employee-dispatch.d.ts +5 -1
- package/dist/silicon-employee-dispatch.js +10 -4
- package/dist/silicon-employee-draft.d.ts +21 -4
- package/dist/silicon-employee-draft.js +103 -16
- package/dist/storage.d.ts +73 -2
- package/dist/storage.js +362 -26
- package/dist/structured-claude-protocol.js +1 -1
- package/dist/structured-client-protocol.js +11 -33
- package/dist/structured-content.d.ts +23 -0
- package/dist/structured-content.js +72 -0
- package/dist/structured-failure.d.ts +16 -0
- package/dist/structured-failure.js +36 -0
- package/dist/structured-pi-adapter.d.ts +8 -3
- package/dist/structured-pi-adapter.js +131 -30
- package/dist/structured-provider-common.d.ts +6 -0
- package/dist/structured-provider-common.js +23 -1
- package/dist/structured-runner.d.ts +45 -0
- package/dist/structured-session-manager.d.ts +78 -4
- package/dist/structured-session-manager.js +513 -129
- package/dist/structured-thinking.d.ts +15 -0
- package/dist/structured-thinking.js +46 -0
- package/dist/subagent-dispatch.d.ts +56 -0
- package/dist/subagent-dispatch.js +102 -0
- package/dist/system-employee.d.ts +4 -3
- package/dist/system-employee.js +7 -4
- package/dist/task-retention.d.ts +23 -0
- package/dist/task-retention.js +69 -0
- package/dist/task-types.d.ts +4 -0
- package/dist/task-types.js +3 -0
- package/dist/team-dispatch.d.ts +101 -0
- package/dist/team-dispatch.js +269 -0
- package/dist/tool-preview.js +7 -1
- package/dist/tui/commands.js +50 -1
- package/dist/tui/ipc-protocol.d.ts +1 -1
- package/dist/tui/ipc-server.d.ts +4 -0
- package/dist/tui/ipc-server.js +23 -0
- package/dist/turn-heartbeat.d.ts +35 -0
- package/dist/turn-heartbeat.js +64 -0
- package/dist/types.d.ts +147 -1
- package/dist/user-profile.d.ts +33 -0
- package/dist/user-profile.js +70 -0
- package/dist/web-ui/chat-message-meta.d.ts +11 -0
- package/dist/web-ui/chat-message-meta.js +47 -0
- package/dist/web-ui/content/ai-teams.js +13 -13
- package/dist/web-ui/content/scripts.js +795 -95
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/content/tailwind.css +1 -6808
- package/dist/web-ui/content/vendor/qrcode/qrcode.bundle.js +1 -1
- package/dist/web-ui/embedded-assets.d.ts +1 -1
- package/dist/web-ui/embedded-assets.js +5 -5
- package/dist/web-ui/index.d.ts +1 -1
- package/dist/web-ui/index.js +3 -3
- package/dist/web-ui/markdown.d.ts +2 -0
- package/dist/web-ui/markdown.js +111 -0
- package/dist/web-ui/page.d.ts +4 -0
- package/dist/web-ui/page.js +8 -0
- package/dist/web-ui/react/local-preview/controller.d.ts +30 -0
- package/dist/web-ui/react/local-preview/controller.js +159 -0
- package/dist/web-ui/running-activity.d.ts +63 -0
- package/dist/web-ui/running-activity.js +134 -0
- package/dist/web-ui/styles.js +2 -11
- package/package.json +7 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DecisionResult } from "./decision-types.js";
|
|
1
2
|
import { EventEmitter } from "node:events";
|
|
2
3
|
import { WandStorage } from "./storage.js";
|
|
3
4
|
import { ExecutionMode, ProcessEventHandler, SessionProvider, SessionSnapshot, SessionSource, WandConfig } from "./types.js";
|
|
@@ -39,6 +40,8 @@ export interface ProcessManagerOptions {
|
|
|
39
40
|
ptyForegroundSampleMs?: number;
|
|
40
41
|
/** Overrides the foreground probe itself, so tests can drive it deterministically. */
|
|
41
42
|
samplePtyForegrounds?: typeof samplePtyForegrounds;
|
|
43
|
+
/** 本地决策入口;只有带首条提示词创建终端会话时用来结算「智能分配」。 */
|
|
44
|
+
resolveDecisionEvaluate?: () => ((value: unknown, caller: string, signal?: AbortSignal) => Promise<DecisionResult>) | undefined;
|
|
42
45
|
}
|
|
43
46
|
export declare class ProcessManager extends EventEmitter {
|
|
44
47
|
private readonly config;
|
|
@@ -52,6 +55,7 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
52
55
|
private readonly ptyForegroundSampleMs;
|
|
53
56
|
/** Foreground probe; injectable so tests can drive it without a real process table. */
|
|
54
57
|
private readonly probePtyForegrounds;
|
|
58
|
+
private readonly resolveDecisionEvaluate;
|
|
55
59
|
/** 24h archive scan timer */
|
|
56
60
|
private archiveTimer;
|
|
57
61
|
/** 前台进程组采样定时器(见 samplePtyForegrounds) */
|
|
@@ -68,6 +72,12 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
68
72
|
private orphanRecoveredCount;
|
|
69
73
|
private readonly topicCoordinator;
|
|
70
74
|
private readonly nativeTitles;
|
|
75
|
+
/**
|
|
76
|
+
* 静默期心跳:ptyBusy 且连续 TURN_QUIET_HEARTBEAT_MS 没有任何输出时,用现有的 status
|
|
77
|
+
* 事件重发一次 ptyBusy 事实与本轮锚点,证明「还在跑」。timer 只在回合在飞期间存在,
|
|
78
|
+
* clearPtyTurn / cleanupRecord / dispose 立即撤销。
|
|
79
|
+
*/
|
|
80
|
+
private readonly ptyHeartbeat;
|
|
71
81
|
private disposed;
|
|
72
82
|
private readonly terminalHost;
|
|
73
83
|
constructor(config: WandConfig, storage: WandStorage, configDir?: string, terminalHost?: TerminalHost, options?: ProcessManagerOptions);
|
|
@@ -100,6 +110,12 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
100
110
|
/** The quiet window elapsed: the CLI is back at its prompt, so the turn is done. */
|
|
101
111
|
private closePtyTurn;
|
|
102
112
|
private clearPtyTurn;
|
|
113
|
+
/**
|
|
114
|
+
* 静默窗口到期:确认这一轮仍在飞才补发,payload 与一次普通 ptyBusy status 事件同形
|
|
115
|
+
* (不带新字段、不用新事件类型)。停在权限裁决上的回合不广播「仍在运行」——那一屏
|
|
116
|
+
* 已有 pendingEscalation 这个显式指示,再说在跑是错的(保留窗口,等输出恢复)。
|
|
117
|
+
*/
|
|
118
|
+
private publishPtyQuietHeartbeat;
|
|
103
119
|
private bindTerminalProcess;
|
|
104
120
|
private handleTerminalResync;
|
|
105
121
|
private handleTerminalExit;
|
|
@@ -144,6 +160,9 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
144
160
|
deleteOpenCodeHistorySessions(sessionIds: string[]): number;
|
|
145
161
|
listQoderHistorySessions(): QoderHistorySession[];
|
|
146
162
|
deleteQoderHistoryFiles(sessionIds: string[]): number;
|
|
163
|
+
deletePiHistoryFiles(sessionIds: string[]): number;
|
|
164
|
+
deleteGrokHistoryFiles(sessionIds: string[]): number;
|
|
165
|
+
deleteGeminiHistoryFiles(sessionIds: string[]): number;
|
|
147
166
|
private captureCodexSessionId;
|
|
148
167
|
private captureOpenCodeSessionId;
|
|
149
168
|
private captureClaudeSessionId;
|
|
@@ -158,7 +177,8 @@ export declare class ProcessManager extends EventEmitter {
|
|
|
158
177
|
*/
|
|
159
178
|
setSessionModel(id: string, model: string | null): SessionSnapshot;
|
|
160
179
|
/**
|
|
161
|
-
*
|
|
180
|
+
* 归档会先停掉还在跑的终端,但保留会话 ID 和 provider session id,恢复时用它们续上。
|
|
181
|
+
* 取消归档只清标记;重新拉起由恢复入口负责。
|
|
162
182
|
*/
|
|
163
183
|
setSessionArchived(id: string, archived: boolean): SessionSnapshot;
|
|
164
184
|
/**
|
package/dist/process-manager.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { isOpenRouterFreeSelector } from "./openrouter-free-models.js";
|
|
2
|
+
import { isAutoAssignSelector, defaultModelGroupSelector, resolveModelGroupModels } from "./model-groups.js";
|
|
3
|
+
import { resolveAutoAssign } from "./model-auto-assign.js";
|
|
4
|
+
import { getDefaultModelForProvider } from "./config.js";
|
|
1
5
|
import { randomUUID } from "node:crypto";
|
|
2
6
|
import { EventEmitter } from "node:events";
|
|
3
7
|
import { existsSync, unlinkSync, rmSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
@@ -9,7 +13,7 @@ import { SessionLogger } from "./session-logger.js";
|
|
|
9
13
|
import { ClaudePtyBridge } from "./claude-pty-bridge.js";
|
|
10
14
|
import { truncateMessagesForTransport } from "./message-truncator.js";
|
|
11
15
|
import { appendWindow, hasExplicitConfirmSyntax, hasPermissionActionContext, normalizePromptText, PTY_OUTPUT_MAX_SIZE } from "./pty-text-utils.js";
|
|
12
|
-
import { buildChildEnv, isRunningAsRoot } from "./env-utils.js";
|
|
16
|
+
import { buildChildEnv, isRunningAsRoot, systemEnvValue } from "./env-utils.js";
|
|
13
17
|
import { buildLanguageDirective, buildManagedAutonomyDirective } from "./language-prompt.js";
|
|
14
18
|
import { prepareSessionWorktree } from "./git-worktree.js";
|
|
15
19
|
import { getProviderCommandSessionId, getProviderResumeCommandSessionId } from "./resume-policy.js";
|
|
@@ -17,11 +21,12 @@ import { commandWithSystemPrompt, composeSystemFallback, normalizeThinkingEffort
|
|
|
17
21
|
import { consumePtyInputForTopic, createPtyTopicLineBuffer, provisionalSessionTopic, SessionNativeTitleTracker, SessionTopicCoordinator, sessionTopicBlocklistForSnapshot, shouldAcceptGeneratedSessionTitle, shouldGenerateSessionTopicFromInput, } from "./session-topic.js";
|
|
18
22
|
import { readNativeSessionTitle } from "./native-session-title.js";
|
|
19
23
|
import { getErrorMessage } from "./error-utils.js";
|
|
24
|
+
import { TurnQuietHeartbeat } from "./turn-heartbeat.js";
|
|
20
25
|
import { recordIterationPrompt } from "./iteration-log.js";
|
|
21
26
|
import { describePtySpawnFailure } from "./ensure-node-pty-helper.js";
|
|
22
27
|
import { resolveSessionProvider, resolveSystemAiContext } from "./session-ai-context.js";
|
|
23
28
|
import { resolveSessionCwd } from "./session-cwd.js";
|
|
24
|
-
import { inferProviderFromCommand } from "./session-provider.js";
|
|
29
|
+
import { inferProviderFromCommand, providerCliCommand } from "./session-provider.js";
|
|
25
30
|
import { RETENTION_IDLE_MS } from "./retention.js";
|
|
26
31
|
import { PtyTerminalState } from "./pty-terminal-state.js";
|
|
27
32
|
import { isPtySubmitInput } from "./pty-turn-activity.js";
|
|
@@ -482,7 +487,7 @@ function restoreTerminalState(state) {
|
|
|
482
487
|
return terminal;
|
|
483
488
|
}
|
|
484
489
|
const MAX_SESSIONS = 200;
|
|
485
|
-
//
|
|
490
|
+
// 会话空闲 7 天后在这里自动归档,再由保留期扫描于 7 天后清理。任务窗口在设置里单独配置。
|
|
486
491
|
const ARCHIVE_AFTER_MS = RETENTION_IDLE_MS;
|
|
487
492
|
const CONFIRM_WINDOW_SIZE = 800;
|
|
488
493
|
/**
|
|
@@ -558,6 +563,7 @@ export class ProcessManager extends EventEmitter {
|
|
|
558
563
|
ptyForegroundSampleMs;
|
|
559
564
|
/** Foreground probe; injectable so tests can drive it without a real process table. */
|
|
560
565
|
probePtyForegrounds;
|
|
566
|
+
resolveDecisionEvaluate;
|
|
561
567
|
/** 24h archive scan timer */
|
|
562
568
|
archiveTimer = null;
|
|
563
569
|
/** 前台进程组采样定时器(见 samplePtyForegrounds) */
|
|
@@ -574,6 +580,12 @@ export class ProcessManager extends EventEmitter {
|
|
|
574
580
|
orphanRecoveredCount = 0;
|
|
575
581
|
topicCoordinator = new SessionTopicCoordinator();
|
|
576
582
|
nativeTitles = new SessionNativeTitleTracker();
|
|
583
|
+
/**
|
|
584
|
+
* 静默期心跳:ptyBusy 且连续 TURN_QUIET_HEARTBEAT_MS 没有任何输出时,用现有的 status
|
|
585
|
+
* 事件重发一次 ptyBusy 事实与本轮锚点,证明「还在跑」。timer 只在回合在飞期间存在,
|
|
586
|
+
* clearPtyTurn / cleanupRecord / dispose 立即撤销。
|
|
587
|
+
*/
|
|
588
|
+
ptyHeartbeat = new TurnQuietHeartbeat((sessionId) => this.publishPtyQuietHeartbeat(sessionId));
|
|
577
589
|
disposed = false;
|
|
578
590
|
terminalHost;
|
|
579
591
|
constructor(config, storage, configDir, terminalHost, options = {}) {
|
|
@@ -583,6 +595,7 @@ export class ProcessManager extends EventEmitter {
|
|
|
583
595
|
this.ptyTurnIdleMs = options.ptyTurnIdleMs ?? PTY_TURN_IDLE_MS;
|
|
584
596
|
this.ptyForegroundSampleMs = options.ptyForegroundSampleMs ?? PTY_FOREGROUND_SAMPLE_MS;
|
|
585
597
|
this.probePtyForegrounds = options.samplePtyForegrounds ?? samplePtyForegrounds;
|
|
598
|
+
this.resolveDecisionEvaluate = options.resolveDecisionEvaluate ?? (() => undefined);
|
|
586
599
|
this.terminalHost = terminalHost ?? new InProcessTerminalHost();
|
|
587
600
|
this.logger = new SessionLogger(configDir || path.join(process.env.HOME || process.cwd(), ".wand"), config.shortcutLogMaxBytes);
|
|
588
601
|
let startupCodexHistory = null;
|
|
@@ -802,7 +815,8 @@ export class ProcessManager extends EventEmitter {
|
|
|
802
815
|
initializeClaudeBridge(record, initialOutput) {
|
|
803
816
|
if (record.provider !== "claude" || !record.providerCliActive)
|
|
804
817
|
return;
|
|
805
|
-
|
|
818
|
+
// 新 bridge 接管 ptyBusy 与本轮锚点:从干净的一轮起步,锚点由 bridge 的翻转写入。
|
|
819
|
+
this.clearPtyTurn(record);
|
|
806
820
|
record.ptyBridge?.removeAllListeners();
|
|
807
821
|
record.ptyBridge = new ClaudePtyBridge({
|
|
808
822
|
sessionId: record.id,
|
|
@@ -839,7 +853,16 @@ export class ProcessManager extends EventEmitter {
|
|
|
839
853
|
return;
|
|
840
854
|
if (record.ptyBusy !== true) {
|
|
841
855
|
record.ptyBusy = true;
|
|
842
|
-
|
|
856
|
+
// 本轮起点:两个锚点同时落下,客户端据此算「这一轮跑了多久 / 多久没动静」。
|
|
857
|
+
const at = new Date().toISOString();
|
|
858
|
+
record.ptyTurnStartedAt = at;
|
|
859
|
+
record.ptyLastActivityAt = at;
|
|
860
|
+
this.ptyHeartbeat.observe(record.id);
|
|
861
|
+
this.emitEvent({
|
|
862
|
+
type: "status",
|
|
863
|
+
sessionId: record.id,
|
|
864
|
+
data: { ptyBusy: true, ptyTurnStartedAt: at, ptyLastActivityAt: at },
|
|
865
|
+
});
|
|
843
866
|
}
|
|
844
867
|
this.refreshPtyTurn(record);
|
|
845
868
|
}
|
|
@@ -847,6 +870,10 @@ export class ProcessManager extends EventEmitter {
|
|
|
847
870
|
refreshPtyTurn(record) {
|
|
848
871
|
if (record.ptyBridge || !this.canTrackPtyTurn(record))
|
|
849
872
|
return;
|
|
873
|
+
// 输出续期只动 lastActivityAt;turnStartedAt 留在本轮开始处,否则「已运行多久」
|
|
874
|
+
// 会被每次 chunk 重置。静默窗口跟着往后推。
|
|
875
|
+
record.ptyLastActivityAt = new Date().toISOString();
|
|
876
|
+
this.ptyHeartbeat.observe(record.id);
|
|
850
877
|
if (record.ptyTurnTimer)
|
|
851
878
|
clearTimeout(record.ptyTurnTimer);
|
|
852
879
|
const timer = setTimeout(() => {
|
|
@@ -864,13 +891,47 @@ export class ProcessManager extends EventEmitter {
|
|
|
864
891
|
if (record.ptyBusy !== true)
|
|
865
892
|
return;
|
|
866
893
|
record.ptyBusy = false;
|
|
867
|
-
this.emitEvent({
|
|
894
|
+
this.emitEvent({
|
|
895
|
+
type: "status",
|
|
896
|
+
sessionId: record.id,
|
|
897
|
+
// 锚点与 ptyBusy 一起收敛成 null,不残留「还在跑」的读数。
|
|
898
|
+
data: { ptyBusy: false, ptyTurnStartedAt: null, ptyLastActivityAt: null },
|
|
899
|
+
});
|
|
868
900
|
}
|
|
869
901
|
clearPtyTurn(record) {
|
|
870
902
|
if (record.ptyTurnTimer) {
|
|
871
903
|
clearTimeout(record.ptyTurnTimer);
|
|
872
904
|
record.ptyTurnTimer = null;
|
|
873
905
|
}
|
|
906
|
+
// ptyBusy 清 false 的一切路径(退回提示符、CLI 退出、finishProviderCli、stop、
|
|
907
|
+
// cleanupRecord)都经过这里:撤掉静默心跳,锚点一并回 null。
|
|
908
|
+
this.ptyHeartbeat.cancel(record.id);
|
|
909
|
+
record.ptyTurnStartedAt = null;
|
|
910
|
+
record.ptyLastActivityAt = null;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* 静默窗口到期:确认这一轮仍在飞才补发,payload 与一次普通 ptyBusy status 事件同形
|
|
914
|
+
* (不带新字段、不用新事件类型)。停在权限裁决上的回合不广播「仍在运行」——那一屏
|
|
915
|
+
* 已有 pendingEscalation 这个显式指示,再说在跑是错的(保留窗口,等输出恢复)。
|
|
916
|
+
*/
|
|
917
|
+
publishPtyQuietHeartbeat(id) {
|
|
918
|
+
if (this.disposed)
|
|
919
|
+
return false;
|
|
920
|
+
const record = this.sessions.get(id);
|
|
921
|
+
if (!record || record.ptyBusy !== true)
|
|
922
|
+
return false;
|
|
923
|
+
if (record.pendingEscalation || this.isPermissionBlocked(record))
|
|
924
|
+
return true;
|
|
925
|
+
this.emitEvent({
|
|
926
|
+
type: "status",
|
|
927
|
+
sessionId: id,
|
|
928
|
+
data: {
|
|
929
|
+
ptyBusy: true,
|
|
930
|
+
ptyTurnStartedAt: record.ptyTurnStartedAt ?? null,
|
|
931
|
+
ptyLastActivityAt: record.ptyLastActivityAt ?? null,
|
|
932
|
+
},
|
|
933
|
+
});
|
|
934
|
+
return true;
|
|
874
935
|
}
|
|
875
936
|
bindTerminalProcess(record, child, onVisibleChunk) {
|
|
876
937
|
child.onResync?.((state) => this.handleTerminalResync(record, child, state));
|
|
@@ -1039,6 +1100,8 @@ export class ProcessManager extends EventEmitter {
|
|
|
1039
1100
|
if (this.disposed)
|
|
1040
1101
|
return;
|
|
1041
1102
|
this.disposed = true;
|
|
1103
|
+
// 静默心跳不跨服务关闭存活;每个会话的 timer 也在 cleanupRecord 里单独撤销。
|
|
1104
|
+
this.ptyHeartbeat.dispose();
|
|
1042
1105
|
if (this.archiveTimer) {
|
|
1043
1106
|
clearInterval(this.archiveTimer);
|
|
1044
1107
|
this.archiveTimer = null;
|
|
@@ -1131,8 +1194,52 @@ export class ProcessManager extends EventEmitter {
|
|
|
1131
1194
|
async start(command, cwd, mode, initialInput, opts) {
|
|
1132
1195
|
if (this.disposed)
|
|
1133
1196
|
throw new Error("ProcessManager has been disposed.");
|
|
1197
|
+
if (isOpenRouterFreeSelector(opts?.model))
|
|
1198
|
+
throw new Error("免费分组仅支持 one 的 Agent 结构化对话。");
|
|
1134
1199
|
if (!opts?.interactiveShell)
|
|
1135
1200
|
this.assertCommandAllowed(command);
|
|
1201
|
+
const groupProvider = opts?.interactiveShell ? undefined : opts?.provider ?? inferProviderFromCommand(command);
|
|
1202
|
+
const configured = groupProvider ? getDefaultModelForProvider(this.config, groupProvider) : "";
|
|
1203
|
+
const requested = opts?.model?.trim();
|
|
1204
|
+
let selector = requested && requested !== "default" ? requested : configured;
|
|
1205
|
+
/** 「智能分配」在终端里结算后的落地选择器;不让会话停在哨兵上说不清实际用了什么。 */
|
|
1206
|
+
let autoAssignedSelector;
|
|
1207
|
+
// 终端在创建时就带着首条提示词(任务派发 / API)时,可以按提示词结算「智能分配」;
|
|
1208
|
+
// 交互式终端没有提示词,只能回落默认分组,不能靠猜。
|
|
1209
|
+
if (groupProvider && isAutoAssignSelector(selector)) {
|
|
1210
|
+
const prompt = initialInput?.trim() ?? "";
|
|
1211
|
+
// 没有提示词时的落地值:默认分组(没有分组时才是该工具配置的默认模型)。
|
|
1212
|
+
const fallbackGroup = defaultModelGroupSelector(this.config.modelGroups, groupProvider, undefined) ?? "";
|
|
1213
|
+
const fallback = fallbackGroup || (isAutoAssignSelector(configured) ? "" : configured);
|
|
1214
|
+
if (prompt) {
|
|
1215
|
+
const assigned = await resolveAutoAssign({
|
|
1216
|
+
provider: groupProvider,
|
|
1217
|
+
prompt,
|
|
1218
|
+
groups: this.config.modelGroups,
|
|
1219
|
+
evaluate: this.resolveDecisionEvaluate(),
|
|
1220
|
+
ai: resolveSystemAiContext({
|
|
1221
|
+
provider: groupProvider, runner: undefined, command: providerCliCommand(groupProvider),
|
|
1222
|
+
structuredState: undefined, selectedModel: null, thinkingEffort: opts?.thinkingEffort,
|
|
1223
|
+
}, this.config, this.storage.getSystemSiliconEmployee()),
|
|
1224
|
+
cwd: resolveSessionCwd(cwd, this.config.defaultCwd),
|
|
1225
|
+
language: this.config.language,
|
|
1226
|
+
});
|
|
1227
|
+
selector = assigned.selector || fallback;
|
|
1228
|
+
autoAssignedSelector = assigned.selector || fallback || undefined;
|
|
1229
|
+
if (assigned.group)
|
|
1230
|
+
console.info(`[AutoAssign] 终端会话使用分组「${assigned.group.name}」(${assigned.strategy})`);
|
|
1231
|
+
}
|
|
1232
|
+
else {
|
|
1233
|
+
console.info("[AutoAssign] 终端会话没有首条提示词,使用默认分组");
|
|
1234
|
+
selector = fallback;
|
|
1235
|
+
autoAssignedSelector = fallback || undefined;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
const preferredModels = groupProvider ? resolveModelGroupModels(this.config.modelGroups, groupProvider, selector, {
|
|
1239
|
+
preferDefault: !requested || requested === "default",
|
|
1240
|
+
}) : [requested ?? ""];
|
|
1241
|
+
if (preferredModels.some(isOpenRouterFreeSelector))
|
|
1242
|
+
throw new Error("免费模型分组仅支持 one 的 Agent 结构化对话。");
|
|
1136
1243
|
const baseCwd = resolveSessionCwd(cwd, this.config.defaultCwd);
|
|
1137
1244
|
const id = opts?.reuseId || randomUUID();
|
|
1138
1245
|
// When a session is being resumed under the same id, capture its prior
|
|
@@ -1178,9 +1285,11 @@ export class ProcessManager extends EventEmitter {
|
|
|
1178
1285
|
: opts?.provider ?? inferProviderFromCommand(command);
|
|
1179
1286
|
const effectiveMode = provider === "codex" ? "full-access" : mode;
|
|
1180
1287
|
const isClaudeProvider = provider === "claude";
|
|
1181
|
-
const selectedModel = opts?.model?.trim() || undefined;
|
|
1288
|
+
const selectedModel = autoAssignedSelector ?? (opts?.model?.trim() || undefined);
|
|
1289
|
+
// Resolve before touching a resume record/worktree; invalid groups must not disturb prior work.
|
|
1290
|
+
// PTY has no reliable pre-input acceptance fact: use the preferred member, never replay automatically.
|
|
1182
1291
|
const initialThinkingEffort = normalizeThinkingEffort(opts?.thinkingEffort);
|
|
1183
|
-
let processedCommand = this.processCommandForMode(command, effectiveMode, provider,
|
|
1292
|
+
let processedCommand = this.processCommandForMode(command, effectiveMode, provider, preferredModels[0], initialThinkingEffort);
|
|
1184
1293
|
// 会话级系统提示:provider 有系统提示开关就走开关(PTY 与结构化行为一致),没有就并进首条输入。
|
|
1185
1294
|
const systemPrompt = (opts?.systemPrompt ?? inheritedRole?.systemPrompt)?.trim() || undefined;
|
|
1186
1295
|
const initialInputText = initialInput && systemPrompt && !systemPromptFlag(provider)
|
|
@@ -1300,8 +1409,8 @@ export class ProcessManager extends EventEmitter {
|
|
|
1300
1409
|
WAND_AUTO_CONFIRM: record.autoApprovePermissions ? "1" : "0",
|
|
1301
1410
|
WAND_AUTO_EDIT: effectiveMode === "auto-edit" ? "1" : "0",
|
|
1302
1411
|
SHELL: this.config.shell,
|
|
1303
|
-
LANG:
|
|
1304
|
-
LC_CTYPE:
|
|
1412
|
+
LANG: systemEnvValue("LANG") || systemEnvValue("LC_ALL") || systemEnvValue("LC_CTYPE") || "C.UTF-8",
|
|
1413
|
+
LC_CTYPE: systemEnvValue("LC_CTYPE") || systemEnvValue("LANG") || systemEnvValue("LC_ALL") || "C.UTF-8",
|
|
1305
1414
|
}),
|
|
1306
1415
|
name: "xterm-256color",
|
|
1307
1416
|
// 使用 record 上由前端协商好的真实尺寸,避免"先 120 列、几百毫秒后再 resize"
|
|
@@ -1525,6 +1634,15 @@ export class ProcessManager extends EventEmitter {
|
|
|
1525
1634
|
deleteQoderHistoryFiles(sessionIds) {
|
|
1526
1635
|
return this.providerHistory.deleteQoderHistoryFiles(sessionIds);
|
|
1527
1636
|
}
|
|
1637
|
+
deletePiHistoryFiles(sessionIds) {
|
|
1638
|
+
return this.providerHistory.deletePiHistoryFiles(sessionIds);
|
|
1639
|
+
}
|
|
1640
|
+
deleteGrokHistoryFiles(sessionIds) {
|
|
1641
|
+
return this.providerHistory.deleteGrokHistoryFiles(sessionIds);
|
|
1642
|
+
}
|
|
1643
|
+
deleteGeminiHistoryFiles(sessionIds) {
|
|
1644
|
+
return this.providerHistory.deleteGeminiHistoryFiles(sessionIds);
|
|
1645
|
+
}
|
|
1528
1646
|
captureCodexSessionId(record, options) {
|
|
1529
1647
|
if (record.provider !== "codex" || record.claudeSessionId) {
|
|
1530
1648
|
return false;
|
|
@@ -1630,9 +1748,16 @@ export class ProcessManager extends EventEmitter {
|
|
|
1630
1748
|
setSessionModel(id, model) {
|
|
1631
1749
|
const record = this.mustGet(id);
|
|
1632
1750
|
const normalized = model?.trim() || null;
|
|
1751
|
+
const configured = record.provider ? getDefaultModelForProvider(this.config, record.provider) : "";
|
|
1752
|
+
const selector = normalized && normalized !== "default" ? normalized : configured;
|
|
1753
|
+
const members = resolveModelGroupModels(this.config.modelGroups, record.provider ?? "claude", selector, {
|
|
1754
|
+
preferDefault: !normalized || normalized === "default",
|
|
1755
|
+
});
|
|
1756
|
+
if (members.some(isOpenRouterFreeSelector))
|
|
1757
|
+
throw new Error("免费分组仅支持 one 的 Agent 结构化对话。");
|
|
1633
1758
|
record.selectedModel = normalized;
|
|
1634
1759
|
if (record.providerCliActive && record.provider === "claude" && record.status === "running" && record.ptyProcess) {
|
|
1635
|
-
const value =
|
|
1760
|
+
const value = members[0] && members[0] !== "default" ? members[0] : "default";
|
|
1636
1761
|
record.ptyProcess.write(`/model ${value}\r`);
|
|
1637
1762
|
}
|
|
1638
1763
|
this.persist(record);
|
|
@@ -1640,14 +1765,22 @@ export class ProcessManager extends EventEmitter {
|
|
|
1640
1765
|
return this.snapshot(record);
|
|
1641
1766
|
}
|
|
1642
1767
|
/**
|
|
1643
|
-
*
|
|
1768
|
+
* 归档会先停掉还在跑的终端,但保留会话 ID 和 provider session id,恢复时用它们续上。
|
|
1769
|
+
* 取消归档只清标记;重新拉起由恢复入口负责。
|
|
1644
1770
|
*/
|
|
1645
1771
|
setSessionArchived(id, archived) {
|
|
1772
|
+
if (archived && this.mustGet(id).status === "running") {
|
|
1773
|
+
this.stop(id);
|
|
1774
|
+
}
|
|
1646
1775
|
const record = this.mustGet(id);
|
|
1647
1776
|
record.archived = archived;
|
|
1648
|
-
record.archivedAt = archived ? new Date().toISOString() : null;
|
|
1777
|
+
record.archivedAt = archived ? (record.archivedAt ?? new Date().toISOString()) : null;
|
|
1649
1778
|
this.persist(record);
|
|
1650
|
-
this.emitEvent({
|
|
1779
|
+
this.emitEvent({
|
|
1780
|
+
type: "status",
|
|
1781
|
+
sessionId: id,
|
|
1782
|
+
data: { archived, archivedAt: record.archivedAt, claudeSessionId: record.claudeSessionId },
|
|
1783
|
+
});
|
|
1651
1784
|
return this.snapshot(record);
|
|
1652
1785
|
}
|
|
1653
1786
|
/**
|
|
@@ -1967,6 +2100,8 @@ export class ProcessManager extends EventEmitter {
|
|
|
1967
2100
|
delete(id) {
|
|
1968
2101
|
const record = this.mustGet(id);
|
|
1969
2102
|
// Always clear pending timers
|
|
2103
|
+
// 会话删除后迟到的回合回调要失效,静默心跳也不能再给不存在的会话发事件。
|
|
2104
|
+
this.ptyHeartbeat.cancel(id);
|
|
1970
2105
|
if (record.claudeTaskDiscoveryTimer) {
|
|
1971
2106
|
clearTimeout(record.claudeTaskDiscoveryTimer);
|
|
1972
2107
|
record.claudeTaskDiscoveryTimer = null;
|
|
@@ -2080,6 +2215,9 @@ export class ProcessManager extends EventEmitter {
|
|
|
2080
2215
|
providerCliActive: record.providerCliActive,
|
|
2081
2216
|
providerCliExitCode: record.providerCliExitCode,
|
|
2082
2217
|
ptyBusy: record.ptyBridge ? record.ptyBridge.isResponding() : record.ptyBusy === true,
|
|
2218
|
+
// 与 ptyBusy 同生命周期的本轮锚点。运行时事实:存储没有对应列,重启后为 null。
|
|
2219
|
+
ptyTurnStartedAt: record.ptyTurnStartedAt ?? null,
|
|
2220
|
+
ptyLastActivityAt: record.ptyLastActivityAt ?? null,
|
|
2083
2221
|
runner: "pty",
|
|
2084
2222
|
command: record.command,
|
|
2085
2223
|
cwd: record.cwd,
|
|
@@ -2494,12 +2632,27 @@ export class ProcessManager extends EventEmitter {
|
|
|
2494
2632
|
const responding = bridgeData?.isResponding === true;
|
|
2495
2633
|
if (record.ptyBusy !== responding) {
|
|
2496
2634
|
record.ptyBusy = responding;
|
|
2635
|
+
// Claude 的 bridge 精确知道回合边界:翻转为 busy 时落下本轮锚点并挂静默
|
|
2636
|
+
// 心跳;回复结束就一起清回 null。
|
|
2637
|
+
const at = responding ? new Date().toISOString() : null;
|
|
2638
|
+
record.ptyTurnStartedAt = at;
|
|
2639
|
+
record.ptyLastActivityAt = at;
|
|
2640
|
+
if (responding)
|
|
2641
|
+
this.ptyHeartbeat.observe(record.id);
|
|
2642
|
+
else
|
|
2643
|
+
this.ptyHeartbeat.cancel(record.id);
|
|
2497
2644
|
this.emitEvent({
|
|
2498
2645
|
type: "status",
|
|
2499
2646
|
sessionId: event.sessionId,
|
|
2500
|
-
data: { ptyBusy: responding },
|
|
2647
|
+
data: { ptyBusy: responding, ptyTurnStartedAt: at, ptyLastActivityAt: at },
|
|
2501
2648
|
});
|
|
2502
2649
|
}
|
|
2650
|
+
else if (responding) {
|
|
2651
|
+
// 回合仍在飞:每个 chat 事件都是活动证据,只续 lastActivityAt 与静默窗口,
|
|
2652
|
+
// 不额外广播(流式期间每 chunk 一条 status 会把 WS 刷爆)。
|
|
2653
|
+
record.ptyLastActivityAt = new Date().toISOString();
|
|
2654
|
+
this.ptyHeartbeat.observe(record.id);
|
|
2655
|
+
}
|
|
2503
2656
|
const data = {
|
|
2504
2657
|
permissionBlocked: this.isPermissionBlocked(record),
|
|
2505
2658
|
};
|
package/dist/provider-catalog.js
CHANGED
|
@@ -127,6 +127,12 @@ export function parseHomebrewInstall(executable) {
|
|
|
127
127
|
function isUpdateSupported(id, version) {
|
|
128
128
|
return !(id === "opencode" && version !== null && /^0\.0\./.test(version));
|
|
129
129
|
}
|
|
130
|
+
function isCodexOptionalDependencyError(error) {
|
|
131
|
+
return /Missing optional dependency\s+@openai\/codex-[\w-]+/.test(error ?? "");
|
|
132
|
+
}
|
|
133
|
+
function npmBin(options) {
|
|
134
|
+
return options.env?.WAND_NPM_BIN || process.env.WAND_NPM_BIN || (process.platform === "win32" ? "npm.cmd" : "npm");
|
|
135
|
+
}
|
|
130
136
|
export function providerCliUpdateAvailable(currentVersion, latestVersion) {
|
|
131
137
|
if (!currentVersion || !latestVersion)
|
|
132
138
|
return false;
|
|
@@ -160,9 +166,8 @@ async function readLatestVersion(spec, options, status) {
|
|
|
160
166
|
}
|
|
161
167
|
if (!spec.npmPackage)
|
|
162
168
|
return { version: null, error: "该 CLI 没有配置版本来源。" };
|
|
163
|
-
const npm = options.env?.WAND_NPM_BIN || process.env.WAND_NPM_BIN || (process.platform === "win32" ? "npm.cmd" : "npm");
|
|
164
169
|
try {
|
|
165
|
-
const result = await runCommand(
|
|
170
|
+
const result = await runCommand(npmBin(options), ["view", `${spec.npmPackage}@latest`, "version"], options.registryTimeoutMs ?? REGISTRY_TIMEOUT_MS, options);
|
|
166
171
|
const version = parseProviderCliVersion(result.stdout);
|
|
167
172
|
return version ? { version } : { version: null, error: "npm registry 未返回版本。" };
|
|
168
173
|
}
|
|
@@ -250,6 +255,7 @@ export async function checkProviderCliUpdates(options = {}) {
|
|
|
250
255
|
const installKind = resolveInstallKind(installed.executable, spec.id, installed.version);
|
|
251
256
|
const latest = await readLatestVersion(spec, options, { executable: installed.executable, installKind });
|
|
252
257
|
const updateSupported = isUpdateSupported(spec.id, installed.version);
|
|
258
|
+
const repairableCodexInstall = spec.id === "codex" && isCodexOptionalDependencyError(installed.error);
|
|
253
259
|
const errors = [installed.error, latest.error].filter(Boolean);
|
|
254
260
|
if (!updateSupported) {
|
|
255
261
|
errors.push("检测到已归档的 OpenCode 0.0.x;请先卸载旧包并安装 opencode-ai@latest。");
|
|
@@ -262,7 +268,7 @@ export async function checkProviderCliUpdates(options = {}) {
|
|
|
262
268
|
installed: installed.executable !== null,
|
|
263
269
|
currentVersion: installed.version,
|
|
264
270
|
latestVersion: latest.version,
|
|
265
|
-
updateAvailable: providerCliUpdateAvailable(installed.version, latest.version),
|
|
271
|
+
updateAvailable: repairableCodexInstall || providerCliUpdateAvailable(installed.version, latest.version),
|
|
266
272
|
updateSupported,
|
|
267
273
|
installKind,
|
|
268
274
|
...(errors.length ? { error: errors.join(";") } : {}),
|
|
@@ -335,10 +341,25 @@ export async function updateProviderClis(statuses, ids, options = {}) {
|
|
|
335
341
|
}
|
|
336
342
|
options.onLog?.(`[CLI Update] ${spec.label}: ${status.currentVersion} -> ${status.latestVersion}`);
|
|
337
343
|
try {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
344
|
+
const repairCodexInstall = spec.id === "codex" && isCodexOptionalDependencyError(status.error);
|
|
345
|
+
// Codex 的 Node shim 依赖平台 optional package;缺失时任何 `codex ...` 子命令都会先崩溃,只能用 npm 重装修复。
|
|
346
|
+
let output;
|
|
347
|
+
if (repairCodexInstall) {
|
|
348
|
+
output = await runCommand(npmBin(options), ["install", "-g", `${spec.npmPackage}@latest`, "--include=optional"], options.updateTimeoutMs ?? UPDATE_TIMEOUT_MS, options);
|
|
349
|
+
}
|
|
350
|
+
else if (spec.updateArgs) {
|
|
351
|
+
output = await runCommand(executable, spec.updateArgs, options.updateTimeoutMs ?? UPDATE_TIMEOUT_MS, options);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
// 没有自更新子命令的 CLI(Gemini)走它的 npm 发布渠道。
|
|
355
|
+
output = await runCommand(npmBin(options), ["install", "-g", `${spec.npmPackage}@latest`], options.updateTimeoutMs ?? UPDATE_TIMEOUT_MS, options);
|
|
356
|
+
}
|
|
357
|
+
if (spec.id === "codex") {
|
|
358
|
+
const verified = await readInstalledVersion(spec, options);
|
|
359
|
+
if (!verified.version) {
|
|
360
|
+
throw new Error(`Codex 更新后仍不可用:${verified.error ?? "无法读取版本。"}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
342
363
|
const combined = trimOutput([output.stdout, output.stderr].filter(Boolean).join("\n"));
|
|
343
364
|
results.push({
|
|
344
365
|
id: spec.id,
|
|
@@ -347,7 +368,7 @@ export async function updateProviderClis(statuses, ids, options = {}) {
|
|
|
347
368
|
skipped: false,
|
|
348
369
|
fromVersion: status.currentVersion,
|
|
349
370
|
toVersion: status.latestVersion,
|
|
350
|
-
message: `${spec.label} 更新命令执行完成。`,
|
|
371
|
+
message: repairCodexInstall ? `${spec.label} optional dependency 已修复。` : `${spec.label} 更新命令执行完成。`,
|
|
351
372
|
...(combined ? { output: combined } : {}),
|
|
352
373
|
});
|
|
353
374
|
}
|
|
@@ -48,6 +48,9 @@ export interface ProviderHistoryScannerOptions {
|
|
|
48
48
|
openCodeDatabasePath?: string;
|
|
49
49
|
/** Qoder and Qoder CN use separate config roots; callers may override both for tests. */
|
|
50
50
|
qoderProjectsDirs?: string[];
|
|
51
|
+
piSessionsDir?: string;
|
|
52
|
+
grokSessionsDir?: string;
|
|
53
|
+
geminiHome?: string;
|
|
51
54
|
}
|
|
52
55
|
/**
|
|
53
56
|
* Incremental provider-history index. Directory entries are refreshed on each
|
|
@@ -59,6 +62,9 @@ export declare class ProviderHistoryScanner {
|
|
|
59
62
|
private readonly codexSessionsDir;
|
|
60
63
|
private readonly openCodeDatabasePath;
|
|
61
64
|
private readonly qoderProjectsDirs;
|
|
65
|
+
private readonly piSessionsDir;
|
|
66
|
+
private readonly grokSessionsDir;
|
|
67
|
+
private readonly geminiHome;
|
|
62
68
|
private readonly claudeIndex;
|
|
63
69
|
private readonly codexIndex;
|
|
64
70
|
private readonly qoderIndex;
|
|
@@ -88,4 +94,7 @@ export declare class ProviderHistoryScanner {
|
|
|
88
94
|
deleteCodexHistoryFiles(threadIds: string[]): number;
|
|
89
95
|
deleteOpenCodeHistorySessions(sessionIds: string[]): number;
|
|
90
96
|
deleteQoderHistoryFiles(sessionIds: string[]): number;
|
|
97
|
+
deletePiHistoryFiles(sessionIds: string[]): number;
|
|
98
|
+
deleteGrokHistoryFiles(sessionIds: string[]): number;
|
|
99
|
+
deleteGeminiHistoryFiles(sessionIds: string[]): number;
|
|
91
100
|
}
|