adhdev 0.8.21 → 0.8.24
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/dist/cli/index.js +1163 -304
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1163 -304
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -84,7 +84,8 @@ function normalizeConfig(raw) {
|
|
|
84
84
|
providerSettings: isPlainObject(parsed.providerSettings) ? parsed.providerSettings : {},
|
|
85
85
|
ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
|
|
86
86
|
disableUpstream: asBoolean(parsed.disableUpstream, DEFAULT_CONFIG.disableUpstream ?? false),
|
|
87
|
-
providerDir: asOptionalString(parsed.providerDir)
|
|
87
|
+
providerDir: asOptionalString(parsed.providerDir),
|
|
88
|
+
terminalSizingMode: parsed.terminalSizingMode === "fit" ? "fit" : "measured"
|
|
88
89
|
};
|
|
89
90
|
}
|
|
90
91
|
function generateMachineId() {
|
|
@@ -232,7 +233,8 @@ var init_config = __esm({
|
|
|
232
233
|
registeredMachineId: void 0,
|
|
233
234
|
providerSettings: {},
|
|
234
235
|
ideSettings: {},
|
|
235
|
-
disableUpstream: false
|
|
236
|
+
disableUpstream: false,
|
|
237
|
+
terminalSizingMode: "measured"
|
|
236
238
|
};
|
|
237
239
|
MACHINE_ID_PREFIX = "mach_";
|
|
238
240
|
}
|
|
@@ -2457,204 +2459,97 @@ var init_status_monitor = __esm({
|
|
|
2457
2459
|
}
|
|
2458
2460
|
});
|
|
2459
2461
|
|
|
2460
|
-
// ../../oss/packages/daemon-core/src/providers/
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
this.monitor.updateConfig({
|
|
2502
|
-
approvalAlert: this.settings.approvalAlert !== false,
|
|
2503
|
-
longGeneratingAlert: this.settings.longGeneratingAlert !== false,
|
|
2504
|
-
longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
|
|
2505
|
-
});
|
|
2506
|
-
}
|
|
2507
|
-
async onTick() {
|
|
2508
|
-
if (!this.context?.cdp?.isConnected) return;
|
|
2509
|
-
}
|
|
2510
|
-
getState() {
|
|
2511
|
-
return {
|
|
2512
|
-
type: this.type,
|
|
2513
|
-
name: this.provider.name,
|
|
2514
|
-
category: "extension",
|
|
2515
|
-
status: this.currentStatus,
|
|
2516
|
-
activeChat: this.messages.length > 0 ? {
|
|
2517
|
-
id: this.chatId || this.instanceId,
|
|
2518
|
-
title: this.chatTitle || this.agentName || this.provider.name,
|
|
2519
|
-
status: this.currentStatus,
|
|
2520
|
-
messages: this.messages,
|
|
2521
|
-
activeModal: this.activeModal,
|
|
2522
|
-
inputContent: ""
|
|
2523
|
-
} : null,
|
|
2524
|
-
currentModel: this.currentModel || void 0,
|
|
2525
|
-
currentPlan: this.currentMode || void 0,
|
|
2526
|
-
controlValues: this.controlValues,
|
|
2527
|
-
providerControls: this.provider.controls,
|
|
2528
|
-
agentStreams: this.agentStreams,
|
|
2529
|
-
instanceId: this.instanceId,
|
|
2530
|
-
lastUpdated: Date.now(),
|
|
2531
|
-
settings: this.settings,
|
|
2532
|
-
pendingEvents: this.flushEvents()
|
|
2533
|
-
};
|
|
2534
|
-
}
|
|
2535
|
-
onEvent(event, data) {
|
|
2536
|
-
if (event === "stream_update") {
|
|
2537
|
-
if (data?.streams) this.agentStreams = data.streams;
|
|
2538
|
-
if (data?.messages) this.messages = data.messages;
|
|
2539
|
-
if (data?.activeModal !== void 0) this.activeModal = data.activeModal;
|
|
2540
|
-
if (data?.model) this.currentModel = data.model;
|
|
2541
|
-
if (data?.mode) this.currentMode = data.mode;
|
|
2542
|
-
if (data?.controlValues) this.controlValues = data.controlValues;
|
|
2543
|
-
if (typeof data?.sessionId === "string" && data.sessionId.trim()) this.chatId = data.sessionId;
|
|
2544
|
-
if (typeof data?.title === "string" && data.title.trim()) this.chatTitle = data.title;
|
|
2545
|
-
if (typeof data?.agentName === "string" && data.agentName.trim()) this.agentName = data.agentName;
|
|
2546
|
-
if (typeof data?.extensionId === "string" && data.extensionId.trim()) this.extensionId = data.extensionId;
|
|
2547
|
-
if (data?.status) {
|
|
2548
|
-
const newStatus = data.status;
|
|
2549
|
-
this.detectTransition(newStatus, data);
|
|
2550
|
-
this.currentStatus = newStatus;
|
|
2551
|
-
}
|
|
2552
|
-
} else if (event === "stream_reset") {
|
|
2553
|
-
this.resetStreamState();
|
|
2554
|
-
} else if (event === "extension_connected") {
|
|
2555
|
-
this.ideType = data?.ideType || "";
|
|
2462
|
+
// ../../oss/packages/daemon-core/src/providers/control-effects.ts
|
|
2463
|
+
function extractProviderControlValues(controls, data) {
|
|
2464
|
+
if (!data || typeof data !== "object") return void 0;
|
|
2465
|
+
const values = {};
|
|
2466
|
+
const explicit = data.controlValues;
|
|
2467
|
+
if (explicit && typeof explicit === "object") {
|
|
2468
|
+
for (const [key, value] of Object.entries(explicit)) {
|
|
2469
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
2470
|
+
values[key] = value;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
for (const ctrl of controls || []) {
|
|
2475
|
+
if (!ctrl.readFrom) continue;
|
|
2476
|
+
const rawValue = data[ctrl.readFrom];
|
|
2477
|
+
if (rawValue === void 0 || rawValue === null) continue;
|
|
2478
|
+
values[ctrl.id] = normalizeControlValue(rawValue);
|
|
2479
|
+
}
|
|
2480
|
+
if (data.model !== void 0 && values.model === void 0) values.model = normalizeControlValue(data.model);
|
|
2481
|
+
if (data.mode !== void 0 && values.mode === void 0) values.mode = normalizeControlValue(data.mode);
|
|
2482
|
+
return Object.keys(values).length > 0 ? values : void 0;
|
|
2483
|
+
}
|
|
2484
|
+
function normalizeProviderEffects(data) {
|
|
2485
|
+
const rawEffects = Array.isArray(data?.effects) ? data.effects : [];
|
|
2486
|
+
const effects = [];
|
|
2487
|
+
for (const raw of rawEffects) {
|
|
2488
|
+
if (!raw || typeof raw !== "object") continue;
|
|
2489
|
+
const type = raw.type;
|
|
2490
|
+
if (type === "message" && raw.message && typeof raw.message === "object") {
|
|
2491
|
+
const content = raw.message.content;
|
|
2492
|
+
if (typeof content !== "string" && !Array.isArray(content)) continue;
|
|
2493
|
+
effects.push({
|
|
2494
|
+
type: "message",
|
|
2495
|
+
id: typeof raw.id === "string" ? raw.id : void 0,
|
|
2496
|
+
when: raw.when === "turn_completed" ? "turn_completed" : "immediate",
|
|
2497
|
+
persist: raw.persist !== false,
|
|
2498
|
+
message: {
|
|
2499
|
+
role: raw.message.role === "assistant" || raw.message.role === "user" ? raw.message.role : "system",
|
|
2500
|
+
content,
|
|
2501
|
+
kind: typeof raw.message.kind === "string" ? raw.message.kind : void 0,
|
|
2502
|
+
senderName: typeof raw.message.senderName === "string" ? raw.message.senderName : void 0
|
|
2556
2503
|
}
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
const now = Date.now();
|
|
2570
|
-
const agentStatus = newStatus === "streaming" || newStatus === "generating" ? "generating" : newStatus === "waiting_approval" ? "waiting_approval" : "idle";
|
|
2571
|
-
const lastMsg = Array.isArray(data?.messages) && data.messages.length > 0 ? data.messages[data.messages.length - 1] : null;
|
|
2572
|
-
const progressFingerprint = agentStatus === "generating" ? `${lastMsg?.role || ""}:${typeof lastMsg?.content === "string" ? lastMsg.content : JSON.stringify(lastMsg?.content || "")}`.slice(-2e3) : void 0;
|
|
2573
|
-
if (agentStatus !== this.lastAgentStatus) {
|
|
2574
|
-
if (this.lastAgentStatus === "idle" && agentStatus === "generating") {
|
|
2575
|
-
this.generatingStartedAt = now;
|
|
2576
|
-
this.pushEvent({
|
|
2577
|
-
event: "agent:generating_started",
|
|
2578
|
-
chatTitle: this.resolveChatTitle(data),
|
|
2579
|
-
timestamp: now,
|
|
2580
|
-
ideType: this.ideType || this.type,
|
|
2581
|
-
agentType: this.type,
|
|
2582
|
-
agentName: this.agentName || this.provider.name,
|
|
2583
|
-
extensionId: this.extensionId || this.type
|
|
2584
|
-
});
|
|
2585
|
-
} else if (agentStatus === "waiting_approval") {
|
|
2586
|
-
if (!this.generatingStartedAt) this.generatingStartedAt = now;
|
|
2587
|
-
this.pushEvent({
|
|
2588
|
-
event: "agent:waiting_approval",
|
|
2589
|
-
chatTitle: this.resolveChatTitle(data),
|
|
2590
|
-
timestamp: now,
|
|
2591
|
-
ideType: this.ideType || this.type,
|
|
2592
|
-
agentType: this.type,
|
|
2593
|
-
agentName: this.agentName || this.provider.name,
|
|
2594
|
-
extensionId: this.extensionId || this.type,
|
|
2595
|
-
modalMessage: data?.activeModal?.message,
|
|
2596
|
-
modalButtons: data?.activeModal?.buttons
|
|
2597
|
-
});
|
|
2598
|
-
} else if (agentStatus === "idle" && (this.lastAgentStatus === "generating" || this.lastAgentStatus === "waiting_approval")) {
|
|
2599
|
-
const duration3 = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
|
|
2600
|
-
this.pushEvent({
|
|
2601
|
-
event: "agent:generating_completed",
|
|
2602
|
-
chatTitle: this.resolveChatTitle(data),
|
|
2603
|
-
duration: duration3,
|
|
2604
|
-
timestamp: now,
|
|
2605
|
-
ideType: this.ideType || this.type,
|
|
2606
|
-
agentType: this.type,
|
|
2607
|
-
agentName: this.agentName || this.provider.name,
|
|
2608
|
-
extensionId: this.extensionId || this.type
|
|
2609
|
-
});
|
|
2610
|
-
this.generatingStartedAt = 0;
|
|
2611
|
-
}
|
|
2612
|
-
this.lastAgentStatus = agentStatus;
|
|
2613
|
-
}
|
|
2614
|
-
const agentKey = `${this.type}:ext`;
|
|
2615
|
-
const monitorEvents = this.monitor.check(agentKey, agentStatus, now, progressFingerprint);
|
|
2616
|
-
for (const me of monitorEvents) {
|
|
2617
|
-
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
2504
|
+
});
|
|
2505
|
+
continue;
|
|
2506
|
+
}
|
|
2507
|
+
if (type === "toast" && raw.toast && typeof raw.toast.message === "string") {
|
|
2508
|
+
effects.push({
|
|
2509
|
+
type: "toast",
|
|
2510
|
+
id: typeof raw.id === "string" ? raw.id : void 0,
|
|
2511
|
+
when: raw.when === "turn_completed" ? "turn_completed" : "immediate",
|
|
2512
|
+
persist: raw.persist !== false,
|
|
2513
|
+
toast: {
|
|
2514
|
+
level: raw.toast.level === "success" || raw.toast.level === "warning" ? raw.toast.level : "info",
|
|
2515
|
+
message: raw.toast.message
|
|
2618
2516
|
}
|
|
2619
|
-
}
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
this.detectTransition("idle", {
|
|
2636
|
-
title: this.chatTitle,
|
|
2637
|
-
agentName: this.agentName,
|
|
2638
|
-
extensionId: this.extensionId,
|
|
2639
|
-
messages: this.messages
|
|
2640
|
-
});
|
|
2517
|
+
});
|
|
2518
|
+
continue;
|
|
2519
|
+
}
|
|
2520
|
+
if (type === "notification" && raw.notification && typeof raw.notification.body === "string") {
|
|
2521
|
+
effects.push({
|
|
2522
|
+
type: "notification",
|
|
2523
|
+
id: typeof raw.id === "string" ? raw.id : void 0,
|
|
2524
|
+
when: raw.when === "turn_completed" ? "turn_completed" : "immediate",
|
|
2525
|
+
persist: raw.persist !== false,
|
|
2526
|
+
notification: {
|
|
2527
|
+
title: typeof raw.notification.title === "string" ? raw.notification.title : void 0,
|
|
2528
|
+
body: raw.notification.body,
|
|
2529
|
+
level: raw.notification.level === "success" || raw.notification.level === "warning" ? raw.notification.level : "info",
|
|
2530
|
+
channels: Array.isArray(raw.notification.channels) ? raw.notification.channels.filter((channel) => channel === "bubble" || channel === "toast" || channel === "browser") : void 0,
|
|
2531
|
+
preferenceKey: raw.notification.preferenceKey === "disconnect" || raw.notification.preferenceKey === "completion" || raw.notification.preferenceKey === "approval" || raw.notification.preferenceKey === "browser" ? raw.notification.preferenceKey : void 0,
|
|
2532
|
+
bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0
|
|
2641
2533
|
}
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
return effects;
|
|
2538
|
+
}
|
|
2539
|
+
function normalizeControlValue(value) {
|
|
2540
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
2541
|
+
return value;
|
|
2542
|
+
}
|
|
2543
|
+
if (value && typeof value === "object") {
|
|
2544
|
+
if (typeof value.label === "string") return value.label;
|
|
2545
|
+
if (typeof value.name === "string") return value.name;
|
|
2546
|
+
if (typeof value.id === "string") return value.id;
|
|
2547
|
+
}
|
|
2548
|
+
return String(value);
|
|
2549
|
+
}
|
|
2550
|
+
var init_control_effects = __esm({
|
|
2551
|
+
"../../oss/packages/daemon-core/src/providers/control-effects.ts"() {
|
|
2552
|
+
"use strict";
|
|
2658
2553
|
}
|
|
2659
2554
|
});
|
|
2660
2555
|
|
|
@@ -2938,6 +2833,344 @@ var init_chat_history = __esm({
|
|
|
2938
2833
|
}
|
|
2939
2834
|
});
|
|
2940
2835
|
|
|
2836
|
+
// ../../oss/packages/daemon-core/src/providers/extension-provider-instance.ts
|
|
2837
|
+
var ExtensionProviderInstance;
|
|
2838
|
+
var init_extension_provider_instance = __esm({
|
|
2839
|
+
"../../oss/packages/daemon-core/src/providers/extension-provider-instance.ts"() {
|
|
2840
|
+
"use strict";
|
|
2841
|
+
init_status_monitor();
|
|
2842
|
+
init_control_effects();
|
|
2843
|
+
init_chat_history();
|
|
2844
|
+
ExtensionProviderInstance = class {
|
|
2845
|
+
type;
|
|
2846
|
+
category = "extension";
|
|
2847
|
+
provider;
|
|
2848
|
+
context = null;
|
|
2849
|
+
settings = {};
|
|
2850
|
+
events = [];
|
|
2851
|
+
// status
|
|
2852
|
+
currentStatus = "idle";
|
|
2853
|
+
agentStreams = [];
|
|
2854
|
+
messages = [];
|
|
2855
|
+
activeModal = null;
|
|
2856
|
+
currentModel = "";
|
|
2857
|
+
currentMode = "";
|
|
2858
|
+
controlValues = {};
|
|
2859
|
+
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
2860
|
+
runtimeMessages = [];
|
|
2861
|
+
lastAgentStatus = "idle";
|
|
2862
|
+
generatingStartedAt = 0;
|
|
2863
|
+
monitor;
|
|
2864
|
+
historyWriter;
|
|
2865
|
+
// meta
|
|
2866
|
+
instanceId;
|
|
2867
|
+
ideType = "";
|
|
2868
|
+
chatId = null;
|
|
2869
|
+
chatTitle = null;
|
|
2870
|
+
agentName = "";
|
|
2871
|
+
extensionId = "";
|
|
2872
|
+
constructor(provider) {
|
|
2873
|
+
this.type = provider.type;
|
|
2874
|
+
this.provider = provider;
|
|
2875
|
+
this.instanceId = crypto.randomUUID();
|
|
2876
|
+
this.monitor = new StatusMonitor();
|
|
2877
|
+
this.historyWriter = new ChatHistoryWriter();
|
|
2878
|
+
}
|
|
2879
|
+
// ─── Lifecycle ──────────────────────────────────
|
|
2880
|
+
async init(context) {
|
|
2881
|
+
this.context = context;
|
|
2882
|
+
this.settings = context.settings || {};
|
|
2883
|
+
this.monitor.updateConfig({
|
|
2884
|
+
approvalAlert: this.settings.approvalAlert !== false,
|
|
2885
|
+
longGeneratingAlert: this.settings.longGeneratingAlert !== false,
|
|
2886
|
+
longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
async onTick() {
|
|
2890
|
+
if (!this.context?.cdp?.isConnected) return;
|
|
2891
|
+
}
|
|
2892
|
+
getState() {
|
|
2893
|
+
return {
|
|
2894
|
+
type: this.type,
|
|
2895
|
+
name: this.provider.name,
|
|
2896
|
+
category: "extension",
|
|
2897
|
+
status: this.currentStatus,
|
|
2898
|
+
activeChat: this.messages.length > 0 || this.runtimeMessages.length > 0 ? {
|
|
2899
|
+
id: this.chatId || this.instanceId,
|
|
2900
|
+
title: this.chatTitle || this.agentName || this.provider.name,
|
|
2901
|
+
status: this.currentStatus,
|
|
2902
|
+
messages: this.mergeConversationMessages(this.messages),
|
|
2903
|
+
activeModal: this.activeModal,
|
|
2904
|
+
inputContent: ""
|
|
2905
|
+
} : null,
|
|
2906
|
+
currentModel: this.currentModel || void 0,
|
|
2907
|
+
currentPlan: this.currentMode || void 0,
|
|
2908
|
+
controlValues: this.controlValues,
|
|
2909
|
+
providerControls: this.provider.controls,
|
|
2910
|
+
agentStreams: this.agentStreams,
|
|
2911
|
+
instanceId: this.instanceId,
|
|
2912
|
+
lastUpdated: Date.now(),
|
|
2913
|
+
settings: this.settings,
|
|
2914
|
+
pendingEvents: this.flushEvents()
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
onEvent(event, data) {
|
|
2918
|
+
if (event === "stream_update") {
|
|
2919
|
+
if (data?.streams) this.agentStreams = data.streams;
|
|
2920
|
+
if (data?.messages) this.messages = data.messages;
|
|
2921
|
+
if (data?.activeModal !== void 0) this.activeModal = data.activeModal;
|
|
2922
|
+
if (data?.model) this.currentModel = data.model;
|
|
2923
|
+
if (data?.mode) this.currentMode = data.mode;
|
|
2924
|
+
const controlValues = extractProviderControlValues(this.provider.controls, data) || data?.controlValues;
|
|
2925
|
+
if (controlValues) this.controlValues = controlValues;
|
|
2926
|
+
if (typeof data?.sessionId === "string" && data.sessionId.trim()) this.chatId = data.sessionId;
|
|
2927
|
+
if (typeof data?.title === "string" && data.title.trim()) this.chatTitle = data.title;
|
|
2928
|
+
if (typeof data?.agentName === "string" && data.agentName.trim()) this.agentName = data.agentName;
|
|
2929
|
+
if (typeof data?.extensionId === "string" && data.extensionId.trim()) this.extensionId = data.extensionId;
|
|
2930
|
+
if (data?.status) {
|
|
2931
|
+
const newStatus = data.status;
|
|
2932
|
+
this.detectTransition(newStatus, data);
|
|
2933
|
+
this.currentStatus = newStatus;
|
|
2934
|
+
}
|
|
2935
|
+
} else if (event === "stream_reset") {
|
|
2936
|
+
this.resetStreamState();
|
|
2937
|
+
} else if (event === "extension_connected") {
|
|
2938
|
+
this.ideType = data?.ideType || "";
|
|
2939
|
+
} else if (event === "provider_state_patch" && data && typeof data === "object") {
|
|
2940
|
+
this.applyProviderResponse(data, { phase: "immediate" });
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
dispose() {
|
|
2944
|
+
this.agentStreams = [];
|
|
2945
|
+
this.messages = [];
|
|
2946
|
+
this.monitor.reset();
|
|
2947
|
+
this.appliedEffectKeys.clear();
|
|
2948
|
+
this.runtimeMessages = [];
|
|
2949
|
+
}
|
|
2950
|
+
updateSettings(newSettings) {
|
|
2951
|
+
this.settings = { ...newSettings };
|
|
2952
|
+
this.monitor.updateConfig({
|
|
2953
|
+
approvalAlert: this.settings.approvalAlert !== false,
|
|
2954
|
+
longGeneratingAlert: this.settings.longGeneratingAlert !== false,
|
|
2955
|
+
longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2958
|
+
/** Query UUID instanceId */
|
|
2959
|
+
getInstanceId() {
|
|
2960
|
+
return this.instanceId;
|
|
2961
|
+
}
|
|
2962
|
+
// ─── status transition detect ──────────────────────────────
|
|
2963
|
+
detectTransition(newStatus, data) {
|
|
2964
|
+
const now = Date.now();
|
|
2965
|
+
const agentStatus = newStatus === "streaming" || newStatus === "generating" ? "generating" : newStatus === "waiting_approval" ? "waiting_approval" : "idle";
|
|
2966
|
+
const lastMsg = Array.isArray(data?.messages) && data.messages.length > 0 ? data.messages[data.messages.length - 1] : null;
|
|
2967
|
+
const progressFingerprint = agentStatus === "generating" ? `${lastMsg?.role || ""}:${typeof lastMsg?.content === "string" ? lastMsg.content : JSON.stringify(lastMsg?.content || "")}`.slice(-2e3) : void 0;
|
|
2968
|
+
const previousStatus = this.lastAgentStatus;
|
|
2969
|
+
if (agentStatus !== this.lastAgentStatus) {
|
|
2970
|
+
if (this.lastAgentStatus === "idle" && agentStatus === "generating") {
|
|
2971
|
+
this.generatingStartedAt = now;
|
|
2972
|
+
this.pushEvent({
|
|
2973
|
+
event: "agent:generating_started",
|
|
2974
|
+
chatTitle: this.resolveChatTitle(data),
|
|
2975
|
+
timestamp: now,
|
|
2976
|
+
ideType: this.ideType || this.type,
|
|
2977
|
+
agentType: this.type,
|
|
2978
|
+
agentName: this.agentName || this.provider.name,
|
|
2979
|
+
extensionId: this.extensionId || this.type
|
|
2980
|
+
});
|
|
2981
|
+
} else if (agentStatus === "waiting_approval") {
|
|
2982
|
+
if (!this.generatingStartedAt) this.generatingStartedAt = now;
|
|
2983
|
+
this.pushEvent({
|
|
2984
|
+
event: "agent:waiting_approval",
|
|
2985
|
+
chatTitle: this.resolveChatTitle(data),
|
|
2986
|
+
timestamp: now,
|
|
2987
|
+
ideType: this.ideType || this.type,
|
|
2988
|
+
agentType: this.type,
|
|
2989
|
+
agentName: this.agentName || this.provider.name,
|
|
2990
|
+
extensionId: this.extensionId || this.type,
|
|
2991
|
+
modalMessage: data?.activeModal?.message,
|
|
2992
|
+
modalButtons: data?.activeModal?.buttons
|
|
2993
|
+
});
|
|
2994
|
+
} else if (agentStatus === "idle" && (this.lastAgentStatus === "generating" || this.lastAgentStatus === "waiting_approval")) {
|
|
2995
|
+
const duration3 = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
|
|
2996
|
+
this.pushEvent({
|
|
2997
|
+
event: "agent:generating_completed",
|
|
2998
|
+
chatTitle: this.resolveChatTitle(data),
|
|
2999
|
+
duration: duration3,
|
|
3000
|
+
timestamp: now,
|
|
3001
|
+
ideType: this.ideType || this.type,
|
|
3002
|
+
agentType: this.type,
|
|
3003
|
+
agentName: this.agentName || this.provider.name,
|
|
3004
|
+
extensionId: this.extensionId || this.type
|
|
3005
|
+
});
|
|
3006
|
+
this.generatingStartedAt = 0;
|
|
3007
|
+
}
|
|
3008
|
+
this.lastAgentStatus = agentStatus;
|
|
3009
|
+
}
|
|
3010
|
+
this.applyProviderResponse(data, {
|
|
3011
|
+
phase: agentStatus === "idle" && (previousStatus === "generating" || previousStatus === "waiting_approval") ? "turn_completed" : "immediate"
|
|
3012
|
+
});
|
|
3013
|
+
const agentKey = `${this.type}:ext`;
|
|
3014
|
+
const monitorEvents = this.monitor.check(agentKey, agentStatus, now, progressFingerprint);
|
|
3015
|
+
for (const me of monitorEvents) {
|
|
3016
|
+
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
pushEvent(event) {
|
|
3020
|
+
this.events.push(event);
|
|
3021
|
+
if (this.events.length > 50) this.events = this.events.slice(-50);
|
|
3022
|
+
}
|
|
3023
|
+
applyProviderResponse(data, options) {
|
|
3024
|
+
if (!data || typeof data !== "object") return;
|
|
3025
|
+
const controlValues = extractProviderControlValues(this.provider.controls, data);
|
|
3026
|
+
if (controlValues) this.controlValues = { ...this.controlValues, ...controlValues };
|
|
3027
|
+
const effects = normalizeProviderEffects(data);
|
|
3028
|
+
for (const effect of effects) {
|
|
3029
|
+
const effectWhen = effect.when || "immediate";
|
|
3030
|
+
if (effectWhen === "turn_completed" && options.phase !== "turn_completed") continue;
|
|
3031
|
+
if (effectWhen === "immediate" && options.phase === "turn_completed") continue;
|
|
3032
|
+
const effectKey = this.getEffectDedupKey(effect);
|
|
3033
|
+
if (this.appliedEffectKeys.has(effectKey)) continue;
|
|
3034
|
+
this.appliedEffectKeys.add(effectKey);
|
|
3035
|
+
if (effect.persist !== false) {
|
|
3036
|
+
const persisted = this.getPersistedEffectContent(effect);
|
|
3037
|
+
if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
|
|
3038
|
+
}
|
|
3039
|
+
if (effect.type === "message" && effect.message) {
|
|
3040
|
+
this.pushEvent({
|
|
3041
|
+
event: "provider:message",
|
|
3042
|
+
timestamp: Date.now(),
|
|
3043
|
+
content: typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content),
|
|
3044
|
+
role: effect.message.role || "system",
|
|
3045
|
+
kind: effect.message.kind,
|
|
3046
|
+
senderName: effect.message.senderName
|
|
3047
|
+
});
|
|
3048
|
+
} else if (effect.type === "toast" && effect.toast) {
|
|
3049
|
+
this.pushEvent({
|
|
3050
|
+
event: "provider:toast",
|
|
3051
|
+
effectId: effect.id || effectKey,
|
|
3052
|
+
timestamp: Date.now(),
|
|
3053
|
+
message: effect.toast.message,
|
|
3054
|
+
level: effect.toast.level || "info"
|
|
3055
|
+
});
|
|
3056
|
+
} else if (effect.type === "notification" && effect.notification) {
|
|
3057
|
+
this.pushEvent({
|
|
3058
|
+
event: "provider:notification",
|
|
3059
|
+
effectId: effect.id || effectKey,
|
|
3060
|
+
timestamp: Date.now(),
|
|
3061
|
+
title: effect.notification.title,
|
|
3062
|
+
message: effect.notification.body,
|
|
3063
|
+
content: typeof effect.notification.bubbleContent === "string" ? effect.notification.bubbleContent : effect.notification.body,
|
|
3064
|
+
level: effect.notification.level || "info",
|
|
3065
|
+
channels: effect.notification.channels || ["toast"],
|
|
3066
|
+
preferenceKey: effect.notification.preferenceKey
|
|
3067
|
+
});
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
|
|
3072
|
+
const normalizedContent = String(content || "").trim();
|
|
3073
|
+
if (!normalizedContent) return;
|
|
3074
|
+
if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
|
|
3075
|
+
this.runtimeMessages.push({
|
|
3076
|
+
key: dedupKey,
|
|
3077
|
+
message: {
|
|
3078
|
+
role: "system",
|
|
3079
|
+
senderName: "System",
|
|
3080
|
+
content: normalizedContent,
|
|
3081
|
+
receivedAt,
|
|
3082
|
+
timestamp: receivedAt
|
|
3083
|
+
}
|
|
3084
|
+
});
|
|
3085
|
+
if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
|
|
3086
|
+
this.historyWriter.appendNewMessages(
|
|
3087
|
+
this.type,
|
|
3088
|
+
[{
|
|
3089
|
+
role: "system",
|
|
3090
|
+
senderName: "System",
|
|
3091
|
+
content: normalizedContent,
|
|
3092
|
+
kind: "system",
|
|
3093
|
+
receivedAt,
|
|
3094
|
+
historyDedupKey: dedupKey
|
|
3095
|
+
}],
|
|
3096
|
+
this.chatTitle || this.agentName || this.provider.name,
|
|
3097
|
+
this.instanceId,
|
|
3098
|
+
this.chatId || this.instanceId
|
|
3099
|
+
);
|
|
3100
|
+
}
|
|
3101
|
+
mergeConversationMessages(messages) {
|
|
3102
|
+
if (this.runtimeMessages.length === 0) return messages;
|
|
3103
|
+
return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
|
|
3104
|
+
const aTime = a.message.receivedAt || a.message.timestamp || 0;
|
|
3105
|
+
const bTime = b.message.receivedAt || b.message.timestamp || 0;
|
|
3106
|
+
if (aTime !== bTime) return aTime - bTime;
|
|
3107
|
+
return a.index - b.index;
|
|
3108
|
+
}).map((entry) => entry.message);
|
|
3109
|
+
}
|
|
3110
|
+
getPersistedEffectContent(effect) {
|
|
3111
|
+
if (effect.type === "message") {
|
|
3112
|
+
return typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
3113
|
+
}
|
|
3114
|
+
if (effect.type === "toast") {
|
|
3115
|
+
return effect.toast?.message || null;
|
|
3116
|
+
}
|
|
3117
|
+
if (effect.type === "notification") {
|
|
3118
|
+
if (typeof effect.notification?.bubbleContent === "string") return effect.notification.bubbleContent;
|
|
3119
|
+
if (typeof effect.notification?.title === "string" && effect.notification.title.trim()) {
|
|
3120
|
+
return `${effect.notification.title}
|
|
3121
|
+
${effect.notification.body || ""}`.trim();
|
|
3122
|
+
}
|
|
3123
|
+
return effect.notification?.body || null;
|
|
3124
|
+
}
|
|
3125
|
+
return null;
|
|
3126
|
+
}
|
|
3127
|
+
getEffectDedupKey(effect) {
|
|
3128
|
+
if (effect.id) return `provider_effect:${effect.id}`;
|
|
3129
|
+
if (effect.type === "message") {
|
|
3130
|
+
return `provider_effect:message:${typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "")}`;
|
|
3131
|
+
}
|
|
3132
|
+
if (effect.type === "notification") {
|
|
3133
|
+
return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
|
|
3134
|
+
}
|
|
3135
|
+
return `provider_effect:toast:${effect.toast?.message || ""}`;
|
|
3136
|
+
}
|
|
3137
|
+
flushEvents() {
|
|
3138
|
+
const events = [...this.events];
|
|
3139
|
+
this.events = [];
|
|
3140
|
+
return events;
|
|
3141
|
+
}
|
|
3142
|
+
resolveChatTitle(data) {
|
|
3143
|
+
const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
|
|
3144
|
+
return title || this.agentName || this.provider.name;
|
|
3145
|
+
}
|
|
3146
|
+
resetStreamState() {
|
|
3147
|
+
if (this.currentStatus !== "idle") {
|
|
3148
|
+
this.detectTransition("idle", {
|
|
3149
|
+
title: this.chatTitle,
|
|
3150
|
+
agentName: this.agentName,
|
|
3151
|
+
extensionId: this.extensionId,
|
|
3152
|
+
messages: this.messages
|
|
3153
|
+
});
|
|
3154
|
+
}
|
|
3155
|
+
this.agentStreams = [];
|
|
3156
|
+
this.messages = [];
|
|
3157
|
+
this.activeModal = null;
|
|
3158
|
+
this.currentModel = "";
|
|
3159
|
+
this.currentMode = "";
|
|
3160
|
+
this.controlValues = {};
|
|
3161
|
+
this.currentStatus = "idle";
|
|
3162
|
+
this.chatId = null;
|
|
3163
|
+
this.chatTitle = null;
|
|
3164
|
+
this.agentName = "";
|
|
3165
|
+
this.extensionId = "";
|
|
3166
|
+
this.lastAgentStatus = "idle";
|
|
3167
|
+
this.generatingStartedAt = 0;
|
|
3168
|
+
this.monitor.reset();
|
|
3169
|
+
}
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
});
|
|
3173
|
+
|
|
2941
3174
|
// ../../oss/packages/daemon-core/src/providers/ide-provider-instance.ts
|
|
2942
3175
|
var crypto2, IdeProviderInstance;
|
|
2943
3176
|
var init_ide_provider_instance = __esm({
|
|
@@ -2948,6 +3181,7 @@ var init_ide_provider_instance = __esm({
|
|
|
2948
3181
|
init_status_monitor();
|
|
2949
3182
|
init_chat_history();
|
|
2950
3183
|
init_logger();
|
|
3184
|
+
init_control_effects();
|
|
2951
3185
|
IdeProviderInstance = class {
|
|
2952
3186
|
type;
|
|
2953
3187
|
category = "ide";
|
|
@@ -2965,6 +3199,8 @@ var init_ide_provider_instance = __esm({
|
|
|
2965
3199
|
monitor;
|
|
2966
3200
|
historyWriter;
|
|
2967
3201
|
autoApproveBusy = false;
|
|
3202
|
+
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
3203
|
+
runtimeMessages = [];
|
|
2968
3204
|
// IDE meta
|
|
2969
3205
|
ideVersion = "";
|
|
2970
3206
|
instanceId;
|
|
@@ -3025,7 +3261,7 @@ var init_ide_provider_instance = __esm({
|
|
|
3025
3261
|
id: this.cachedChat.id || "active_session",
|
|
3026
3262
|
title: this.cachedChat.title || this.type,
|
|
3027
3263
|
status: this.cachedChat.status || this.currentStatus,
|
|
3028
|
-
messages: this.cachedChat.messages || [],
|
|
3264
|
+
messages: this.mergeConversationMessages(this.cachedChat.messages || []),
|
|
3029
3265
|
activeModal: this.cachedChat.activeModal || null,
|
|
3030
3266
|
inputContent: this.cachedChat.inputContent || ""
|
|
3031
3267
|
} : null,
|
|
@@ -3065,6 +3301,13 @@ var init_ide_provider_instance = __esm({
|
|
|
3065
3301
|
for (const ext of this.extensions.values()) {
|
|
3066
3302
|
ext.onEvent("stream_reset");
|
|
3067
3303
|
}
|
|
3304
|
+
} else if (event === "provider_state_patch" && data && typeof data === "object") {
|
|
3305
|
+
const extType = typeof data.extensionType === "string" ? data.extensionType : "";
|
|
3306
|
+
if (extType && this.extensions.has(extType)) {
|
|
3307
|
+
this.extensions.get(extType).onEvent("provider_state_patch", data);
|
|
3308
|
+
} else {
|
|
3309
|
+
this.applyProviderResponse(data, { phase: "immediate" });
|
|
3310
|
+
}
|
|
3068
3311
|
}
|
|
3069
3312
|
}
|
|
3070
3313
|
dispose() {
|
|
@@ -3072,11 +3315,21 @@ var init_ide_provider_instance = __esm({
|
|
|
3072
3315
|
this.lastAgentStatuses.clear();
|
|
3073
3316
|
this.generatingStartedAt.clear();
|
|
3074
3317
|
this.monitor.reset();
|
|
3318
|
+
this.appliedEffectKeys.clear();
|
|
3319
|
+
this.runtimeMessages = [];
|
|
3075
3320
|
for (const ext of this.extensions.values()) {
|
|
3076
3321
|
ext.dispose();
|
|
3077
3322
|
}
|
|
3078
3323
|
this.extensions.clear();
|
|
3079
3324
|
}
|
|
3325
|
+
updateSettings(newSettings) {
|
|
3326
|
+
this.settings = { ...newSettings };
|
|
3327
|
+
this.monitor.updateConfig({
|
|
3328
|
+
approvalAlert: this.settings.approvalAlert !== false,
|
|
3329
|
+
longGeneratingAlert: this.settings.longGeneratingAlert !== false,
|
|
3330
|
+
longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
|
|
3331
|
+
});
|
|
3332
|
+
}
|
|
3080
3333
|
// ─── Extension manage ─────────────────────────────
|
|
3081
3334
|
/** Extension Instance add */
|
|
3082
3335
|
async addExtension(provider, settings) {
|
|
@@ -3189,6 +3442,8 @@ var init_ide_provider_instance = __esm({
|
|
|
3189
3442
|
raw.messages = raw.messages.filter((m) => !hiddenKinds.has(m.kind));
|
|
3190
3443
|
}
|
|
3191
3444
|
}
|
|
3445
|
+
const controlValues = extractProviderControlValues(this.provider.controls, raw);
|
|
3446
|
+
if (controlValues) raw.controlValues = controlValues;
|
|
3192
3447
|
this.cachedChat = { ...raw, activeModal };
|
|
3193
3448
|
this.detectAgentTransitions(raw, now);
|
|
3194
3449
|
if (raw.messages?.length > 0) {
|
|
@@ -3255,6 +3510,9 @@ var init_ide_provider_instance = __esm({
|
|
|
3255
3510
|
}
|
|
3256
3511
|
this.lastAgentStatuses.set(agentKey, agentStatus);
|
|
3257
3512
|
}
|
|
3513
|
+
this.applyProviderResponse(chatData, {
|
|
3514
|
+
phase: agentStatus === "idle" && (lastStatus === "generating" || lastStatus === "waiting_approval") ? "turn_completed" : "immediate"
|
|
3515
|
+
});
|
|
3258
3516
|
if (agentStatus === "waiting_approval" && this.settings.autoApprove && !this.autoApproveBusy) {
|
|
3259
3517
|
this.autoApproveViaScript(chatData);
|
|
3260
3518
|
}
|
|
@@ -3267,6 +3525,136 @@ var init_ide_provider_instance = __esm({
|
|
|
3267
3525
|
this.events.push(event);
|
|
3268
3526
|
if (this.events.length > 50) this.events = this.events.slice(-50);
|
|
3269
3527
|
}
|
|
3528
|
+
applyProviderResponse(data, options) {
|
|
3529
|
+
if (!data || typeof data !== "object") return;
|
|
3530
|
+
const controlValues = extractProviderControlValues(this.provider.controls, data);
|
|
3531
|
+
if (controlValues) {
|
|
3532
|
+
this.cachedChat = {
|
|
3533
|
+
...this.cachedChat || {},
|
|
3534
|
+
...data,
|
|
3535
|
+
controlValues: { ...this.cachedChat?.controlValues || {}, ...controlValues }
|
|
3536
|
+
};
|
|
3537
|
+
}
|
|
3538
|
+
const effects = normalizeProviderEffects(data);
|
|
3539
|
+
for (const effect of effects) {
|
|
3540
|
+
const effectWhen = effect.when || "immediate";
|
|
3541
|
+
if (effectWhen === "turn_completed" && options.phase !== "turn_completed") continue;
|
|
3542
|
+
if (effectWhen === "immediate" && options.phase === "turn_completed") continue;
|
|
3543
|
+
const effectKey = this.getEffectDedupKey(effect);
|
|
3544
|
+
if (this.appliedEffectKeys.has(effectKey)) continue;
|
|
3545
|
+
this.appliedEffectKeys.add(effectKey);
|
|
3546
|
+
if (effect.persist !== false) {
|
|
3547
|
+
const persisted = this.getPersistedEffectContent(effect);
|
|
3548
|
+
if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
|
|
3549
|
+
}
|
|
3550
|
+
if (effect.type === "message" && effect.message) {
|
|
3551
|
+
this.pushEvent({
|
|
3552
|
+
event: "provider:message",
|
|
3553
|
+
timestamp: Date.now(),
|
|
3554
|
+
content: typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content),
|
|
3555
|
+
role: effect.message.role || "system",
|
|
3556
|
+
kind: effect.message.kind,
|
|
3557
|
+
senderName: effect.message.senderName
|
|
3558
|
+
});
|
|
3559
|
+
} else if (effect.type === "toast" && effect.toast) {
|
|
3560
|
+
this.pushEvent({
|
|
3561
|
+
event: "provider:toast",
|
|
3562
|
+
effectId: effect.id || effectKey,
|
|
3563
|
+
timestamp: Date.now(),
|
|
3564
|
+
message: effect.toast.message,
|
|
3565
|
+
level: effect.toast.level || "info"
|
|
3566
|
+
});
|
|
3567
|
+
} else if (effect.type === "notification" && effect.notification) {
|
|
3568
|
+
this.pushEvent({
|
|
3569
|
+
event: "provider:notification",
|
|
3570
|
+
effectId: effect.id || effectKey,
|
|
3571
|
+
timestamp: Date.now(),
|
|
3572
|
+
title: effect.notification.title,
|
|
3573
|
+
message: effect.notification.body,
|
|
3574
|
+
content: typeof effect.notification.bubbleContent === "string" ? effect.notification.bubbleContent : effect.notification.body,
|
|
3575
|
+
level: effect.notification.level || "info",
|
|
3576
|
+
channels: effect.notification.channels || ["toast"],
|
|
3577
|
+
preferenceKey: effect.notification.preferenceKey
|
|
3578
|
+
});
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
|
|
3583
|
+
const normalizedContent = String(content || "").trim();
|
|
3584
|
+
if (!normalizedContent) return;
|
|
3585
|
+
if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
|
|
3586
|
+
if (!this.cachedChat) {
|
|
3587
|
+
this.cachedChat = {
|
|
3588
|
+
id: "active_session",
|
|
3589
|
+
title: this.provider.name,
|
|
3590
|
+
status: this.currentStatus,
|
|
3591
|
+
messages: [],
|
|
3592
|
+
activeModal: null,
|
|
3593
|
+
inputContent: ""
|
|
3594
|
+
};
|
|
3595
|
+
}
|
|
3596
|
+
this.runtimeMessages.push({
|
|
3597
|
+
key: dedupKey,
|
|
3598
|
+
message: {
|
|
3599
|
+
role: "system",
|
|
3600
|
+
senderName: "System",
|
|
3601
|
+
content: normalizedContent,
|
|
3602
|
+
receivedAt,
|
|
3603
|
+
timestamp: receivedAt
|
|
3604
|
+
}
|
|
3605
|
+
});
|
|
3606
|
+
if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
|
|
3607
|
+
this.historyWriter.appendNewMessages(
|
|
3608
|
+
this.type,
|
|
3609
|
+
[{
|
|
3610
|
+
role: "system",
|
|
3611
|
+
senderName: "System",
|
|
3612
|
+
content: normalizedContent,
|
|
3613
|
+
kind: "system",
|
|
3614
|
+
receivedAt,
|
|
3615
|
+
historyDedupKey: dedupKey
|
|
3616
|
+
}],
|
|
3617
|
+
this.cachedChat?.title || this.provider.name,
|
|
3618
|
+
this.instanceId,
|
|
3619
|
+
this.cachedChat?.id || this.instanceId
|
|
3620
|
+
);
|
|
3621
|
+
}
|
|
3622
|
+
mergeConversationMessages(messages) {
|
|
3623
|
+
if (this.runtimeMessages.length === 0) return messages;
|
|
3624
|
+
return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
|
|
3625
|
+
const aTime = a.message.receivedAt || a.message.timestamp || 0;
|
|
3626
|
+
const bTime = b.message.receivedAt || b.message.timestamp || 0;
|
|
3627
|
+
if (aTime !== bTime) return aTime - bTime;
|
|
3628
|
+
return a.index - b.index;
|
|
3629
|
+
}).map((entry) => entry.message);
|
|
3630
|
+
}
|
|
3631
|
+
getPersistedEffectContent(effect) {
|
|
3632
|
+
if (effect.type === "message") {
|
|
3633
|
+
return typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
3634
|
+
}
|
|
3635
|
+
if (effect.type === "toast") {
|
|
3636
|
+
return effect.toast?.message || null;
|
|
3637
|
+
}
|
|
3638
|
+
if (effect.type === "notification") {
|
|
3639
|
+
if (typeof effect.notification?.bubbleContent === "string") return effect.notification.bubbleContent;
|
|
3640
|
+
if (typeof effect.notification?.title === "string" && effect.notification.title.trim()) {
|
|
3641
|
+
return `${effect.notification.title}
|
|
3642
|
+
${effect.notification.body || ""}`.trim();
|
|
3643
|
+
}
|
|
3644
|
+
return effect.notification?.body || null;
|
|
3645
|
+
}
|
|
3646
|
+
return null;
|
|
3647
|
+
}
|
|
3648
|
+
getEffectDedupKey(effect) {
|
|
3649
|
+
if (effect.id) return `provider_effect:${effect.id}`;
|
|
3650
|
+
if (effect.type === "message") {
|
|
3651
|
+
return `provider_effect:message:${typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "")}`;
|
|
3652
|
+
}
|
|
3653
|
+
if (effect.type === "notification") {
|
|
3654
|
+
return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
|
|
3655
|
+
}
|
|
3656
|
+
return `provider_effect:toast:${effect.toast?.message || ""}`;
|
|
3657
|
+
}
|
|
3270
3658
|
flushEvents() {
|
|
3271
3659
|
const events = [...this.events];
|
|
3272
3660
|
this.events = [];
|
|
@@ -4184,6 +4572,24 @@ function isRecentDuplicateSend(key) {
|
|
|
4184
4572
|
recentSendByTarget.set(key, now);
|
|
4185
4573
|
return false;
|
|
4186
4574
|
}
|
|
4575
|
+
function parseMaybeJson(value) {
|
|
4576
|
+
if (typeof value !== "string") return value;
|
|
4577
|
+
try {
|
|
4578
|
+
return JSON.parse(value);
|
|
4579
|
+
} catch {
|
|
4580
|
+
return value;
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
function didProviderConfirmSend(result) {
|
|
4584
|
+
const parsed = parseMaybeJson(result);
|
|
4585
|
+
if (parsed === true) return true;
|
|
4586
|
+
if (typeof parsed === "string") {
|
|
4587
|
+
const normalized = parsed.trim().toLowerCase();
|
|
4588
|
+
return normalized === "ok" || normalized === "sent" || normalized === "success" || normalized === "true";
|
|
4589
|
+
}
|
|
4590
|
+
if (!parsed || typeof parsed !== "object") return false;
|
|
4591
|
+
return parsed.sent === true || parsed.success === true || parsed.ok === true || parsed.submitted === true || parsed.dispatched === true;
|
|
4592
|
+
}
|
|
4187
4593
|
async function handleChatHistory(h, args) {
|
|
4188
4594
|
const { agentType, offset, limit } = args;
|
|
4189
4595
|
const historySessionId = getHistorySessionId(h, args);
|
|
@@ -4366,14 +4772,8 @@ async function handleSendChat(h, args) {
|
|
|
4366
4772
|
try {
|
|
4367
4773
|
const evalResult = await h.evaluateProviderScript("sendMessage", { MESSAGE: text }, 3e4);
|
|
4368
4774
|
if (evalResult?.result) {
|
|
4369
|
-
|
|
4370
|
-
if (
|
|
4371
|
-
try {
|
|
4372
|
-
parsed = JSON.parse(parsed);
|
|
4373
|
-
} catch {
|
|
4374
|
-
}
|
|
4375
|
-
}
|
|
4376
|
-
if (parsed?.sent) {
|
|
4775
|
+
const parsed = parseMaybeJson(evalResult.result);
|
|
4776
|
+
if (didProviderConfirmSend(parsed)) {
|
|
4377
4777
|
_log(`Extension script sent OK`);
|
|
4378
4778
|
return _logSendSuccess("extension-script");
|
|
4379
4779
|
}
|
|
@@ -4405,14 +4805,8 @@ async function handleSendChat(h, args) {
|
|
|
4405
4805
|
if (sendScript) {
|
|
4406
4806
|
try {
|
|
4407
4807
|
const result = await targetCdp.evaluate(sendScript, 3e4);
|
|
4408
|
-
|
|
4409
|
-
if (
|
|
4410
|
-
try {
|
|
4411
|
-
parsed = JSON.parse(result);
|
|
4412
|
-
} catch {
|
|
4413
|
-
}
|
|
4414
|
-
}
|
|
4415
|
-
if (parsed?.sent) {
|
|
4808
|
+
const parsed = parseMaybeJson(result);
|
|
4809
|
+
if (didProviderConfirmSend(parsed)) {
|
|
4416
4810
|
_log(`sendMessage script OK`);
|
|
4417
4811
|
return _logSendSuccess("script");
|
|
4418
4812
|
}
|
|
@@ -4457,14 +4851,8 @@ async function handleSendChat(h, args) {
|
|
|
4457
4851
|
const matchText = provider.webviewMatchText;
|
|
4458
4852
|
const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
|
|
4459
4853
|
const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
|
|
4460
|
-
|
|
4461
|
-
if (
|
|
4462
|
-
try {
|
|
4463
|
-
wvParsed = JSON.parse(wvResult);
|
|
4464
|
-
} catch {
|
|
4465
|
-
}
|
|
4466
|
-
}
|
|
4467
|
-
if (wvParsed?.sent) {
|
|
4854
|
+
const wvParsed = parseMaybeJson(wvResult);
|
|
4855
|
+
if (didProviderConfirmSend(wvParsed)) {
|
|
4468
4856
|
_log(`webviewSendMessage OK`);
|
|
4469
4857
|
return _logSendSuccess("webview-script");
|
|
4470
4858
|
}
|
|
@@ -4486,14 +4874,8 @@ async function handleSendChat(h, args) {
|
|
|
4486
4874
|
const matchText = provider.webviewMatchText;
|
|
4487
4875
|
const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
|
|
4488
4876
|
const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
|
|
4489
|
-
|
|
4490
|
-
if (
|
|
4491
|
-
try {
|
|
4492
|
-
wvParsed = JSON.parse(wvResult);
|
|
4493
|
-
} catch {
|
|
4494
|
-
}
|
|
4495
|
-
}
|
|
4496
|
-
if (wvParsed?.sent) {
|
|
4877
|
+
const wvParsed = parseMaybeJson(wvResult);
|
|
4878
|
+
if (didProviderConfirmSend(wvParsed)) {
|
|
4497
4879
|
_log(`webviewSendMessage OK`);
|
|
4498
4880
|
return _logSendSuccess("webview-script");
|
|
4499
4881
|
}
|
|
@@ -5394,7 +5776,56 @@ function handleSetProviderSetting(h, args) {
|
|
|
5394
5776
|
}
|
|
5395
5777
|
return { success: false, error: `Failed to set ${providerType}.${key} \u2014 invalid key, value, or not a public setting` };
|
|
5396
5778
|
}
|
|
5397
|
-
|
|
5779
|
+
function normalizeProviderScriptArgs(args) {
|
|
5780
|
+
const normalizedArgs = { ...args || {} };
|
|
5781
|
+
for (const key of ["mode", "model", "message", "action", "button", "text", "sessionId", "value"]) {
|
|
5782
|
+
if (key in normalizedArgs && !(key.toUpperCase() in normalizedArgs)) {
|
|
5783
|
+
normalizedArgs[key.toUpperCase()] = normalizedArgs[key];
|
|
5784
|
+
}
|
|
5785
|
+
}
|
|
5786
|
+
return normalizedArgs;
|
|
5787
|
+
}
|
|
5788
|
+
function parseScriptResult(result) {
|
|
5789
|
+
if (typeof result === "string") {
|
|
5790
|
+
try {
|
|
5791
|
+
const parsed = JSON.parse(result);
|
|
5792
|
+
if (parsed && typeof parsed === "object" && parsed.success === false) {
|
|
5793
|
+
return { success: false, payload: parsed };
|
|
5794
|
+
}
|
|
5795
|
+
return { success: true, payload: parsed };
|
|
5796
|
+
} catch {
|
|
5797
|
+
return { success: true, payload: { result } };
|
|
5798
|
+
}
|
|
5799
|
+
}
|
|
5800
|
+
if (result && typeof result === "object" && result.success === false) {
|
|
5801
|
+
return { success: false, payload: result };
|
|
5802
|
+
}
|
|
5803
|
+
return { success: true, payload: result };
|
|
5804
|
+
}
|
|
5805
|
+
function getCliScriptCommand(payload) {
|
|
5806
|
+
if (!payload || typeof payload !== "object") return null;
|
|
5807
|
+
if (typeof payload.sendMessage === "string" && payload.sendMessage.trim()) {
|
|
5808
|
+
return { type: "send_message", text: payload.sendMessage.trim() };
|
|
5809
|
+
}
|
|
5810
|
+
const command = payload.command;
|
|
5811
|
+
if (!command || typeof command !== "object") return null;
|
|
5812
|
+
if (command.type !== "send_message") return null;
|
|
5813
|
+
const text = typeof command.text === "string" ? command.text.trim() : typeof command.message === "string" ? command.message.trim() : "";
|
|
5814
|
+
if (!text) return null;
|
|
5815
|
+
return { type: "send_message", text };
|
|
5816
|
+
}
|
|
5817
|
+
function applyProviderPatch(h, args, payload) {
|
|
5818
|
+
if (!payload || typeof payload !== "object") return;
|
|
5819
|
+
const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
|
|
5820
|
+
const targetSession = targetSessionId ? h.ctx.sessionRegistry?.get(targetSessionId) : void 0;
|
|
5821
|
+
const instanceKey = targetSession?.instanceKey || targetSessionId;
|
|
5822
|
+
if (!instanceKey) return;
|
|
5823
|
+
h.ctx.instanceManager?.sendEvent(instanceKey, "provider_state_patch", {
|
|
5824
|
+
...payload,
|
|
5825
|
+
extensionType: targetSession?.transport === "cdp-webview" ? targetSession.providerType : void 0
|
|
5826
|
+
});
|
|
5827
|
+
}
|
|
5828
|
+
async function executeProviderScript(h, args, scriptName) {
|
|
5398
5829
|
const { agentType, ideType } = args || {};
|
|
5399
5830
|
if (!agentType) return { success: false, error: "agentType is required" };
|
|
5400
5831
|
const loader = h.ctx.providerLoader;
|
|
@@ -5407,13 +5838,29 @@ async function handleExtensionScript(h, args, scriptName) {
|
|
|
5407
5838
|
if (!provider.scripts?.[actualScriptName]) {
|
|
5408
5839
|
return { success: false, error: `Script '${actualScriptName}' not available for ${agentType}` };
|
|
5409
5840
|
}
|
|
5410
|
-
const
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
if (
|
|
5414
|
-
|
|
5841
|
+
const normalizedArgs = normalizeProviderScriptArgs(args);
|
|
5842
|
+
if (provider.category === "cli") {
|
|
5843
|
+
const adapter = h.getCliAdapter(args?.targetSessionId || agentType);
|
|
5844
|
+
if (!adapter?.invokeScript) {
|
|
5845
|
+
return { success: false, error: `CLI adapter does not support script '${actualScriptName}'` };
|
|
5846
|
+
}
|
|
5847
|
+
try {
|
|
5848
|
+
const raw = await adapter.invokeScript(actualScriptName, normalizedArgs);
|
|
5849
|
+
const parsed = parseScriptResult(raw);
|
|
5850
|
+
if (!parsed.success) {
|
|
5851
|
+
return { success: false, ...parsed.payload || {} };
|
|
5852
|
+
}
|
|
5853
|
+
const cliCommand = getCliScriptCommand(parsed.payload);
|
|
5854
|
+
if (cliCommand?.type === "send_message" && cliCommand.text) {
|
|
5855
|
+
await adapter.sendMessage(cliCommand.text);
|
|
5856
|
+
}
|
|
5857
|
+
applyProviderPatch(h, args, parsed.payload);
|
|
5858
|
+
return { success: true, ...parsed.payload && typeof parsed.payload === "object" ? parsed.payload : { result: parsed.payload } };
|
|
5859
|
+
} catch (e) {
|
|
5860
|
+
return { success: false, error: `Script execution failed: ${e.message}` };
|
|
5415
5861
|
}
|
|
5416
5862
|
}
|
|
5863
|
+
const scriptFn = provider.scripts[actualScriptName];
|
|
5417
5864
|
const scriptCode = scriptFn(normalizedArgs);
|
|
5418
5865
|
if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
|
|
5419
5866
|
const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || agentType : h.currentSession?.cdpManagerKey || h.currentManagerKey || ideType;
|
|
@@ -5467,16 +5914,29 @@ async function handleExtensionScript(h, args, scriptName) {
|
|
|
5467
5914
|
if (typeof result === "string") {
|
|
5468
5915
|
try {
|
|
5469
5916
|
const parsed = JSON.parse(result);
|
|
5917
|
+
applyProviderPatch(h, args, parsed);
|
|
5918
|
+
if (parsed && typeof parsed === "object" && parsed.success === false) {
|
|
5919
|
+
return { success: false, ...parsed };
|
|
5920
|
+
}
|
|
5470
5921
|
return { success: true, ...parsed };
|
|
5471
5922
|
} catch {
|
|
5472
5923
|
return { success: true, result };
|
|
5473
5924
|
}
|
|
5474
5925
|
}
|
|
5926
|
+
applyProviderPatch(h, args, result);
|
|
5475
5927
|
return { success: true, result };
|
|
5476
5928
|
} catch (e) {
|
|
5477
5929
|
return { success: false, error: `Script execution failed: ${e.message}` };
|
|
5478
5930
|
}
|
|
5479
5931
|
}
|
|
5932
|
+
async function handleExtensionScript(h, args, scriptName) {
|
|
5933
|
+
return executeProviderScript(h, args, scriptName);
|
|
5934
|
+
}
|
|
5935
|
+
async function handleProviderScript(h, args) {
|
|
5936
|
+
const scriptName = typeof args?.scriptName === "string" ? args.scriptName.trim() : "";
|
|
5937
|
+
if (!scriptName) return { success: false, error: "scriptName is required" };
|
|
5938
|
+
return executeProviderScript(h, args, scriptName);
|
|
5939
|
+
}
|
|
5480
5940
|
function handleGetIdeExtensions(h, args) {
|
|
5481
5941
|
const { ideType } = args || {};
|
|
5482
5942
|
const loader = h.ctx.providerLoader;
|
|
@@ -6000,6 +6460,8 @@ var init_handler = __esm({
|
|
|
6000
6460
|
case "set_ide_extension":
|
|
6001
6461
|
return handleSetIdeExtension(this, args);
|
|
6002
6462
|
// ─── Extension Model / Mode Control (stream-commands.ts) ──────────
|
|
6463
|
+
case "invoke_provider_script":
|
|
6464
|
+
return handleProviderScript(this, args);
|
|
6003
6465
|
case "list_extension_models":
|
|
6004
6466
|
return handleExtensionScript(this, args, "listModels");
|
|
6005
6467
|
case "set_extension_model":
|
|
@@ -6684,6 +7146,53 @@ function stripTerminalNoise(str) {
|
|
|
6684
7146
|
function sanitizeTerminalText(str) {
|
|
6685
7147
|
return stripTerminalNoise(stripAnsi(str));
|
|
6686
7148
|
}
|
|
7149
|
+
function splitCliScreenLines(text) {
|
|
7150
|
+
return String(text || "").replace(/\u0007/g, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.replace(/\s+$/, ""));
|
|
7151
|
+
}
|
|
7152
|
+
function isPromptLikeCliLine(line) {
|
|
7153
|
+
const trimmed = String(line || "").trim();
|
|
7154
|
+
if (!trimmed) return false;
|
|
7155
|
+
return /^[❯›>]\s*(?:$|\S.*)$/.test(trimmed);
|
|
7156
|
+
}
|
|
7157
|
+
function buildCliScreenSnapshot(text) {
|
|
7158
|
+
const normalizedText = String(text || "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
7159
|
+
const rawLines = splitCliScreenLines(normalizedText);
|
|
7160
|
+
const lines = rawLines.map((line, index, arr) => {
|
|
7161
|
+
const trimmed = String(line || "").trim();
|
|
7162
|
+
return {
|
|
7163
|
+
index,
|
|
7164
|
+
fromTop: index,
|
|
7165
|
+
fromBottom: arr.length - index - 1,
|
|
7166
|
+
text: line,
|
|
7167
|
+
trimmed,
|
|
7168
|
+
isEmpty: trimmed.length === 0
|
|
7169
|
+
};
|
|
7170
|
+
});
|
|
7171
|
+
const nonEmptyLines = lines.filter((line) => !line.isEmpty);
|
|
7172
|
+
const firstNonEmptyLine = nonEmptyLines[0] ?? null;
|
|
7173
|
+
const lastNonEmptyLine = nonEmptyLines[nonEmptyLines.length - 1] ?? null;
|
|
7174
|
+
let promptLineIndex = -1;
|
|
7175
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
7176
|
+
if (isPromptLikeCliLine(lines[i].text)) {
|
|
7177
|
+
promptLineIndex = i;
|
|
7178
|
+
break;
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
return {
|
|
7182
|
+
text: normalizedText,
|
|
7183
|
+
lineCount: lines.length,
|
|
7184
|
+
lines,
|
|
7185
|
+
nonEmptyLines,
|
|
7186
|
+
firstNonEmptyLineIndex: firstNonEmptyLine?.index ?? -1,
|
|
7187
|
+
lastNonEmptyLineIndex: lastNonEmptyLine?.index ?? -1,
|
|
7188
|
+
firstNonEmptyLine,
|
|
7189
|
+
lastNonEmptyLine,
|
|
7190
|
+
promptLineIndex,
|
|
7191
|
+
promptLine: promptLineIndex >= 0 ? lines[promptLineIndex] : null,
|
|
7192
|
+
linesAbovePrompt: promptLineIndex >= 0 ? lines.slice(0, promptLineIndex) : [...lines],
|
|
7193
|
+
linesBelowPrompt: promptLineIndex >= 0 ? lines.slice(promptLineIndex + 1) : []
|
|
7194
|
+
};
|
|
7195
|
+
}
|
|
6687
7196
|
function computeTerminalQueryTail(buffer) {
|
|
6688
7197
|
const prefixes = ["\x1B[6n", "\x1B[?6n"];
|
|
6689
7198
|
const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
|
|
@@ -6925,7 +7434,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
6925
7434
|
ready = false;
|
|
6926
7435
|
startupBuffer = "";
|
|
6927
7436
|
startupParseGate = false;
|
|
7437
|
+
startupSettleTimer = null;
|
|
6928
7438
|
spawnAt = 0;
|
|
7439
|
+
startupFirstOutputAt = 0;
|
|
6929
7440
|
// PTY I/O
|
|
6930
7441
|
onPtyDataCallback = null;
|
|
6931
7442
|
pendingOutputParseBuffer = "";
|
|
@@ -6966,6 +7477,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
6966
7477
|
statusHistory = [];
|
|
6967
7478
|
// ─── CLI Scripts (script-based parsing) ───
|
|
6968
7479
|
cliScripts;
|
|
7480
|
+
runtimeSettings = {};
|
|
6969
7481
|
/** Full accumulated ANSI-stripped PTY output */
|
|
6970
7482
|
accumulatedBuffer = "";
|
|
6971
7483
|
/** Full accumulated raw PTY output (with ANSI) */
|
|
@@ -6980,14 +7492,15 @@ var init_provider_cli_adapter = __esm({
|
|
|
6980
7492
|
traceSessionId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
6981
7493
|
static MAX_TRACE_ENTRIES = 250;
|
|
6982
7494
|
providerResolutionMeta;
|
|
6983
|
-
static IDLE_FINISH_CONFIRM_MS =
|
|
7495
|
+
static IDLE_FINISH_CONFIRM_MS = 2e3;
|
|
7496
|
+
static STATUS_ACTIVITY_HOLD_MS = 2e3;
|
|
6984
7497
|
static FINISH_RETRY_DELAY_MS = 300;
|
|
6985
7498
|
static MAX_FINISH_RETRIES = 2;
|
|
6986
7499
|
syncMessageViews() {
|
|
6987
7500
|
this.messages = [...this.committedMessages];
|
|
6988
7501
|
this.structuredMessages = [...this.committedMessages];
|
|
6989
7502
|
}
|
|
6990
|
-
|
|
7503
|
+
hydrateParsedMessages(parsedMessages, scope) {
|
|
6991
7504
|
const referenceMessages = [...this.committedMessages];
|
|
6992
7505
|
const usedReferenceIndexes = /* @__PURE__ */ new Set();
|
|
6993
7506
|
const now = Date.now();
|
|
@@ -7020,13 +7533,30 @@ var init_provider_cli_adapter = __esm({
|
|
|
7020
7533
|
const content = typeof message.content === "string" ? message.content : String(message.content || "");
|
|
7021
7534
|
const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
|
|
7022
7535
|
const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
|
|
7536
|
+
const fallbackTimestamp = role === "user" ? scope?.startedAt || now : this.lastOutputAt || scope?.startedAt || now;
|
|
7537
|
+
const timestamp = referenceTimestamp ?? fallbackTimestamp;
|
|
7023
7538
|
return {
|
|
7539
|
+
...message,
|
|
7024
7540
|
role,
|
|
7025
7541
|
content,
|
|
7026
|
-
timestamp
|
|
7542
|
+
timestamp,
|
|
7543
|
+
receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
|
|
7027
7544
|
};
|
|
7028
7545
|
});
|
|
7029
7546
|
}
|
|
7547
|
+
normalizeParsedMessages(parsedMessages, scope) {
|
|
7548
|
+
return this.hydrateParsedMessages(parsedMessages, scope).map((message) => ({
|
|
7549
|
+
role: message.role,
|
|
7550
|
+
content: message.content,
|
|
7551
|
+
timestamp: message.timestamp,
|
|
7552
|
+
receivedAt: message.receivedAt,
|
|
7553
|
+
kind: message.kind,
|
|
7554
|
+
id: message.id,
|
|
7555
|
+
index: message.index,
|
|
7556
|
+
meta: message.meta,
|
|
7557
|
+
senderName: message.senderName
|
|
7558
|
+
}));
|
|
7559
|
+
}
|
|
7030
7560
|
sliceFromOffset(text, start) {
|
|
7031
7561
|
if (!text) return "";
|
|
7032
7562
|
if (!Number.isFinite(start) || start <= 0) return text;
|
|
@@ -7036,14 +7566,20 @@ var init_provider_cli_adapter = __esm({
|
|
|
7036
7566
|
buildParseInput(baseMessages, partialResponse, scope) {
|
|
7037
7567
|
const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
|
|
7038
7568
|
const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
|
|
7569
|
+
const screenText = this.terminalScreen.getText();
|
|
7570
|
+
const recentBuffer = buffer.slice(-1e3) || this.recentOutputBuffer;
|
|
7039
7571
|
return {
|
|
7040
7572
|
buffer,
|
|
7041
7573
|
rawBuffer,
|
|
7042
|
-
recentBuffer
|
|
7043
|
-
screenText
|
|
7574
|
+
recentBuffer,
|
|
7575
|
+
screenText,
|
|
7576
|
+
screen: buildCliScreenSnapshot(screenText),
|
|
7577
|
+
bufferScreen: buildCliScreenSnapshot(buffer),
|
|
7578
|
+
recentScreen: buildCliScreenSnapshot(recentBuffer),
|
|
7044
7579
|
messages: [...baseMessages],
|
|
7045
7580
|
partialResponse,
|
|
7046
|
-
promptText: scope?.prompt || ""
|
|
7581
|
+
promptText: scope?.prompt || "",
|
|
7582
|
+
settings: { ...this.runtimeSettings }
|
|
7047
7583
|
};
|
|
7048
7584
|
}
|
|
7049
7585
|
setStatus(status, trigger) {
|
|
@@ -7149,6 +7685,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
7149
7685
|
const scriptNames = Object.keys(scripts).filter((k) => typeof scripts[k] === "function");
|
|
7150
7686
|
LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
|
|
7151
7687
|
}
|
|
7688
|
+
updateRuntimeSettings(settings) {
|
|
7689
|
+
this.runtimeSettings = { ...settings };
|
|
7690
|
+
}
|
|
7152
7691
|
// ─── Lifecycle ─────────────────────────────────
|
|
7153
7692
|
setServerConn(serverConn) {
|
|
7154
7693
|
this.serverConn = serverConn;
|
|
@@ -7185,7 +7724,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
7185
7724
|
let shellArgs;
|
|
7186
7725
|
const useShellUnix = !isWin && (!!spawnConfig.shell || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
7187
7726
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
7188
|
-
const useShellWin = isCmdShim || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
7727
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
7189
7728
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
7190
7729
|
if (useShell) {
|
|
7191
7730
|
if (!spawnConfig.shell && !isWin) {
|
|
@@ -7283,6 +7822,11 @@ var init_provider_cli_adapter = __esm({
|
|
|
7283
7822
|
this.spawnAt = Date.now();
|
|
7284
7823
|
this.startupParseGate = true;
|
|
7285
7824
|
this.startupBuffer = "";
|
|
7825
|
+
this.startupFirstOutputAt = 0;
|
|
7826
|
+
if (this.startupSettleTimer) {
|
|
7827
|
+
clearTimeout(this.startupSettleTimer);
|
|
7828
|
+
this.startupSettleTimer = null;
|
|
7829
|
+
}
|
|
7286
7830
|
this.terminalScreen.reset(24, 80);
|
|
7287
7831
|
this.pendingTerminalQueryTail = "";
|
|
7288
7832
|
this.currentTurnScope = null;
|
|
@@ -7296,7 +7840,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
7296
7840
|
this.recordTrace("ready", {
|
|
7297
7841
|
runtimeMeta: this.getRuntimeMetadata()
|
|
7298
7842
|
});
|
|
7299
|
-
this.setStatus("
|
|
7843
|
+
this.setStatus("starting", "pty_ready");
|
|
7844
|
+
this.scheduleStartupSettleCheck();
|
|
7300
7845
|
this.onStatusChange?.();
|
|
7301
7846
|
}
|
|
7302
7847
|
// ─── Output Handling ────────────────────────────
|
|
@@ -7311,6 +7856,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
7311
7856
|
this.lastScreenSnapshot = normalizedScreenSnapshot;
|
|
7312
7857
|
this.lastScreenChangeAt = now;
|
|
7313
7858
|
}
|
|
7859
|
+
if (this.startupParseGate && !this.startupFirstOutputAt && (cleanData.trim() || normalizedScreenSnapshot.trim())) {
|
|
7860
|
+
this.startupFirstOutputAt = now;
|
|
7861
|
+
}
|
|
7314
7862
|
if (this.idleFinishCandidate && (rawData.length > 0 || cleanData.length > 0)) {
|
|
7315
7863
|
this.clearIdleFinishCandidate("new_output");
|
|
7316
7864
|
}
|
|
@@ -7321,6 +7869,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
7321
7869
|
cleanPreview: this.summarizeTraceText(cleanData, 300),
|
|
7322
7870
|
screenText: this.summarizeTraceText(this.terminalScreen.getText(), 1200)
|
|
7323
7871
|
});
|
|
7872
|
+
if (this.startupParseGate) {
|
|
7873
|
+
this.scheduleStartupSettleCheck();
|
|
7874
|
+
}
|
|
7324
7875
|
if (this.isWaitingForResponse && cleanData) {
|
|
7325
7876
|
this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
|
|
7326
7877
|
}
|
|
@@ -7334,27 +7885,51 @@ var init_provider_cli_adapter = __esm({
|
|
|
7334
7885
|
this.recentOutputBuffer = (this.recentOutputBuffer + cleanData).slice(-1e3);
|
|
7335
7886
|
this.accumulatedBuffer = (this.accumulatedBuffer + cleanData).slice(-_ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
|
|
7336
7887
|
this.accumulatedRawBuffer = (this.accumulatedRawBuffer + rawData).slice(-_ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
|
|
7337
|
-
|
|
7338
|
-
this.startupBuffer += cleanData;
|
|
7339
|
-
const elapsed = Date.now() - this.spawnAt;
|
|
7340
|
-
const screenText = this.terminalScreen.getText() || "";
|
|
7341
|
-
const startupModal = this.getStartupConfirmationModal(screenText);
|
|
7342
|
-
const scriptStatus = startupModal ? "waiting_approval" : this.runDetectStatus(this.startupBuffer);
|
|
7343
|
-
const hasInteractivePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
7344
|
-
const startupStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
7345
|
-
const isReady = (scriptStatus === "idle" || scriptStatus === "waiting_approval") && hasInteractivePrompt && startupStableMs >= 700 || !!startupModal && startupStableMs >= 700 || elapsed > 8e3 || this.startupBuffer.length > 12e3;
|
|
7346
|
-
if (isReady) {
|
|
7347
|
-
this.startupParseGate = false;
|
|
7348
|
-
this.ready = true;
|
|
7349
|
-
LOG.info(
|
|
7350
|
-
"CLI",
|
|
7351
|
-
`[${this.cliType}] Startup ready (${elapsed}ms, scriptStatus=${scriptStatus}, prompt=${hasInteractivePrompt}, stableMs=${startupStableMs}) providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
|
|
7352
|
-
);
|
|
7353
|
-
this.onStatusChange?.();
|
|
7354
|
-
}
|
|
7355
|
-
}
|
|
7888
|
+
this.resolveStartupState("output");
|
|
7356
7889
|
this.scheduleSettle();
|
|
7357
7890
|
}
|
|
7891
|
+
resolveStartupState(trigger) {
|
|
7892
|
+
if (!this.startupParseGate) return;
|
|
7893
|
+
const now = Date.now();
|
|
7894
|
+
const screenText = this.terminalScreen.getText() || "";
|
|
7895
|
+
const normalizedScreen = normalizeScreenSnapshot(screenText);
|
|
7896
|
+
const hasStartupOutput = !!this.startupFirstOutputAt || !!normalizedScreen.trim();
|
|
7897
|
+
if (!hasStartupOutput) return;
|
|
7898
|
+
const stableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
7899
|
+
if (stableMs < 2e3) return;
|
|
7900
|
+
const startupModal = this.getStartupConfirmationModal(screenText);
|
|
7901
|
+
this.startupParseGate = false;
|
|
7902
|
+
if (this.startupSettleTimer) {
|
|
7903
|
+
clearTimeout(this.startupSettleTimer);
|
|
7904
|
+
this.startupSettleTimer = null;
|
|
7905
|
+
}
|
|
7906
|
+
this.ready = true;
|
|
7907
|
+
if (startupModal) {
|
|
7908
|
+
this.activeModal = startupModal;
|
|
7909
|
+
this.setStatus("waiting_approval", `startup_ready:${trigger}`);
|
|
7910
|
+
} else {
|
|
7911
|
+
this.setStatus("idle", `startup_ready:${trigger}`);
|
|
7912
|
+
}
|
|
7913
|
+
LOG.info(
|
|
7914
|
+
"CLI",
|
|
7915
|
+
`[${this.cliType}] Startup settled (${trigger}, stableMs=${stableMs}, modal=${!!startupModal}) providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
|
|
7916
|
+
);
|
|
7917
|
+
this.onStatusChange?.();
|
|
7918
|
+
}
|
|
7919
|
+
scheduleStartupSettleCheck() {
|
|
7920
|
+
if (!this.startupParseGate) return;
|
|
7921
|
+
if (this.startupSettleTimer) clearTimeout(this.startupSettleTimer);
|
|
7922
|
+
const now = Date.now();
|
|
7923
|
+
const stableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
7924
|
+
const delayMs = Math.max(250, 2050 - stableMs);
|
|
7925
|
+
this.startupSettleTimer = setTimeout(() => {
|
|
7926
|
+
this.startupSettleTimer = null;
|
|
7927
|
+
this.resolveStartupState("startup_timer");
|
|
7928
|
+
if (this.startupParseGate && Date.now() - this.spawnAt < 1e4) {
|
|
7929
|
+
this.scheduleStartupSettleCheck();
|
|
7930
|
+
}
|
|
7931
|
+
}, delayMs);
|
|
7932
|
+
}
|
|
7358
7933
|
scheduleSettle() {
|
|
7359
7934
|
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
7360
7935
|
const settleEpoch = this.responseEpoch;
|
|
@@ -7396,6 +7971,43 @@ var init_provider_cli_adapter = __esm({
|
|
|
7396
7971
|
if (!text.trim()) return false;
|
|
7397
7972
|
return /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(text) || /⏎\s+send/i.test(text) || /\?\s*for\s*shortcuts/i.test(text) || /Type your message(?:\s+or\s+@path\/to\/file)?/i.test(text) || /workspace\s*\(\/directory\)/i.test(text) || /for\s*shortcuts/i.test(text);
|
|
7398
7973
|
}
|
|
7974
|
+
findLastMatchingLineIndex(lines, predicate) {
|
|
7975
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
7976
|
+
if (predicate(lines[index])) return index;
|
|
7977
|
+
}
|
|
7978
|
+
return -1;
|
|
7979
|
+
}
|
|
7980
|
+
looksLikeClaudeGeneratingLine(line) {
|
|
7981
|
+
const trimmed = String(line || "").trim();
|
|
7982
|
+
if (!trimmed) return false;
|
|
7983
|
+
if (/esc to (cancel|interrupt|stop)/i.test(trimmed)) return true;
|
|
7984
|
+
if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+\s+\S+.*\b(?:thinking|thought for \d+s?)\b/i.test(trimmed)) return true;
|
|
7985
|
+
if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+\s+[A-Z][A-Za-z-]{3,}ing\b.*(?:…|\.{3})/u.test(trimmed)) return true;
|
|
7986
|
+
if (/^[⏺•]\s+(?:Reading|Writing|Editing|Searching|Inspecting|Planning|Analyzing|Synthesizing|Drafting|Running|Listing|Scanning|Matching)\b.*(?:…|\.{3})/i.test(trimmed)) {
|
|
7987
|
+
return /ctrl\+o to expand/i.test(trimmed) || /\b\d+\s+(?:file|files|pattern|patterns|director(?:y|ies)|match|matches|result|results)\b/i.test(trimmed);
|
|
7988
|
+
}
|
|
7989
|
+
return false;
|
|
7990
|
+
}
|
|
7991
|
+
detectClaudeGeneratingOverride(screenText, tail) {
|
|
7992
|
+
if (this.cliType !== "claude-cli") return false;
|
|
7993
|
+
const source = sanitizeTerminalText(screenText || tail || "");
|
|
7994
|
+
if (!source.trim()) return false;
|
|
7995
|
+
const allLines = source.split(/\r\n|\n|\r/g).map((line) => line.trim()).filter(Boolean);
|
|
7996
|
+
if (allLines.length === 0) return false;
|
|
7997
|
+
const recentLines = allLines.slice(-12);
|
|
7998
|
+
const promptIndex = this.findLastMatchingLineIndex(recentLines, (line) => /^[❯›>]\s*$/.test(line));
|
|
7999
|
+
const activeRegion = promptIndex >= 0 ? recentLines.slice(Math.max(0, promptIndex - 2), promptIndex) : recentLines;
|
|
8000
|
+
if (activeRegion.length === 0) return false;
|
|
8001
|
+
return activeRegion.some((line) => this.looksLikeClaudeGeneratingLine(line));
|
|
8002
|
+
}
|
|
8003
|
+
refineDetectedStatus(status, tail, screenText) {
|
|
8004
|
+
if (this.startupParseGate) {
|
|
8005
|
+
return this.getStartupConfirmationModal(screenText || "") ? "waiting_approval" : "starting";
|
|
8006
|
+
}
|
|
8007
|
+
if (status === "waiting_approval") return status;
|
|
8008
|
+
if (this.detectClaudeGeneratingOverride(screenText || "", tail)) return "generating";
|
|
8009
|
+
return status;
|
|
8010
|
+
}
|
|
7399
8011
|
looksLikeVisibleAssistantCandidate(screenText) {
|
|
7400
8012
|
const lines = sanitizeTerminalText(String(screenText || "")).split(/\r\n|\n|\r/g);
|
|
7401
8013
|
for (const line of lines) {
|
|
@@ -7430,6 +8042,11 @@ var init_provider_cli_adapter = __esm({
|
|
|
7430
8042
|
const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
7431
8043
|
return quietForMs < 1200 || screenStableMs < 1200 || !commitResult.hasAssistant;
|
|
7432
8044
|
}
|
|
8045
|
+
hasRecentInteractiveActivity(now) {
|
|
8046
|
+
const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
8047
|
+
const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : Number.MAX_SAFE_INTEGER;
|
|
8048
|
+
return quietForMs < _ProviderCliAdapter.STATUS_ACTIVITY_HOLD_MS || screenStableMs < _ProviderCliAdapter.STATUS_ACTIVITY_HOLD_MS;
|
|
8049
|
+
}
|
|
7433
8050
|
getStartupConfirmationModal(screenText) {
|
|
7434
8051
|
const text = sanitizeTerminalText(String(screenText || ""));
|
|
7435
8052
|
if (!text.trim()) return null;
|
|
@@ -7457,13 +8074,14 @@ var init_provider_cli_adapter = __esm({
|
|
|
7457
8074
|
const startedAt = Date.now();
|
|
7458
8075
|
let loggedWait = false;
|
|
7459
8076
|
while (Date.now() - startedAt < maxWaitMs) {
|
|
8077
|
+
this.resolveStartupState("interactive_wait");
|
|
7460
8078
|
const screenText = this.terminalScreen.getText() || "";
|
|
7461
8079
|
const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
7462
8080
|
const stableMs = this.lastScreenChangeAt ? Date.now() - this.lastScreenChangeAt : 0;
|
|
7463
8081
|
const recentlyOutput = this.lastNonEmptyOutputAt ? Date.now() - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
7464
8082
|
const status = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
|
|
7465
8083
|
const startupLikelyActive = /Welcome back|Tips for getting|Recent activity|Claude Code v\d/i.test(screenText);
|
|
7466
|
-
const interactiveReady = hasPrompt && stableMs >= 700 && recentlyOutput >= 350 && status !== "
|
|
8084
|
+
const interactiveReady = hasPrompt && stableMs >= 700 && recentlyOutput >= 350 && status !== "generating";
|
|
7467
8085
|
if (interactiveReady) {
|
|
7468
8086
|
if (loggedWait) {
|
|
7469
8087
|
LOG.info(
|
|
@@ -7502,6 +8120,10 @@ var init_provider_cli_adapter = __esm({
|
|
|
7502
8120
|
}
|
|
7503
8121
|
const tail = this.settledBuffer;
|
|
7504
8122
|
const screenText = this.terminalScreen.getText() || "";
|
|
8123
|
+
this.resolveStartupState("settled");
|
|
8124
|
+
if (this.startupParseGate) {
|
|
8125
|
+
return;
|
|
8126
|
+
}
|
|
7505
8127
|
const startupModal = this.getStartupConfirmationModal(screenText);
|
|
7506
8128
|
const modal = this.runParseApproval(tail) || startupModal;
|
|
7507
8129
|
const rawScriptStatus = this.runDetectStatus(tail);
|
|
@@ -7564,6 +8186,28 @@ var init_provider_cli_adapter = __esm({
|
|
|
7564
8186
|
} else {
|
|
7565
8187
|
clearPendingScriptStatus();
|
|
7566
8188
|
}
|
|
8189
|
+
const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
|
|
8190
|
+
const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity;
|
|
8191
|
+
if (shouldHoldGenerating) {
|
|
8192
|
+
this.clearIdleFinishCandidate("hold_generating_recent_activity");
|
|
8193
|
+
this.setStatus("generating", "recent_activity_hold");
|
|
8194
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
8195
|
+
this.idleTimeout = setTimeout(() => {
|
|
8196
|
+
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
8197
|
+
this.finishResponse();
|
|
8198
|
+
}
|
|
8199
|
+
}, this.timeouts.generatingIdle);
|
|
8200
|
+
this.recordTrace("hold_generating_recent_activity", {
|
|
8201
|
+
scriptStatus,
|
|
8202
|
+
recentInteractiveActivity,
|
|
8203
|
+
lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
|
|
8204
|
+
lastScreenChangeAt: this.lastScreenChangeAt,
|
|
8205
|
+
holdMs: _ProviderCliAdapter.STATUS_ACTIVITY_HOLD_MS,
|
|
8206
|
+
...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
|
|
8207
|
+
});
|
|
8208
|
+
this.onStatusChange?.();
|
|
8209
|
+
return;
|
|
8210
|
+
}
|
|
7567
8211
|
if (scriptStatus === "waiting_approval") {
|
|
7568
8212
|
this.clearIdleFinishCandidate("waiting_approval");
|
|
7569
8213
|
const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
|
|
@@ -7641,8 +8285,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
7641
8285
|
const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
7642
8286
|
const hasAssistantTurn = !!lastParsedAssistant;
|
|
7643
8287
|
const assistantLength = lastParsedAssistant?.content?.length || 0;
|
|
7644
|
-
const idleQuietThresholdMs = Math.max(
|
|
7645
|
-
const idleStableThresholdMs =
|
|
8288
|
+
const idleQuietThresholdMs = Math.max(2e3, this.timeouts.outputSettle);
|
|
8289
|
+
const idleStableThresholdMs = 2e3;
|
|
7646
8290
|
const idleReady = visibleIdlePrompt && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
|
|
7647
8291
|
const candidate = this.idleFinishCandidate;
|
|
7648
8292
|
const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS;
|
|
@@ -7756,7 +8400,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
7756
8400
|
this.currentTurnScope
|
|
7757
8401
|
);
|
|
7758
8402
|
if (parsed && Array.isArray(parsed.messages)) {
|
|
7759
|
-
this.committedMessages = this.normalizeParsedMessages(parsed.messages);
|
|
8403
|
+
this.committedMessages = this.normalizeParsedMessages(parsed.messages, this.currentTurnScope);
|
|
7760
8404
|
const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
|
|
7761
8405
|
if (promptForTrim) {
|
|
7762
8406
|
const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
@@ -7793,11 +8437,15 @@ var init_provider_cli_adapter = __esm({
|
|
|
7793
8437
|
runDetectStatus(text) {
|
|
7794
8438
|
if (!this.cliScripts?.detectStatus) return null;
|
|
7795
8439
|
try {
|
|
7796
|
-
|
|
8440
|
+
const screenText = this.terminalScreen.getText();
|
|
8441
|
+
const status = this.cliScripts.detectStatus({
|
|
7797
8442
|
tail: text.slice(-500),
|
|
7798
|
-
screenText
|
|
7799
|
-
rawBuffer: this.accumulatedRawBuffer
|
|
8443
|
+
screenText,
|
|
8444
|
+
rawBuffer: this.accumulatedRawBuffer,
|
|
8445
|
+
screen: buildCliScreenSnapshot(screenText),
|
|
8446
|
+
tailScreen: buildCliScreenSnapshot(text.slice(-500))
|
|
7800
8447
|
});
|
|
8448
|
+
return this.refineDetectedStatus(status, text, screenText || "");
|
|
7801
8449
|
} catch (e) {
|
|
7802
8450
|
LOG.warn("CLI", `[${this.cliType}] detectStatus error: ${e.message}`);
|
|
7803
8451
|
return null;
|
|
@@ -7806,11 +8454,16 @@ var init_provider_cli_adapter = __esm({
|
|
|
7806
8454
|
runParseApproval(tail) {
|
|
7807
8455
|
if (!this.cliScripts?.parseApproval) return null;
|
|
7808
8456
|
try {
|
|
8457
|
+
const screenText = this.terminalScreen.getText();
|
|
8458
|
+
const buffer = screenText || this.accumulatedBuffer;
|
|
7809
8459
|
return this.cliScripts.parseApproval({
|
|
7810
|
-
buffer
|
|
7811
|
-
screenText
|
|
8460
|
+
buffer,
|
|
8461
|
+
screenText,
|
|
7812
8462
|
rawBuffer: this.accumulatedRawBuffer,
|
|
7813
|
-
tail
|
|
8463
|
+
tail,
|
|
8464
|
+
screen: buildCliScreenSnapshot(screenText),
|
|
8465
|
+
bufferScreen: buildCliScreenSnapshot(buffer),
|
|
8466
|
+
tailScreen: buildCliScreenSnapshot(tail)
|
|
7814
8467
|
});
|
|
7815
8468
|
} catch (e) {
|
|
7816
8469
|
LOG.warn("CLI", `[${this.cliType}] parseApproval error: ${e.message}`);
|
|
@@ -7826,6 +8479,21 @@ var init_provider_cli_adapter = __esm({
|
|
|
7826
8479
|
activeModal: this.activeModal
|
|
7827
8480
|
};
|
|
7828
8481
|
}
|
|
8482
|
+
seedCommittedMessages(messages) {
|
|
8483
|
+
const normalized = (Array.isArray(messages) ? messages : []).filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
|
|
8484
|
+
role: message.role,
|
|
8485
|
+
content: typeof message.content === "string" ? message.content : String(message.content || ""),
|
|
8486
|
+
timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0,
|
|
8487
|
+
receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : void 0,
|
|
8488
|
+
kind: typeof message.kind === "string" ? message.kind : void 0,
|
|
8489
|
+
id: typeof message.id === "string" ? message.id : void 0,
|
|
8490
|
+
index: typeof message.index === "number" ? message.index : void 0,
|
|
8491
|
+
meta: message.meta && typeof message.meta === "object" ? { ...message.meta } : void 0,
|
|
8492
|
+
senderName: typeof message.senderName === "string" ? message.senderName : void 0
|
|
8493
|
+
}));
|
|
8494
|
+
this.committedMessages = normalized;
|
|
8495
|
+
this.syncMessageViews();
|
|
8496
|
+
}
|
|
7829
8497
|
/**
|
|
7830
8498
|
* Script-based full parse — returns ReadChatResult.
|
|
7831
8499
|
* Called by command handler / dashboard for rich content rendering.
|
|
@@ -7836,12 +8504,20 @@ var init_provider_cli_adapter = __esm({
|
|
|
7836
8504
|
this.responseBuffer,
|
|
7837
8505
|
this.currentTurnScope
|
|
7838
8506
|
);
|
|
8507
|
+
const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
|
|
7839
8508
|
if (parsed && Array.isArray(parsed.messages)) {
|
|
8509
|
+
const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => ({
|
|
8510
|
+
...message,
|
|
8511
|
+
id: message.id || `msg_${index}`,
|
|
8512
|
+
index: typeof message.index === "number" ? message.index : index,
|
|
8513
|
+
kind: message.kind || "standard",
|
|
8514
|
+
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
8515
|
+
})) : this.hydrateParsedMessages(parsed.messages, this.currentTurnScope);
|
|
7840
8516
|
return {
|
|
7841
8517
|
id: parsed.id || "cli_session",
|
|
7842
8518
|
status: parsed.status || this.currentStatus,
|
|
7843
8519
|
title: parsed.title || this.cliName,
|
|
7844
|
-
messages:
|
|
8520
|
+
messages: hydratedMessages,
|
|
7845
8521
|
activeModal: parsed.activeModal ?? this.activeModal,
|
|
7846
8522
|
providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0
|
|
7847
8523
|
};
|
|
@@ -7862,11 +8538,30 @@ var init_provider_cli_adapter = __esm({
|
|
|
7862
8538
|
activeModal: this.activeModal
|
|
7863
8539
|
};
|
|
7864
8540
|
}
|
|
8541
|
+
async invokeScript(scriptName, args) {
|
|
8542
|
+
const fn = this.cliScripts?.[scriptName];
|
|
8543
|
+
if (typeof fn !== "function") {
|
|
8544
|
+
throw new Error(`CLI script '${scriptName}' not available`);
|
|
8545
|
+
}
|
|
8546
|
+
const input = this.buildParseInput(
|
|
8547
|
+
this.committedMessages,
|
|
8548
|
+
this.responseBuffer,
|
|
8549
|
+
this.currentTurnScope
|
|
8550
|
+
);
|
|
8551
|
+
return await Promise.resolve(fn({
|
|
8552
|
+
...input,
|
|
8553
|
+
args: args && typeof args === "object" ? { ...args } : {}
|
|
8554
|
+
}));
|
|
8555
|
+
}
|
|
7865
8556
|
parseCurrentTranscript(baseMessages, partialResponse, scope) {
|
|
7866
8557
|
if (!this.cliScripts?.parseOutput) return null;
|
|
7867
8558
|
try {
|
|
7868
8559
|
const input = this.buildParseInput(baseMessages, partialResponse, scope);
|
|
7869
8560
|
const parsed = this.cliScripts.parseOutput(input);
|
|
8561
|
+
const refinedStatus = this.refineDetectedStatus(typeof parsed?.status === "string" ? parsed.status : null, input.recentBuffer, input.screenText);
|
|
8562
|
+
if (parsed && refinedStatus && parsed.status !== refinedStatus) {
|
|
8563
|
+
parsed.status = refinedStatus;
|
|
8564
|
+
}
|
|
7870
8565
|
const promptForTrim = scope?.prompt || getLastUserPromptText(baseMessages);
|
|
7871
8566
|
if (parsed && Array.isArray(parsed.messages) && promptForTrim) {
|
|
7872
8567
|
const lastAssistant = [...parsed.messages].reverse().find((message) => message?.role === "assistant" && typeof message.content === "string");
|
|
@@ -7913,12 +8608,23 @@ ${data.message || ""}`.trim();
|
|
|
7913
8608
|
if (this.startupParseGate) {
|
|
7914
8609
|
const deadline = Date.now() + 1e4;
|
|
7915
8610
|
while (this.startupParseGate && Date.now() < deadline) {
|
|
8611
|
+
this.resolveStartupState("send_wait");
|
|
7916
8612
|
await new Promise((resolve13) => setTimeout(resolve13, 50));
|
|
7917
8613
|
}
|
|
7918
8614
|
}
|
|
8615
|
+
await this.waitForInteractivePrompt();
|
|
8616
|
+
if (!this.ready) {
|
|
8617
|
+
this.resolveStartupState("send_precheck");
|
|
8618
|
+
const screenText = this.terminalScreen.getText() || "";
|
|
8619
|
+
const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
8620
|
+
if (hasPrompt && this.currentStatus === "idle") {
|
|
8621
|
+
this.ready = true;
|
|
8622
|
+
this.startupParseGate = false;
|
|
8623
|
+
LOG.info("CLI", `[${this.cliType}] sendMessage recovered idle prompt readiness`);
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
7919
8626
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
7920
8627
|
if (this.isWaitingForResponse) return;
|
|
7921
|
-
await this.waitForInteractivePrompt();
|
|
7922
8628
|
const blockingModal = this.activeModal || this.getStartupConfirmationModal(this.terminalScreen.getText() || "");
|
|
7923
8629
|
if (blockingModal || this.currentStatus === "waiting_approval") {
|
|
7924
8630
|
throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
|
|
@@ -7962,8 +8668,6 @@ ${data.message || ""}`.trim();
|
|
|
7962
8668
|
}
|
|
7963
8669
|
this.responseEpoch += 1;
|
|
7964
8670
|
this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
7965
|
-
this.setStatus("generating", "sendMessage");
|
|
7966
|
-
this.onStatusChange?.();
|
|
7967
8671
|
const startResponseTimeout = () => {
|
|
7968
8672
|
if (this.responseTimeout) clearTimeout(this.responseTimeout);
|
|
7969
8673
|
this.responseTimeout = setTimeout(() => {
|
|
@@ -7982,7 +8686,7 @@ ${data.message || ""}`.trim();
|
|
|
7982
8686
|
const retrySubmitIfStuck = (attempt) => {
|
|
7983
8687
|
this.submitRetryTimer = null;
|
|
7984
8688
|
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
7985
|
-
if (this.currentStatus
|
|
8689
|
+
if (this.currentStatus === "waiting_approval") return;
|
|
7986
8690
|
if ((this.responseBuffer || "").trim()) return;
|
|
7987
8691
|
const screenText = this.terminalScreen.getText();
|
|
7988
8692
|
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
@@ -8017,7 +8721,7 @@ ${data.message || ""}`.trim();
|
|
|
8017
8721
|
this.submitRetryTimer = setTimeout(() => {
|
|
8018
8722
|
this.submitRetryTimer = null;
|
|
8019
8723
|
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
8020
|
-
if (this.currentStatus
|
|
8724
|
+
if (this.currentStatus === "waiting_approval") return;
|
|
8021
8725
|
if ((this.responseBuffer || "").trim()) return;
|
|
8022
8726
|
const screenText = this.terminalScreen.getText();
|
|
8023
8727
|
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
@@ -8449,6 +9153,7 @@ var init_cli_provider_instance = __esm({
|
|
|
8449
9153
|
init_status_monitor();
|
|
8450
9154
|
init_chat_history();
|
|
8451
9155
|
init_logger();
|
|
9156
|
+
init_control_effects();
|
|
8452
9157
|
CachedDatabaseSync = null;
|
|
8453
9158
|
CliProviderInstance = class {
|
|
8454
9159
|
constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
|
|
@@ -8477,6 +9182,8 @@ var init_cli_provider_instance = __esm({
|
|
|
8477
9182
|
generatingDebounceTimer = null;
|
|
8478
9183
|
generatingDebouncePending = null;
|
|
8479
9184
|
lastApprovalEventAt = 0;
|
|
9185
|
+
controlValues = {};
|
|
9186
|
+
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
8480
9187
|
historyWriter;
|
|
8481
9188
|
runtimeMessages = [];
|
|
8482
9189
|
instanceId;
|
|
@@ -8489,6 +9196,7 @@ var init_cli_provider_instance = __esm({
|
|
|
8489
9196
|
async init(context) {
|
|
8490
9197
|
this.context = context;
|
|
8491
9198
|
this.settings = context.settings || {};
|
|
9199
|
+
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
8492
9200
|
this.monitor.updateConfig({
|
|
8493
9201
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
8494
9202
|
longGeneratingAlert: this.settings.longGeneratingAlert !== false,
|
|
@@ -8504,6 +9212,21 @@ var init_cli_provider_instance = __esm({
|
|
|
8504
9212
|
this.detectStatusTransition();
|
|
8505
9213
|
});
|
|
8506
9214
|
await this.adapter.spawn();
|
|
9215
|
+
if (this.providerSessionId) {
|
|
9216
|
+
const restoredHistory = readChatHistory(this.type, 0, 200, this.providerSessionId);
|
|
9217
|
+
if (restoredHistory.messages.length > 0) {
|
|
9218
|
+
this.adapter.seedCommittedMessages(
|
|
9219
|
+
restoredHistory.messages.map((message) => ({
|
|
9220
|
+
role: message.role,
|
|
9221
|
+
content: message.content,
|
|
9222
|
+
timestamp: message.receivedAt,
|
|
9223
|
+
receivedAt: message.receivedAt,
|
|
9224
|
+
kind: message.kind,
|
|
9225
|
+
senderName: message.senderName
|
|
9226
|
+
}))
|
|
9227
|
+
);
|
|
9228
|
+
}
|
|
9229
|
+
}
|
|
8507
9230
|
if (this.providerSessionId && this.launchMode === "resume") {
|
|
8508
9231
|
const resumedAt = Date.now();
|
|
8509
9232
|
this.historyWriter.appendSystemMarker(
|
|
@@ -8584,6 +9307,12 @@ var init_cli_provider_instance = __esm({
|
|
|
8584
9307
|
}
|
|
8585
9308
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
8586
9309
|
const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
|
|
9310
|
+
const controlValues = extractProviderControlValues(this.provider.controls, parsedStatus);
|
|
9311
|
+
if (controlValues) {
|
|
9312
|
+
this.controlValues = controlValues;
|
|
9313
|
+
} else if (Object.keys(this.controlValues).length > 0) {
|
|
9314
|
+
this.controlValues = {};
|
|
9315
|
+
}
|
|
8587
9316
|
const mergedMessages = this.mergeConversationMessages(parsedMessages);
|
|
8588
9317
|
const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
|
|
8589
9318
|
if (parsedMessages.length > 0) {
|
|
@@ -8604,6 +9333,7 @@ var init_cli_provider_instance = __esm({
|
|
|
8604
9333
|
);
|
|
8605
9334
|
}
|
|
8606
9335
|
}
|
|
9336
|
+
this.applyProviderResponse(parsedStatus, { phase: "immediate" });
|
|
8607
9337
|
return {
|
|
8608
9338
|
type: this.type,
|
|
8609
9339
|
name: this.provider.name,
|
|
@@ -8633,8 +9363,7 @@ var init_cli_provider_instance = __esm({
|
|
|
8633
9363
|
attachedClients: runtime.attachedClients || []
|
|
8634
9364
|
} : void 0,
|
|
8635
9365
|
resume: this.provider.resume,
|
|
8636
|
-
controlValues:
|
|
8637
|
-
// CLI controls not yet wired from stream
|
|
9366
|
+
controlValues: this.controlValues,
|
|
8638
9367
|
providerControls: this.provider.controls
|
|
8639
9368
|
};
|
|
8640
9369
|
}
|
|
@@ -8645,6 +9374,15 @@ var init_cli_provider_instance = __esm({
|
|
|
8645
9374
|
getPresentationMode() {
|
|
8646
9375
|
return this.presentationMode;
|
|
8647
9376
|
}
|
|
9377
|
+
updateSettings(newSettings) {
|
|
9378
|
+
this.settings = { ...newSettings };
|
|
9379
|
+
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
9380
|
+
this.monitor.updateConfig({
|
|
9381
|
+
approvalAlert: this.settings.approvalAlert !== false,
|
|
9382
|
+
longGeneratingAlert: this.settings.longGeneratingAlert !== false,
|
|
9383
|
+
longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
|
|
9384
|
+
});
|
|
9385
|
+
}
|
|
8648
9386
|
onEvent(event, data) {
|
|
8649
9387
|
if (event === "send_message" && data?.text) {
|
|
8650
9388
|
void this.adapter.sendMessage(data.text).catch((e) => {
|
|
@@ -8656,22 +9394,27 @@ var init_cli_provider_instance = __esm({
|
|
|
8656
9394
|
void this.adapter.resolveAction(data).catch((e) => {
|
|
8657
9395
|
LOG.warn("CLI", `[${this.type}] resolve_action failed: ${e?.message || e}`);
|
|
8658
9396
|
});
|
|
9397
|
+
} else if (event === "provider_state_patch" && data && typeof data === "object") {
|
|
9398
|
+
this.applyProviderResponse(data, { phase: "immediate" });
|
|
8659
9399
|
}
|
|
8660
9400
|
}
|
|
8661
9401
|
dispose() {
|
|
8662
9402
|
this.adapter.shutdown();
|
|
8663
9403
|
this.monitor.reset();
|
|
9404
|
+
this.appliedEffectKeys.clear();
|
|
8664
9405
|
}
|
|
8665
9406
|
completedDebounceTimer = null;
|
|
8666
9407
|
completedDebouncePending = null;
|
|
8667
9408
|
detectStatusTransition() {
|
|
8668
9409
|
const now = Date.now();
|
|
8669
9410
|
const adapterStatus = this.adapter.getStatus();
|
|
9411
|
+
const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
|
|
8670
9412
|
const newStatus = adapterStatus.status;
|
|
8671
9413
|
const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
|
|
8672
9414
|
const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
|
|
8673
9415
|
const partial2 = this.adapter.getPartialResponse();
|
|
8674
9416
|
const progressFingerprint = newStatus === "generating" ? `${partial2 || ""}::${adapterStatus.messages.at(-1)?.content || ""}`.slice(-2e3) : void 0;
|
|
9417
|
+
const previousStatus = this.lastStatus;
|
|
8675
9418
|
if (newStatus !== this.lastStatus) {
|
|
8676
9419
|
LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
|
|
8677
9420
|
if (this.lastStatus === "idle" && newStatus === "generating") {
|
|
@@ -8764,6 +9507,9 @@ var init_cli_provider_instance = __esm({
|
|
|
8764
9507
|
}
|
|
8765
9508
|
this.lastStatus = newStatus;
|
|
8766
9509
|
}
|
|
9510
|
+
this.applyProviderResponse(parsedStatus, {
|
|
9511
|
+
phase: newStatus === "idle" && (previousStatus === "generating" || previousStatus === "waiting_approval") ? "turn_completed" : "immediate"
|
|
9512
|
+
});
|
|
8767
9513
|
const agentKey = `${this.type}:cli`;
|
|
8768
9514
|
const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint);
|
|
8769
9515
|
for (const me of monitorEvents) {
|
|
@@ -8779,6 +9525,88 @@ var init_cli_provider_instance = __esm({
|
|
|
8779
9525
|
this.events = [];
|
|
8780
9526
|
return events;
|
|
8781
9527
|
}
|
|
9528
|
+
applyProviderResponse(data, options) {
|
|
9529
|
+
if (!data || typeof data !== "object") return;
|
|
9530
|
+
const controlValues = extractProviderControlValues(this.provider.controls, data);
|
|
9531
|
+
if (controlValues) {
|
|
9532
|
+
this.controlValues = { ...this.controlValues, ...controlValues };
|
|
9533
|
+
}
|
|
9534
|
+
const effects = normalizeProviderEffects(data);
|
|
9535
|
+
for (const effect of effects) {
|
|
9536
|
+
const effectWhen = effect.when || "immediate";
|
|
9537
|
+
if (effectWhen === "turn_completed" && options.phase !== "turn_completed") continue;
|
|
9538
|
+
if (effectWhen === "immediate" && options.phase === "turn_completed") continue;
|
|
9539
|
+
const effectKey = this.getEffectDedupKey(effect);
|
|
9540
|
+
if (this.appliedEffectKeys.has(effectKey)) continue;
|
|
9541
|
+
this.appliedEffectKeys.add(effectKey);
|
|
9542
|
+
if (effect.persist !== false) {
|
|
9543
|
+
const persisted = this.getPersistedEffectContent(effect);
|
|
9544
|
+
if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
|
|
9545
|
+
}
|
|
9546
|
+
if (effect.type === "message" && effect.message) {
|
|
9547
|
+
const content = typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content);
|
|
9548
|
+
this.pushEvent({
|
|
9549
|
+
event: "provider:message",
|
|
9550
|
+
timestamp: Date.now(),
|
|
9551
|
+
content,
|
|
9552
|
+
role: effect.message.role || "system",
|
|
9553
|
+
kind: effect.message.kind,
|
|
9554
|
+
senderName: effect.message.senderName
|
|
9555
|
+
});
|
|
9556
|
+
} else if (effect.type === "toast" && effect.toast) {
|
|
9557
|
+
this.pushEvent({
|
|
9558
|
+
event: "provider:toast",
|
|
9559
|
+
effectId: effect.id || effectKey,
|
|
9560
|
+
timestamp: Date.now(),
|
|
9561
|
+
message: effect.toast.message,
|
|
9562
|
+
level: effect.toast.level || "info"
|
|
9563
|
+
});
|
|
9564
|
+
} else if (effect.type === "notification" && effect.notification) {
|
|
9565
|
+
this.pushEvent({
|
|
9566
|
+
event: "provider:notification",
|
|
9567
|
+
effectId: effect.id || effectKey,
|
|
9568
|
+
timestamp: Date.now(),
|
|
9569
|
+
title: effect.notification.title,
|
|
9570
|
+
message: effect.notification.body,
|
|
9571
|
+
content: typeof effect.notification.bubbleContent === "string" ? effect.notification.bubbleContent : effect.notification.body,
|
|
9572
|
+
level: effect.notification.level || "info",
|
|
9573
|
+
channels: effect.notification.channels || ["toast"],
|
|
9574
|
+
preferenceKey: effect.notification.preferenceKey
|
|
9575
|
+
});
|
|
9576
|
+
}
|
|
9577
|
+
}
|
|
9578
|
+
if (this.appliedEffectKeys.size > 200) {
|
|
9579
|
+
this.appliedEffectKeys = new Set(Array.from(this.appliedEffectKeys).slice(-100));
|
|
9580
|
+
}
|
|
9581
|
+
}
|
|
9582
|
+
getEffectDedupKey(effect) {
|
|
9583
|
+
if (effect.id) return `provider_effect:${effect.id}`;
|
|
9584
|
+
if (effect.type === "message") {
|
|
9585
|
+
const content = typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
9586
|
+
return `provider_effect:message:${content}`;
|
|
9587
|
+
}
|
|
9588
|
+
if (effect.type === "notification") {
|
|
9589
|
+
return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
|
|
9590
|
+
}
|
|
9591
|
+
return `provider_effect:toast:${effect.toast?.message || ""}`;
|
|
9592
|
+
}
|
|
9593
|
+
getPersistedEffectContent(effect) {
|
|
9594
|
+
if (effect.type === "message") {
|
|
9595
|
+
return typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
9596
|
+
}
|
|
9597
|
+
if (effect.type === "toast") {
|
|
9598
|
+
return effect.toast?.message || null;
|
|
9599
|
+
}
|
|
9600
|
+
if (effect.type === "notification") {
|
|
9601
|
+
if (typeof effect.notification?.bubbleContent === "string") return effect.notification.bubbleContent;
|
|
9602
|
+
if (typeof effect.notification?.title === "string" && effect.notification.title.trim()) {
|
|
9603
|
+
return `${effect.notification.title}
|
|
9604
|
+
${effect.notification.body || ""}`.trim();
|
|
9605
|
+
}
|
|
9606
|
+
return effect.notification?.body || null;
|
|
9607
|
+
}
|
|
9608
|
+
return null;
|
|
9609
|
+
}
|
|
8782
9610
|
// ─── Adapter access (backward compat) ──────────────────
|
|
8783
9611
|
getAdapter() {
|
|
8784
9612
|
return this.adapter;
|
|
@@ -29633,6 +30461,22 @@ function getMacAppIdentifiers() {
|
|
|
29633
30461
|
function getWinProcessNames() {
|
|
29634
30462
|
return getProviderLoader().getWinProcessNames();
|
|
29635
30463
|
}
|
|
30464
|
+
function getProviderMeta(ideId) {
|
|
30465
|
+
return getProviderLoader().getMeta(ideId);
|
|
30466
|
+
}
|
|
30467
|
+
function getPreferredLaunchMethod(ideId, platform11) {
|
|
30468
|
+
const prefer = getProviderMeta(ideId)?.launch?.prefer;
|
|
30469
|
+
const value = prefer?.[platform11];
|
|
30470
|
+
return value === "cli" || value === "app" || value === "auto" ? value : "auto";
|
|
30471
|
+
}
|
|
30472
|
+
function getCdpStartupTimeoutMs(ideId) {
|
|
30473
|
+
const value = getProviderMeta(ideId)?.launch?.cdpStartupTimeoutMs;
|
|
30474
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 15e3;
|
|
30475
|
+
return Math.max(1e3, Math.floor(value));
|
|
30476
|
+
}
|
|
30477
|
+
function escapeForAppleScript(value) {
|
|
30478
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
30479
|
+
}
|
|
29636
30480
|
async function findFreePort(ports) {
|
|
29637
30481
|
for (const port2 of ports) {
|
|
29638
30482
|
const free = await checkPortFree(port2);
|
|
@@ -29685,12 +30529,12 @@ async function killIdeProcess(ideId) {
|
|
|
29685
30529
|
try {
|
|
29686
30530
|
if (plat === "darwin" && appName) {
|
|
29687
30531
|
try {
|
|
29688
|
-
(0, import_child_process6.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
|
|
30532
|
+
(0, import_child_process6.execSync)(`osascript -e 'tell application "${escapeForAppleScript(appName)}" to quit' 2>/dev/null`, {
|
|
29689
30533
|
timeout: 5e3
|
|
29690
30534
|
});
|
|
29691
30535
|
} catch {
|
|
29692
30536
|
try {
|
|
29693
|
-
(0, import_child_process6.execSync)(`pkill -
|
|
30537
|
+
(0, import_child_process6.execSync)(`pkill -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
|
|
29694
30538
|
} catch {
|
|
29695
30539
|
}
|
|
29696
30540
|
}
|
|
@@ -29720,7 +30564,7 @@ async function killIdeProcess(ideId) {
|
|
|
29720
30564
|
}
|
|
29721
30565
|
if (plat === "darwin" && appName) {
|
|
29722
30566
|
try {
|
|
29723
|
-
(0, import_child_process6.execSync)(`pkill -9 -
|
|
30567
|
+
(0, import_child_process6.execSync)(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
|
|
29724
30568
|
} catch {
|
|
29725
30569
|
}
|
|
29726
30570
|
} else if (plat === "win32" && winProcesses) {
|
|
@@ -29743,8 +30587,23 @@ function isIdeRunning(ideId) {
|
|
|
29743
30587
|
if (plat === "darwin") {
|
|
29744
30588
|
const appName = getMacAppIdentifiers()[ideId];
|
|
29745
30589
|
if (!appName) return false;
|
|
29746
|
-
|
|
29747
|
-
|
|
30590
|
+
try {
|
|
30591
|
+
const result = (0, import_child_process6.execSync)(`pgrep -x "${appName}" 2>/dev/null`, {
|
|
30592
|
+
encoding: "utf-8",
|
|
30593
|
+
timeout: 3e3
|
|
30594
|
+
});
|
|
30595
|
+
return result.trim().length > 0;
|
|
30596
|
+
} catch {
|
|
30597
|
+
const result = (0, import_child_process6.execSync)(
|
|
30598
|
+
`osascript -e 'tell application "System Events" to count (every process whose name is "${escapeForAppleScript(appName)}")'`,
|
|
30599
|
+
{
|
|
30600
|
+
encoding: "utf-8",
|
|
30601
|
+
timeout: 3e3,
|
|
30602
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
30603
|
+
}
|
|
30604
|
+
);
|
|
30605
|
+
return Number.parseInt(result.trim() || "0", 10) > 0;
|
|
30606
|
+
}
|
|
29748
30607
|
} else if (plat === "win32") {
|
|
29749
30608
|
const winProcesses = getWinProcessNames()[ideId];
|
|
29750
30609
|
if (!winProcesses) return false;
|
|
@@ -29893,7 +30752,8 @@ async function launchWithCdp(options = {}) {
|
|
|
29893
30752
|
await launchLinux(targetIde, port, workspace, options.newWindow);
|
|
29894
30753
|
}
|
|
29895
30754
|
let cdpReady = false;
|
|
29896
|
-
|
|
30755
|
+
const waitDeadline = Date.now() + getCdpStartupTimeoutMs(targetIde.id);
|
|
30756
|
+
while (Date.now() < waitDeadline) {
|
|
29897
30757
|
await new Promise((r) => setTimeout(r, 500));
|
|
29898
30758
|
if (await isCdpActive(port)) {
|
|
29899
30759
|
cdpReady = true;
|
|
@@ -29922,14 +30782,18 @@ async function launchWithCdp(options = {}) {
|
|
|
29922
30782
|
}
|
|
29923
30783
|
async function launchMacOS(ide, port, workspace, newWindow) {
|
|
29924
30784
|
const appName = getMacAppIdentifiers()[ide.id];
|
|
30785
|
+
const preferredMethod = getPreferredLaunchMethod(ide.id, "darwin");
|
|
29925
30786
|
const args = ["--remote-debugging-port=" + port];
|
|
29926
30787
|
if (newWindow) args.push("--new-window");
|
|
29927
30788
|
if (workspace) args.push(workspace);
|
|
29928
|
-
|
|
30789
|
+
const canUseCli = !!ide.cliCommand;
|
|
30790
|
+
const canUseAppLauncher = !!appName;
|
|
30791
|
+
const useAppLauncher = preferredMethod === "app" ? canUseAppLauncher : preferredMethod === "cli" ? false : !canUseCli && canUseAppLauncher;
|
|
30792
|
+
if (!useAppLauncher && ide.cliCommand) {
|
|
30793
|
+
(0, import_child_process6.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
|
|
30794
|
+
} else if (appName) {
|
|
29929
30795
|
const openArgs = ["-a", appName, "--args", ...args];
|
|
29930
30796
|
(0, import_child_process6.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
|
|
29931
|
-
} else if (ide.cliCommand) {
|
|
29932
|
-
(0, import_child_process6.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
|
|
29933
30797
|
} else {
|
|
29934
30798
|
throw new Error(`No app identifier or CLI for ${ide.displayName}`);
|
|
29935
30799
|
}
|
|
@@ -30247,6 +31111,7 @@ function buildStatusSnapshot(options) {
|
|
|
30247
31111
|
workspaces: wsState.workspaces,
|
|
30248
31112
|
defaultWorkspaceId: wsState.defaultWorkspaceId,
|
|
30249
31113
|
defaultWorkspacePath: wsState.defaultWorkspacePath,
|
|
31114
|
+
terminalSizingMode: cfg.terminalSizingMode || "measured",
|
|
30250
31115
|
recentLaunches: buildRecentLaunches(recentActivity),
|
|
30251
31116
|
terminalBackend,
|
|
30252
31117
|
availableProviders: buildAvailableProviders(options.providerLoader)
|
|
@@ -31095,6 +31960,7 @@ var ProviderStreamAdapter;
|
|
|
31095
31960
|
var init_provider_adapter = __esm({
|
|
31096
31961
|
"../../oss/packages/daemon-core/src/agent-stream/provider-adapter.ts"() {
|
|
31097
31962
|
"use strict";
|
|
31963
|
+
init_control_effects();
|
|
31098
31964
|
ProviderStreamAdapter = class {
|
|
31099
31965
|
agentType;
|
|
31100
31966
|
agentName;
|
|
@@ -31154,19 +32020,10 @@ var init_provider_adapter = __esm({
|
|
|
31154
32020
|
mode: data.mode,
|
|
31155
32021
|
activeModal: data.activeModal
|
|
31156
32022
|
};
|
|
31157
|
-
|
|
31158
|
-
|
|
31159
|
-
|
|
31160
|
-
|
|
31161
|
-
const val = data[ctrl.readFrom];
|
|
31162
|
-
if (val !== void 0 && val !== null) {
|
|
31163
|
-
cv[ctrl.id] = typeof val === "object" ? val.name || val.id || String(val) : val;
|
|
31164
|
-
}
|
|
31165
|
-
}
|
|
31166
|
-
if (data.model && !cv["model"]) cv["model"] = data.model;
|
|
31167
|
-
if (data.mode && !cv["mode"]) cv["mode"] = data.mode;
|
|
31168
|
-
if (Object.keys(cv).length > 0) state.controlValues = cv;
|
|
31169
|
-
}
|
|
32023
|
+
const controlValues = extractProviderControlValues(this.provider.controls, data);
|
|
32024
|
+
if (controlValues) state.controlValues = controlValues;
|
|
32025
|
+
const effects = normalizeProviderEffects(data);
|
|
32026
|
+
if (effects.length > 0) state.effects = effects;
|
|
31170
32027
|
if (state.messages.length > 0) {
|
|
31171
32028
|
this.lastSuccessState = state;
|
|
31172
32029
|
}
|
|
@@ -31726,6 +32583,8 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
|
|
|
31726
32583
|
activeModal: stream.activeModal || null,
|
|
31727
32584
|
model: stream.model || void 0,
|
|
31728
32585
|
mode: stream.mode || void 0,
|
|
32586
|
+
controlValues: stream.controlValues || void 0,
|
|
32587
|
+
effects: stream.effects || void 0,
|
|
31729
32588
|
sessionId: stream.sessionId || stream.instanceId || void 0,
|
|
31730
32589
|
title: stream.title || stream.agentName || void 0,
|
|
31731
32590
|
agentType: stream.agentType || void 0,
|
|
@@ -46409,7 +47268,7 @@ var init_adhdev_daemon = __esm({
|
|
|
46409
47268
|
import_ws3 = require("ws");
|
|
46410
47269
|
import_chalk2 = __toESM(require("chalk"));
|
|
46411
47270
|
init_version();
|
|
46412
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.
|
|
47271
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.24" });
|
|
46413
47272
|
DANGEROUS_PATTERNS = [
|
|
46414
47273
|
/\brm\s+(-[a-z]*f|-[a-z]*r|--force|--recursive)/i,
|
|
46415
47274
|
/\bsudo\b/i,
|