@adhdev/daemon-standalone 0.9.64 → 0.9.65

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/index.js CHANGED
@@ -28356,681 +28356,165 @@ var require_dist2 = __commonJS({
28356
28356
  LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
28357
28357
  }
28358
28358
  });
28359
- function normalizeInputEnvelope(input) {
28360
- const normalized = normalizeInputEnvelopePayload(input);
28361
- const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
28359
+ function normalizeCategories(categories) {
28360
+ if (!Array.isArray(categories)) return [];
28361
+ return categories.map((category) => String(category || "").trim()).filter(Boolean);
28362
+ }
28363
+ function resolveDebugRuntimeConfig(options = {}) {
28364
+ const dev = options.dev === true;
28362
28365
  return {
28363
- parts: normalized.parts,
28364
- textFallback,
28365
- ...normalized.metadata ? { metadata: normalized.metadata } : {}
28366
+ logLevel: options.logLevel || (dev ? "debug" : DEFAULT_CONFIG2.logLevel),
28367
+ collectDebugTrace: typeof options.trace === "boolean" ? options.trace : dev,
28368
+ traceContent: options.traceContent === true,
28369
+ traceBufferSize: Number.isFinite(options.traceBufferSize) ? Math.max(10, Math.floor(options.traceBufferSize)) : dev ? DEV_TRACE_BUFFER_SIZE : DEFAULT_CONFIG2.traceBufferSize,
28370
+ traceCategories: normalizeCategories(options.traceCategories)
28366
28371
  };
28367
28372
  }
28368
- function normalizeMessageParts(content) {
28369
- if (typeof content === "string") return [{ type: "text", text: content }];
28370
- if (!Array.isArray(content)) {
28371
- if (content && typeof content === "object" && typeof content.text === "string") {
28372
- return [{ type: "text", text: String(content.text) }];
28373
- }
28374
- return [];
28375
- }
28376
- const parts = [];
28377
- for (const raw of content) {
28378
- if (typeof raw === "string") {
28379
- parts.push({ type: "text", text: raw });
28380
- continue;
28381
- }
28382
- if (!raw || typeof raw !== "object") continue;
28383
- const part = normalizeMessagePartObject(raw);
28384
- if (part) parts.push(part);
28385
- }
28386
- return parts;
28373
+ function setDebugRuntimeConfig(config2) {
28374
+ currentConfig = {
28375
+ ...config2,
28376
+ traceCategories: normalizeCategories(config2.traceCategories),
28377
+ traceBufferSize: Math.max(10, Math.floor(config2.traceBufferSize || DEFAULT_CONFIG2.traceBufferSize))
28378
+ };
28387
28379
  }
28388
- function flattenMessageParts(parts) {
28389
- return parts.map((part) => {
28390
- if (part.type === "text") return part.text;
28391
- if (part.type === "resource") return part.resource.text || "";
28392
- return "";
28393
- }).filter((value) => value.length > 0).join("\n");
28380
+ function getDebugRuntimeConfig() {
28381
+ return { ...currentConfig, traceCategories: [...currentConfig.traceCategories] };
28394
28382
  }
28395
- function normalizeInputEnvelopePayload(input) {
28396
- if (typeof input === "string") {
28397
- return { parts: [{ type: "text", text: input }], textFallback: input };
28398
- }
28399
- if (!input || typeof input !== "object") {
28400
- return { parts: [], textFallback: "" };
28401
- }
28402
- const record2 = input;
28403
- const nestedInput = record2.input;
28404
- if (nestedInput && typeof nestedInput === "object") {
28405
- const nested = nestedInput;
28406
- return {
28407
- parts: normalizeInputParts(nested.parts ?? nested.prompt),
28408
- textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
28409
- metadata: normalizeInputMetadata(nested.metadata)
28383
+ function resetDebugRuntimeConfig() {
28384
+ currentConfig = { ...DEFAULT_CONFIG2 };
28385
+ }
28386
+ function shouldCollectTraceCategory(category) {
28387
+ const config2 = currentConfig;
28388
+ if (!config2.collectDebugTrace) return false;
28389
+ if (!category) return true;
28390
+ if (config2.traceCategories.length === 0) return true;
28391
+ return config2.traceCategories.includes(category);
28392
+ }
28393
+ var NORMAL_TRACE_BUFFER_SIZE;
28394
+ var DEV_TRACE_BUFFER_SIZE;
28395
+ var DEFAULT_CONFIG2;
28396
+ var currentConfig;
28397
+ var init_debug_config = __esm2({
28398
+ "src/logging/debug-config.ts"() {
28399
+ "use strict";
28400
+ NORMAL_TRACE_BUFFER_SIZE = 200;
28401
+ DEV_TRACE_BUFFER_SIZE = 1e3;
28402
+ DEFAULT_CONFIG2 = {
28403
+ logLevel: "info",
28404
+ collectDebugTrace: false,
28405
+ traceContent: false,
28406
+ traceBufferSize: NORMAL_TRACE_BUFFER_SIZE,
28407
+ traceCategories: []
28410
28408
  };
28409
+ currentConfig = { ...DEFAULT_CONFIG2 };
28411
28410
  }
28412
- const directText = typeof record2.text === "string" ? record2.text : typeof record2.message === "string" ? record2.message : void 0;
28413
- if (directText !== void 0) {
28414
- return { parts: [{ type: "text", text: directText }], textFallback: directText };
28415
- }
28416
- const directParts = normalizeInputParts(record2.parts ?? record2.prompt);
28417
- return {
28418
- parts: directParts,
28419
- textFallback: typeof record2.textFallback === "string" ? record2.textFallback : void 0,
28420
- metadata: normalizeInputMetadata(record2.metadata)
28421
- };
28411
+ });
28412
+ function isModuleNotFoundError(error48, ref) {
28413
+ if (!(error48 instanceof Error)) return false;
28414
+ const message = error48.message || "";
28415
+ const code = "code" in error48 ? error48.code : void 0;
28416
+ return code === "MODULE_NOT_FOUND" && message.includes(ref);
28422
28417
  }
28423
- function normalizeInputMetadata(value) {
28424
- if (!value || typeof value !== "object") return void 0;
28425
- const record2 = value;
28426
- const metadata = {};
28427
- if (record2.source === "dashboard" || record2.source === "shortcut_api" || record2.source === "provider_script" || record2.source === "session_replay") {
28428
- metadata.source = record2.source;
28429
- }
28430
- if (typeof record2.clientTimestamp === "number" && Number.isFinite(record2.clientTimestamp)) {
28431
- metadata.clientTimestamp = record2.clientTimestamp;
28418
+ function normalizeBinding(mod, ref) {
28419
+ const binding = mod?.default?.createTerminal ? mod.default : mod?.createTerminal ? mod : null;
28420
+ if (!binding) {
28421
+ throw new Error(`Ghostty VT binding "${ref}" does not export createTerminal()`);
28432
28422
  }
28433
- return Object.keys(metadata).length > 0 ? metadata : void 0;
28423
+ return binding;
28434
28424
  }
28435
- function normalizeInputParts(value) {
28436
- if (!Array.isArray(value)) return [];
28437
- const parts = [];
28438
- for (const raw of value) {
28439
- if (typeof raw === "string") {
28440
- parts.push({ type: "text", text: raw });
28441
- continue;
28442
- }
28443
- if (!raw || typeof raw !== "object") continue;
28444
- const part = normalizeInputPartObject(raw);
28445
- if (part) parts.push(part);
28446
- }
28447
- return parts;
28425
+ function getBindingCandidates() {
28426
+ const explicit = process.env.ADHDEV_GHOSTTY_VT_BINDING?.trim();
28427
+ return explicit ? [explicit] : DEFAULT_BINDING_CANDIDATES;
28448
28428
  }
28449
- function normalizeInputPartObject(raw) {
28450
- const type = raw.type;
28451
- if (type === "text" && typeof raw.text === "string") {
28452
- return { type, text: raw.text };
28429
+ function loadGhosttyVtBinding(required2) {
28430
+ if (cachedBinding !== void 0) {
28431
+ if (!cachedBinding && required2 && cachedBindingError) {
28432
+ throw cachedBindingError;
28433
+ }
28434
+ return cachedBinding;
28453
28435
  }
28454
- if (type === "image" && typeof raw.mimeType === "string") {
28455
- return {
28456
- type,
28457
- mimeType: raw.mimeType,
28458
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
28459
- ...typeof raw.data === "string" ? { data: raw.data } : {},
28460
- ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
28461
- };
28436
+ const errors = [];
28437
+ for (const ref of getBindingCandidates()) {
28438
+ try {
28439
+ const mod = require(ref);
28440
+ cachedBinding = normalizeBinding(mod, ref);
28441
+ cachedBindingError = null;
28442
+ return cachedBinding;
28443
+ } catch (error48) {
28444
+ if (isModuleNotFoundError(error48, ref)) {
28445
+ errors.push(`${ref}: module not found`);
28446
+ continue;
28447
+ }
28448
+ const message = error48 instanceof Error ? error48.message : String(error48);
28449
+ errors.push(`${ref}: ${message}`);
28450
+ }
28462
28451
  }
28463
- if (type === "audio" && typeof raw.mimeType === "string") {
28464
- return {
28465
- type,
28466
- mimeType: raw.mimeType,
28467
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
28468
- ...typeof raw.data === "string" ? { data: raw.data } : {},
28469
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
28452
+ cachedBinding = null;
28453
+ cachedBindingError = new Error(
28454
+ `ghostty-vt backend requested but no binding is available (${errors.join("; ") || "no candidates tried"})`
28455
+ );
28456
+ if (required2) throw cachedBindingError;
28457
+ return null;
28458
+ }
28459
+ function resolveTerminalBackendPreference() {
28460
+ const raw = process.env.ADHDEV_TERMINAL_BACKEND?.trim().toLowerCase();
28461
+ if (raw === "ghostty-vt" || raw === "xterm" || raw === "auto") return raw;
28462
+ return "auto";
28463
+ }
28464
+ function isGhosttyVtBackendAvailable() {
28465
+ return !!loadGhosttyVtBinding(false);
28466
+ }
28467
+ var DEFAULT_BINDING_CANDIDATES;
28468
+ var cachedBinding;
28469
+ var cachedBindingError;
28470
+ var GhosttyVtTerminalBackend;
28471
+ var init_ghostty_vt_backend = __esm2({
28472
+ "src/cli-adapters/terminal-backends/ghostty-vt-backend.ts"() {
28473
+ "use strict";
28474
+ DEFAULT_BINDING_CANDIDATES = [
28475
+ "@adhdev/ghostty-vt-node"
28476
+ ];
28477
+ cachedBindingError = null;
28478
+ GhosttyVtTerminalBackend = class {
28479
+ kind = "ghostty-vt";
28480
+ terminal;
28481
+ constructor(options) {
28482
+ const binding = loadGhosttyVtBinding(true);
28483
+ if (!binding) {
28484
+ throw new Error("ghostty-vt backend requested but no binding is available");
28485
+ }
28486
+ this.terminal = binding.createTerminal({
28487
+ cols: Math.max(1, options.cols | 0),
28488
+ rows: Math.max(1, options.rows | 0),
28489
+ scrollback: Math.max(0, options.scrollback | 0)
28490
+ });
28491
+ }
28492
+ resize(rows, cols) {
28493
+ this.terminal.resize(Math.max(1, cols | 0), Math.max(1, rows | 0));
28494
+ }
28495
+ write(data) {
28496
+ if (!data) return;
28497
+ this.terminal.write(data);
28498
+ }
28499
+ getText() {
28500
+ return this.terminal.formatPlainText({ trim: true }) || "";
28501
+ }
28502
+ getCursorPosition() {
28503
+ return this.terminal.getCursorPosition();
28504
+ }
28505
+ dispose() {
28506
+ this.terminal.dispose();
28507
+ }
28470
28508
  };
28471
28509
  }
28472
- if (type === "video" && typeof raw.mimeType === "string") {
28473
- return {
28474
- type,
28475
- mimeType: raw.mimeType,
28476
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
28477
- ...typeof raw.data === "string" ? { data: raw.data } : {},
28478
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
28479
- };
28480
- }
28481
- if (type === "resource" && typeof raw.uri === "string") {
28482
- return {
28483
- type,
28484
- uri: raw.uri,
28485
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
28486
- ...typeof raw.name === "string" ? { name: raw.name } : {},
28487
- ...typeof raw.text === "string" ? { text: raw.text } : {},
28488
- ...typeof raw.data === "string" ? { data: raw.data } : {}
28489
- };
28490
- }
28491
- if (type === "resource_link" && typeof raw.uri === "string") {
28492
- return {
28493
- type: "resource",
28494
- uri: raw.uri,
28495
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
28496
- ...typeof raw.name === "string" ? { name: raw.name } : {}
28497
- };
28498
- }
28499
- return null;
28500
- }
28501
- function normalizeMessagePartObject(raw) {
28502
- const type = raw.type;
28503
- if (type === "text" && typeof raw.text === "string") {
28504
- return { type, text: raw.text };
28505
- }
28506
- if (type === "image" && typeof raw.mimeType === "string") {
28507
- return {
28508
- type,
28509
- mimeType: raw.mimeType,
28510
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
28511
- ...typeof raw.data === "string" ? { data: raw.data } : {}
28512
- };
28513
- }
28514
- if (type === "audio" && typeof raw.mimeType === "string") {
28515
- return {
28516
- type,
28517
- mimeType: raw.mimeType,
28518
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
28519
- ...typeof raw.data === "string" ? { data: raw.data } : {},
28520
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
28521
- };
28522
- }
28523
- if (type === "video" && typeof raw.mimeType === "string") {
28524
- return {
28525
- type,
28526
- mimeType: raw.mimeType,
28527
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
28528
- ...typeof raw.data === "string" ? { data: raw.data } : {},
28529
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
28530
- };
28531
- }
28532
- if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
28533
- return {
28534
- type,
28535
- uri: raw.uri,
28536
- name: raw.name,
28537
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
28538
- ...typeof raw.size === "number" ? { size: raw.size } : {}
28539
- };
28540
- }
28541
- if (type === "resource" && raw.resource && typeof raw.resource === "object") {
28542
- const resource = raw.resource;
28543
- if (typeof resource.uri !== "string") return null;
28544
- return {
28545
- type,
28546
- resource: {
28547
- uri: resource.uri,
28548
- ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
28549
- ...typeof resource.text === "string" ? { text: resource.text } : {},
28550
- ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
28551
- }
28552
- };
28553
- }
28554
- return null;
28555
- }
28556
- function flattenInputParts(parts) {
28557
- return parts.map((part) => {
28558
- if (part.type === "text") return part.text;
28559
- if (part.type === "audio") return part.transcript || "";
28560
- if (part.type === "resource") return part.text || "";
28561
- return "";
28562
- }).filter((value) => value.length > 0).join("\n");
28563
- }
28564
- var init_io_contracts = __esm2({
28565
- "src/providers/io-contracts.ts"() {
28566
- "use strict";
28567
- }
28568
- });
28569
- function flattenContent(content) {
28570
- if (typeof content === "string") return content;
28571
- return flattenMessageParts(normalizeMessageParts(content));
28572
- }
28573
- var init_contracts = __esm2({
28574
- "src/providers/contracts.ts"() {
28575
- "use strict";
28576
- init_io_contracts();
28577
- init_io_contracts();
28578
- }
28579
- });
28580
- function canonicalizeKindHint(value) {
28581
- return value.trim().toLowerCase().replace(/[\s-]+/g, "_");
28582
- }
28583
- function resolveBuiltinOrAliasKind(kind) {
28584
- if (typeof kind !== "string") return null;
28585
- const normalizedKind = canonicalizeKindHint(kind);
28586
- if (!normalizedKind) return null;
28587
- if (KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
28588
- return CHAT_MESSAGE_KIND_ALIASES[normalizedKind] || null;
28589
- }
28590
- function inferHintKind(value) {
28591
- const direct = resolveBuiltinOrAliasKind(value);
28592
- if (direct) return direct;
28593
- if (typeof value !== "string") return null;
28594
- const normalized = canonicalizeKindHint(value);
28595
- if (!normalized) return null;
28596
- if (/thought|thinking|reasoning/.test(normalized)) return "thought";
28597
- if (/tool/.test(normalized)) return "tool";
28598
- if (/terminal|command|shell|console/.test(normalized)) return "terminal";
28599
- return null;
28600
- }
28601
- function inferKindFromToolCalls(message) {
28602
- const toolCalls = Array.isArray(message?.toolCalls) ? message.toolCalls : [];
28603
- if (toolCalls.length === 0) return null;
28604
- if (toolCalls.some((toolCall) => toolCall?.kind === "think")) return "thought";
28605
- if (toolCalls.some((toolCall) => toolCall?.kind === "execute")) return "terminal";
28606
- if (toolCalls.some((toolCall) => Array.isArray(toolCall?.content) && toolCall.content.some((entry) => entry?.type === "terminal"))) {
28607
- return "terminal";
28608
- }
28609
- return "tool";
28610
- }
28611
- function inferMissingChatMessageKind(message) {
28612
- const role = typeof message?.role === "string" ? message.role.trim().toLowerCase() : "";
28613
- if (role === "system") return "system";
28614
- const meta3 = message?.meta && typeof message.meta === "object" ? message.meta : void 0;
28615
- const hintCandidates = [
28616
- message?._sub,
28617
- message?._type,
28618
- meta3?.label,
28619
- typeof message?.senderName === "string" ? message.senderName : void 0
28620
- ];
28621
- for (const candidate of hintCandidates) {
28622
- const inferred = inferHintKind(candidate);
28623
- if (inferred) return inferred;
28624
- }
28625
- const inferredFromToolCalls = inferKindFromToolCalls(message);
28626
- if (inferredFromToolCalls) return inferredFromToolCalls;
28627
- return null;
28628
- }
28629
- function isBuiltinChatMessageKind(kind) {
28630
- return resolveBuiltinOrAliasKind(kind) !== null;
28631
- }
28632
- function normalizeChatMessageKind(kind, role) {
28633
- const resolvedKind = resolveBuiltinOrAliasKind(kind);
28634
- if (resolvedKind) return resolvedKind;
28635
- const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
28636
- return normalizedRole === "system" ? "system" : "standard";
28637
- }
28638
- function resolveChatMessageKind(message) {
28639
- const explicitKind = resolveBuiltinOrAliasKind(message?.kind);
28640
- if (explicitKind) return explicitKind;
28641
- const inferredKind = inferMissingChatMessageKind(message);
28642
- if (inferredKind) return inferredKind;
28643
- return normalizeChatMessageKind(message?.kind, message?.role);
28644
- }
28645
- function buildChatMessage(message) {
28646
- return {
28647
- ...message,
28648
- kind: resolveChatMessageKind(message)
28649
- };
28650
- }
28651
- function buildSystemChatMessage(message) {
28652
- return buildChatMessage({
28653
- ...message,
28654
- role: "system",
28655
- kind: message?.kind || "system"
28656
- });
28657
- }
28658
- function buildRuntimeSystemChatMessage(message) {
28659
- return buildSystemChatMessage({
28660
- ...message,
28661
- senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
28662
- });
28663
- }
28664
- function buildAssistantChatMessage(message) {
28665
- return buildChatMessage({
28666
- ...message,
28667
- role: "assistant",
28668
- kind: message?.kind || "standard"
28669
- });
28670
- }
28671
- function buildThoughtChatMessage(message) {
28672
- return buildAssistantChatMessage({
28673
- ...message,
28674
- kind: message?.kind || "thought"
28675
- });
28676
- }
28677
- function buildToolChatMessage(message) {
28678
- return buildAssistantChatMessage({
28679
- ...message,
28680
- kind: message?.kind || "tool"
28681
- });
28682
- }
28683
- function buildTerminalChatMessage(message) {
28684
- return buildAssistantChatMessage({
28685
- ...message,
28686
- kind: message?.kind || "terminal"
28687
- });
28688
- }
28689
- function buildUserChatMessage(message) {
28690
- return buildChatMessage({
28691
- ...message,
28692
- role: "user",
28693
- kind: message?.kind || "standard"
28694
- });
28695
- }
28696
- function normalizeChatMessage(message) {
28697
- return buildChatMessage(message);
28698
- }
28699
- function normalizeChatMessages(messages) {
28700
- return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
28701
- }
28702
- var BUILTIN_CHAT_MESSAGE_KINDS;
28703
- var KNOWN_CHAT_MESSAGE_KINDS;
28704
- var CHAT_MESSAGE_KIND_ALIASES;
28705
- var init_chat_message_normalization = __esm2({
28706
- "src/providers/chat-message-normalization.ts"() {
28707
- "use strict";
28708
- BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
28709
- KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
28710
- CHAT_MESSAGE_KIND_ALIASES = {
28711
- text: "standard",
28712
- message: "standard",
28713
- assistant: "standard",
28714
- thinking: "thought",
28715
- think: "thought",
28716
- reasoning: "thought",
28717
- reason: "thought",
28718
- toolcall: "tool",
28719
- tool_call: "tool",
28720
- tooluse: "tool",
28721
- tool_use: "tool",
28722
- action: "tool",
28723
- command: "terminal",
28724
- cmd: "terminal",
28725
- shell: "terminal",
28726
- console: "terminal"
28727
- };
28728
- }
28729
- });
28730
- function isPlainObject3(value) {
28731
- return !!value && typeof value === "object" && !Array.isArray(value);
28732
- }
28733
- function isFiniteNumber(value) {
28734
- return typeof value === "number" && Number.isFinite(value);
28735
- }
28736
- function validateStatus(status, source) {
28737
- if (typeof status !== "string" || !VALID_STATUSES.includes(status)) {
28738
- throw new Error(`${source}: status must be one of ${VALID_STATUSES.join(", ")}`);
28739
- }
28740
- return status;
28741
- }
28742
- function validateRole(role, source, index) {
28743
- if (typeof role !== "string" || !VALID_ROLES.includes(role)) {
28744
- throw new Error(`${source}: messages[${index}].role must be one of ${VALID_ROLES.join(", ")}`);
28745
- }
28746
- return role;
28747
- }
28748
- function validateBubbleState(state, source, index) {
28749
- if (typeof state !== "string" || !VALID_BUBBLE_STATES.includes(state)) {
28750
- throw new Error(`${source}: messages[${index}].bubbleState must be one of ${VALID_BUBBLE_STATES.join(", ")}`);
28751
- }
28752
- return state;
28753
- }
28754
- function validateTurnStatus(turnStatus, source) {
28755
- if (typeof turnStatus !== "string" || !VALID_TURN_STATUSES.includes(turnStatus)) {
28756
- throw new Error(`${source}: turnStatus must be one of ${VALID_TURN_STATUSES.join(", ")}`);
28757
- }
28758
- return turnStatus;
28759
- }
28760
- function validateMessageContent(content, source, index) {
28761
- if (typeof content === "string") return content;
28762
- if (Array.isArray(content)) return normalizeMessageParts(content);
28763
- throw new Error(`${source}: messages[${index}].content must be a string or structured content array`);
28764
- }
28765
- function validateMessage(message, source, index) {
28766
- if (!isPlainObject3(message)) {
28767
- throw new Error(`${source}: messages[${index}] must be an object`);
28768
- }
28769
- const normalized = {
28770
- role: validateRole(message.role, source, index),
28771
- content: validateMessageContent(message.content, source, index)
28772
- };
28773
- if (typeof message.kind === "string") normalized.kind = message.kind;
28774
- if (typeof message.id === "string") normalized.id = message.id;
28775
- if (typeof message.bubbleId === "string") normalized.bubbleId = message.bubbleId;
28776
- if (typeof message.providerUnitKey === "string") normalized.providerUnitKey = message.providerUnitKey;
28777
- if (message.bubbleState !== void 0) normalized.bubbleState = validateBubbleState(message.bubbleState, source, index);
28778
- if (isFiniteNumber(message.index)) normalized.index = message.index;
28779
- if (isFiniteNumber(message.timestamp)) normalized.timestamp = message.timestamp;
28780
- if (isFiniteNumber(message.receivedAt)) normalized.receivedAt = message.receivedAt;
28781
- if (typeof message._turnKey === "string") normalized._turnKey = message._turnKey;
28782
- if (Array.isArray(message.toolCalls)) normalized.toolCalls = message.toolCalls;
28783
- if (isPlainObject3(message.meta)) normalized.meta = message.meta;
28784
- if (typeof message.senderName === "string") normalized.senderName = message.senderName;
28785
- if (typeof message._type === "string") normalized._type = message._type;
28786
- if (typeof message._sub === "string") normalized._sub = message._sub;
28787
- return normalized;
28788
- }
28789
- function validateModal(activeModal, status, source) {
28790
- if (activeModal == null) {
28791
- if (status === "waiting_approval") {
28792
- throw new Error(`${source}: waiting_approval status requires activeModal with buttons`);
28793
- }
28794
- return activeModal === null ? null : void 0;
28795
- }
28796
- if (!isPlainObject3(activeModal)) {
28797
- throw new Error(`${source}: activeModal must be an object when provided`);
28798
- }
28799
- if (typeof activeModal.message !== "string") {
28800
- throw new Error(`${source}: activeModal.message must be a string`);
28801
- }
28802
- if (!Array.isArray(activeModal.buttons) || activeModal.buttons.some((button) => typeof button !== "string" || !button.trim())) {
28803
- throw new Error(`${source}: activeModal.buttons must be a non-empty string array`);
28804
- }
28805
- const normalized = {
28806
- message: activeModal.message,
28807
- buttons: activeModal.buttons.map((button) => button.trim())
28808
- };
28809
- if (isFiniteNumber(activeModal.width)) normalized.width = activeModal.width;
28810
- if (isFiniteNumber(activeModal.height)) normalized.height = activeModal.height;
28811
- return normalized;
28812
- }
28813
- function validateControlValues(controlValues, source) {
28814
- if (controlValues === void 0) return void 0;
28815
- if (!isPlainObject3(controlValues)) {
28816
- throw new Error(`${source}: controlValues must be an object when provided`);
28817
- }
28818
- const normalized = {};
28819
- for (const [key, value] of Object.entries(controlValues)) {
28820
- if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
28821
- throw new Error(`${source}: controlValues.${key} must be string, number, or boolean`);
28822
- }
28823
- normalized[key] = value;
28824
- }
28825
- return normalized;
28826
- }
28827
- function validateReadChatResultPayload(raw, source = "read_chat") {
28828
- if (!isPlainObject3(raw)) {
28829
- throw new Error(`${source}: payload must be an object`);
28830
- }
28831
- const status = validateStatus(raw.status, source);
28832
- if (!Array.isArray(raw.messages)) {
28833
- throw new Error(`${source}: messages must be an array`);
28834
- }
28835
- const messages = raw.messages.map((message, index) => validateMessage(message, source, index));
28836
- const activeModal = validateModal(raw.activeModal, status, source);
28837
- const controlValues = validateControlValues(raw.controlValues, source);
28838
- const normalized = {
28839
- status,
28840
- messages
28841
- };
28842
- if (activeModal !== void 0) normalized.activeModal = activeModal;
28843
- if (typeof raw.id === "string") normalized.id = raw.id;
28844
- if (typeof raw.title === "string") normalized.title = raw.title;
28845
- if (typeof raw.currentTurnId === "string") normalized.currentTurnId = raw.currentTurnId;
28846
- if (raw.turnStatus !== void 0) normalized.turnStatus = validateTurnStatus(raw.turnStatus, source);
28847
- if (typeof raw.agentType === "string") normalized.agentType = raw.agentType;
28848
- if (typeof raw.agentName === "string") normalized.agentName = raw.agentName;
28849
- if (typeof raw.extensionId === "string") normalized.extensionId = raw.extensionId;
28850
- if (typeof raw.inputContent === "string") normalized.inputContent = raw.inputContent;
28851
- if (typeof raw.isVisible === "boolean") normalized.isVisible = raw.isVisible;
28852
- if (typeof raw.isWelcomeScreen === "boolean") normalized.isWelcomeScreen = raw.isWelcomeScreen;
28853
- if (controlValues) normalized.controlValues = controlValues;
28854
- if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
28855
- if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
28856
- if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
28857
- if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
28858
- if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
28859
- return normalized;
28860
- }
28861
- var VALID_STATUSES;
28862
- var VALID_ROLES;
28863
- var VALID_BUBBLE_STATES;
28864
- var VALID_TURN_STATUSES;
28865
- var init_read_chat_contract = __esm2({
28866
- "src/providers/read-chat-contract.ts"() {
28867
- "use strict";
28868
- init_contracts();
28869
- VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "streaming", "long_generating"];
28870
- VALID_ROLES = ["user", "assistant", "system", "human"];
28871
- VALID_BUBBLE_STATES = ["draft", "streaming", "final", "removed"];
28872
- VALID_TURN_STATUSES = ["open", "waiting_approval", "complete", "error"];
28873
- }
28874
- });
28875
- function normalizeCategories(categories) {
28876
- if (!Array.isArray(categories)) return [];
28877
- return categories.map((category) => String(category || "").trim()).filter(Boolean);
28878
- }
28879
- function resolveDebugRuntimeConfig(options = {}) {
28880
- const dev = options.dev === true;
28881
- return {
28882
- logLevel: options.logLevel || (dev ? "debug" : DEFAULT_CONFIG2.logLevel),
28883
- collectDebugTrace: typeof options.trace === "boolean" ? options.trace : dev,
28884
- traceContent: options.traceContent === true,
28885
- traceBufferSize: Number.isFinite(options.traceBufferSize) ? Math.max(10, Math.floor(options.traceBufferSize)) : dev ? DEV_TRACE_BUFFER_SIZE : DEFAULT_CONFIG2.traceBufferSize,
28886
- traceCategories: normalizeCategories(options.traceCategories)
28887
- };
28888
- }
28889
- function setDebugRuntimeConfig(config2) {
28890
- currentConfig = {
28891
- ...config2,
28892
- traceCategories: normalizeCategories(config2.traceCategories),
28893
- traceBufferSize: Math.max(10, Math.floor(config2.traceBufferSize || DEFAULT_CONFIG2.traceBufferSize))
28894
- };
28895
- }
28896
- function getDebugRuntimeConfig() {
28897
- return { ...currentConfig, traceCategories: [...currentConfig.traceCategories] };
28898
- }
28899
- function resetDebugRuntimeConfig() {
28900
- currentConfig = { ...DEFAULT_CONFIG2 };
28901
- }
28902
- function shouldCollectTraceCategory(category) {
28903
- const config2 = currentConfig;
28904
- if (!config2.collectDebugTrace) return false;
28905
- if (!category) return true;
28906
- if (config2.traceCategories.length === 0) return true;
28907
- return config2.traceCategories.includes(category);
28908
- }
28909
- var NORMAL_TRACE_BUFFER_SIZE;
28910
- var DEV_TRACE_BUFFER_SIZE;
28911
- var DEFAULT_CONFIG2;
28912
- var currentConfig;
28913
- var init_debug_config = __esm2({
28914
- "src/logging/debug-config.ts"() {
28915
- "use strict";
28916
- NORMAL_TRACE_BUFFER_SIZE = 200;
28917
- DEV_TRACE_BUFFER_SIZE = 1e3;
28918
- DEFAULT_CONFIG2 = {
28919
- logLevel: "info",
28920
- collectDebugTrace: false,
28921
- traceContent: false,
28922
- traceBufferSize: NORMAL_TRACE_BUFFER_SIZE,
28923
- traceCategories: []
28924
- };
28925
- currentConfig = { ...DEFAULT_CONFIG2 };
28926
- }
28927
- });
28928
- function isModuleNotFoundError(error48, ref) {
28929
- if (!(error48 instanceof Error)) return false;
28930
- const message = error48.message || "";
28931
- const code = "code" in error48 ? error48.code : void 0;
28932
- return code === "MODULE_NOT_FOUND" && message.includes(ref);
28933
- }
28934
- function normalizeBinding(mod, ref) {
28935
- const binding = mod?.default?.createTerminal ? mod.default : mod?.createTerminal ? mod : null;
28936
- if (!binding) {
28937
- throw new Error(`Ghostty VT binding "${ref}" does not export createTerminal()`);
28938
- }
28939
- return binding;
28940
- }
28941
- function getBindingCandidates() {
28942
- const explicit = process.env.ADHDEV_GHOSTTY_VT_BINDING?.trim();
28943
- return explicit ? [explicit] : DEFAULT_BINDING_CANDIDATES;
28944
- }
28945
- function loadGhosttyVtBinding(required2) {
28946
- if (cachedBinding !== void 0) {
28947
- if (!cachedBinding && required2 && cachedBindingError) {
28948
- throw cachedBindingError;
28949
- }
28950
- return cachedBinding;
28951
- }
28952
- const errors = [];
28953
- for (const ref of getBindingCandidates()) {
28954
- try {
28955
- const mod = require(ref);
28956
- cachedBinding = normalizeBinding(mod, ref);
28957
- cachedBindingError = null;
28958
- return cachedBinding;
28959
- } catch (error48) {
28960
- if (isModuleNotFoundError(error48, ref)) {
28961
- errors.push(`${ref}: module not found`);
28962
- continue;
28963
- }
28964
- const message = error48 instanceof Error ? error48.message : String(error48);
28965
- errors.push(`${ref}: ${message}`);
28966
- }
28967
- }
28968
- cachedBinding = null;
28969
- cachedBindingError = new Error(
28970
- `ghostty-vt backend requested but no binding is available (${errors.join("; ") || "no candidates tried"})`
28971
- );
28972
- if (required2) throw cachedBindingError;
28973
- return null;
28974
- }
28975
- function resolveTerminalBackendPreference() {
28976
- const raw = process.env.ADHDEV_TERMINAL_BACKEND?.trim().toLowerCase();
28977
- if (raw === "ghostty-vt" || raw === "xterm" || raw === "auto") return raw;
28978
- return "auto";
28979
- }
28980
- function isGhosttyVtBackendAvailable() {
28981
- return !!loadGhosttyVtBinding(false);
28982
- }
28983
- var DEFAULT_BINDING_CANDIDATES;
28984
- var cachedBinding;
28985
- var cachedBindingError;
28986
- var GhosttyVtTerminalBackend;
28987
- var init_ghostty_vt_backend = __esm2({
28988
- "src/cli-adapters/terminal-backends/ghostty-vt-backend.ts"() {
28989
- "use strict";
28990
- DEFAULT_BINDING_CANDIDATES = [
28991
- "@adhdev/ghostty-vt-node"
28992
- ];
28993
- cachedBindingError = null;
28994
- GhosttyVtTerminalBackend = class {
28995
- kind = "ghostty-vt";
28996
- terminal;
28997
- constructor(options) {
28998
- const binding = loadGhosttyVtBinding(true);
28999
- if (!binding) {
29000
- throw new Error("ghostty-vt backend requested but no binding is available");
29001
- }
29002
- this.terminal = binding.createTerminal({
29003
- cols: Math.max(1, options.cols | 0),
29004
- rows: Math.max(1, options.rows | 0),
29005
- scrollback: Math.max(0, options.scrollback | 0)
29006
- });
29007
- }
29008
- resize(rows, cols) {
29009
- this.terminal.resize(Math.max(1, cols | 0), Math.max(1, rows | 0));
29010
- }
29011
- write(data) {
29012
- if (!data) return;
29013
- this.terminal.write(data);
29014
- }
29015
- getText() {
29016
- return this.terminal.formatPlainText({ trim: true }) || "";
29017
- }
29018
- getCursorPosition() {
29019
- return this.terminal.getCursorPosition();
29020
- }
29021
- dispose() {
29022
- this.terminal.dispose();
29023
- }
29024
- };
29025
- }
29026
- });
29027
- function loadTerminalCtor() {
29028
- if (!TerminalCtor) {
29029
- const mod = (init_xterm(), __toCommonJS(xterm_exports));
29030
- TerminalCtor = mod.Terminal || mod.default?.Terminal || mod.default;
29031
- if (!TerminalCtor) {
29032
- throw new Error("@xterm/xterm Terminal export not found");
29033
- }
28510
+ });
28511
+ function loadTerminalCtor() {
28512
+ if (!TerminalCtor) {
28513
+ const mod = (init_xterm(), __toCommonJS(xterm_exports));
28514
+ TerminalCtor = mod.Terminal || mod.default?.Terminal || mod.default;
28515
+ if (!TerminalCtor) {
28516
+ throw new Error("@xterm/xterm Terminal export not found");
28517
+ }
29034
28518
  }
29035
28519
  return TerminalCtor;
29036
28520
  }
@@ -29427,71 +28911,10 @@ var require_dist2 = __commonJS({
29427
28911
  const matched = tokens.filter(
29428
28912
  (token) => normalizedScreen.includes(token) || compactScreen.includes(compactPromptText(token))
29429
28913
  ).length;
29430
- return matched >= required2;
29431
- }
29432
- function normalizeScreenSnapshot(text) {
29433
- return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
29434
- }
29435
- function shouldReflowComparableMessageLines(lines) {
29436
- return Array.isArray(lines) && lines.length > 1 && lines.slice(0, -1).every((line) => String(line || "").trim().length >= 48) && !lines.some((line) => /^```/.test(line)) && !lines.some((line) => /^\|/.test(line)) && !lines.some((line) => /^\s*(?:[-*+] |\d+\.\s)/.test(line));
29437
- }
29438
- function joinComparableMessageLines(lines) {
29439
- return lines.reduce((acc, line) => {
29440
- const next = String(line || "").trim();
29441
- if (!next) return acc;
29442
- if (!acc) return next;
29443
- if (/[,\d]$/.test(acc) && /^\d/.test(next)) {
29444
- return `${acc}${next}`;
29445
- }
29446
- if (/[A-Za-z]$/.test(acc) && /^\d/.test(next)) {
29447
- return `${acc}${next}`;
29448
- }
29449
- const fragmentMatch = acc.match(/([A-Za-z]{1,4})$/);
29450
- const fragment = fragmentMatch ? fragmentMatch[1].toLowerCase() : "";
29451
- if (/^[a-z]/.test(next) && fragment && !COMMON_COMPARABLE_WRAP_WORDS.has(fragment)) {
29452
- return `${acc}${next}`;
29453
- }
29454
- return `${acc} ${next}`;
29455
- }, "").replace(/\s+([,.;:!?])/g, "$1").replace(/(\d)\s+,/g, "$1,").replace(/\s+/g, " ").trim();
29456
- }
29457
- function normalizeComparableMessageContent(text) {
29458
- const lines = String(text || "").split(/\r\n|\n|\r/g).map((line) => line.trim()).filter(Boolean);
29459
- if (lines.length === 0) return "";
29460
- if (shouldReflowComparableMessageLines(lines)) {
29461
- return joinComparableMessageLines(lines);
29462
- }
29463
- return lines.join(" ").replace(/\s+/g, " ").trim();
29464
- }
29465
- function trimPromptEchoPrefix(text, promptText) {
29466
- const prompt = normalizeComparableMessageContent(String(promptText || ""));
29467
- if (!prompt) return String(text || "");
29468
- const lines = String(text || "").split(/\r\n|\n|\r/g);
29469
- let dropCount = 0;
29470
- for (let index = 0; index < Math.min(lines.length, 6); index += 1) {
29471
- const fragment = normalizeComparableMessageContent(lines[index].replace(/^[.…]+\s*/, ""));
29472
- if (!fragment) {
29473
- if (dropCount === index) dropCount = index + 1;
29474
- continue;
29475
- }
29476
- const fragmentWordCount = fragment ? fragment.split(/\s+/).filter(Boolean).length : 0;
29477
- const canBePromptEcho = fragment.length >= 16 || fragmentWordCount >= 4;
29478
- if (canBePromptEcho && prompt.includes(fragment)) {
29479
- dropCount = index + 1;
29480
- continue;
29481
- }
29482
- break;
29483
- }
29484
- return lines.slice(dropCount).join("\n").trim();
28914
+ return matched >= required2;
29485
28915
  }
29486
- function getLastUserPromptText(messages) {
29487
- const items = Array.isArray(messages) ? messages : [];
29488
- for (let index = items.length - 1; index >= 0; index -= 1) {
29489
- const message = items[index];
29490
- if (message?.role === "user" && typeof message.content === "string" && message.content.trim()) {
29491
- return message.content;
29492
- }
29493
- }
29494
- return "";
28916
+ function normalizeScreenSnapshot(text) {
28917
+ return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
29495
28918
  }
29496
28919
  function parsePatternEntry(x) {
29497
28920
  if (x instanceof RegExp) return x;
@@ -29523,7 +28946,6 @@ var require_dist2 = __commonJS({
29523
28946
  var path13;
29524
28947
  var import_child_process4;
29525
28948
  var buildCliSpawnEnv;
29526
- var COMMON_COMPARABLE_WRAP_WORDS;
29527
28949
  var init_provider_cli_shared = __esm2({
29528
28950
  "src/cli-adapters/provider-cli-shared.ts"() {
29529
28951
  "use strict";
@@ -29532,32 +28954,6 @@ var require_dist2 = __commonJS({
29532
28954
  import_child_process4 = require("child_process");
29533
28955
  init_spawn_env();
29534
28956
  buildCliSpawnEnv = import_session_host_core3.sanitizeSpawnEnv;
29535
- COMMON_COMPARABLE_WRAP_WORDS = /* @__PURE__ */ new Set([
29536
- "a",
29537
- "an",
29538
- "and",
29539
- "as",
29540
- "at",
29541
- "but",
29542
- "by",
29543
- "for",
29544
- "from",
29545
- "in",
29546
- "into",
29547
- "is",
29548
- "it",
29549
- "of",
29550
- "on",
29551
- "or",
29552
- "that",
29553
- "the",
29554
- "their",
29555
- "then",
29556
- "this",
29557
- "to",
29558
- "was",
29559
- "with"
29560
- ]);
29561
28957
  }
29562
28958
  });
29563
28959
  function sliceFromOffset(text, start) {
@@ -29566,169 +28962,8 @@ var require_dist2 = __commonJS({
29566
28962
  if (start >= text.length) return "";
29567
28963
  return text.slice(start);
29568
28964
  }
29569
- function hydrateCliParsedMessages(parsedMessages, options) {
29570
- const { committedMessages, scope, lastOutputAt } = options;
29571
- const referenceMessages = [...committedMessages];
29572
- const referenceComparables = new Array(referenceMessages.length);
29573
- const usedReferenceIndexes = /* @__PURE__ */ new Set();
29574
- const now = options.now ?? Date.now();
29575
- let exactReferenceIndexesByKey = null;
29576
- const exactReferenceCursorByKey = /* @__PURE__ */ new Map();
29577
- const hasFiniteTimestamp = (message) => typeof message?.timestamp === "number" && Number.isFinite(message.timestamp);
29578
- const getReferenceComparable = (index) => {
29579
- if (typeof referenceComparables[index] === "string") return referenceComparables[index] || "";
29580
- const comparable = normalizeComparableMessageContent(referenceMessages[index]?.content || "");
29581
- referenceComparables[index] = comparable;
29582
- return comparable;
29583
- };
29584
- const messagesShareStableIdentity = (parsed, reference) => {
29585
- if (!parsed || !reference) return false;
29586
- const parsedId = typeof parsed.id === "string" ? parsed.id.trim() : "";
29587
- const referenceId = typeof reference.id === "string" ? reference.id.trim() : "";
29588
- if (parsedId && referenceId && parsedId === referenceId) return true;
29589
- return typeof parsed.index === "number" && Number.isFinite(parsed.index) && typeof reference.index === "number" && Number.isFinite(reference.index) && parsed.index === reference.index;
29590
- };
29591
- const exactReferenceKey = (role, comparable) => `${role}\0${comparable}`;
29592
- const ensureExactReferenceIndex = () => {
29593
- if (exactReferenceIndexesByKey) return exactReferenceIndexesByKey;
29594
- const byKey = /* @__PURE__ */ new Map();
29595
- for (let i = 0; i < referenceMessages.length; i++) {
29596
- const candidate = referenceMessages[i];
29597
- if (!candidate || candidate.role !== "user" && candidate.role !== "assistant" || !hasFiniteTimestamp(candidate)) continue;
29598
- const comparable = getReferenceComparable(i);
29599
- if (!comparable) continue;
29600
- const key = exactReferenceKey(candidate.role, comparable);
29601
- const indexes = byKey.get(key);
29602
- if (indexes) {
29603
- indexes.push(i);
29604
- } else {
29605
- byKey.set(key, [i]);
29606
- }
29607
- }
29608
- exactReferenceIndexesByKey = byKey;
29609
- return byKey;
29610
- };
29611
- const takeExactReferenceTimestamp = (role, normalizedContent) => {
29612
- const key = exactReferenceKey(role, normalizedContent);
29613
- const indexes = ensureExactReferenceIndex().get(key);
29614
- if (!indexes) return void 0;
29615
- let cursor = exactReferenceCursorByKey.get(key) || 0;
29616
- while (cursor < indexes.length) {
29617
- const candidateIndex = indexes[cursor];
29618
- cursor += 1;
29619
- if (usedReferenceIndexes.has(candidateIndex)) continue;
29620
- const candidate = referenceMessages[candidateIndex];
29621
- if (!candidate || candidate.role !== role || !hasFiniteTimestamp(candidate)) continue;
29622
- usedReferenceIndexes.add(candidateIndex);
29623
- exactReferenceCursorByKey.set(key, cursor);
29624
- return candidate.timestamp;
29625
- }
29626
- exactReferenceCursorByKey.set(key, cursor);
29627
- return void 0;
29628
- };
29629
- const findReferenceTimestamp = (message, role, content, parsedIndex) => {
29630
- const sameIndex = referenceMessages[parsedIndex];
29631
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && hasFiniteTimestamp(sameIndex) && messagesShareStableIdentity(message, sameIndex)) {
29632
- usedReferenceIndexes.add(parsedIndex);
29633
- return sameIndex.timestamp;
29634
- }
29635
- const normalizedContent = normalizeComparableMessageContent(content);
29636
- if (!normalizedContent) return void 0;
29637
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && getReferenceComparable(parsedIndex) === normalizedContent && hasFiniteTimestamp(sameIndex)) {
29638
- usedReferenceIndexes.add(parsedIndex);
29639
- return sameIndex.timestamp;
29640
- }
29641
- const exactTimestamp = takeExactReferenceTimestamp(role, normalizedContent);
29642
- if (typeof exactTimestamp === "number") return exactTimestamp;
29643
- for (let i = 0; i < referenceMessages.length; i++) {
29644
- if (usedReferenceIndexes.has(i)) continue;
29645
- const candidate = referenceMessages[i];
29646
- if (!candidate || candidate.role !== role) continue;
29647
- const candidateContent = getReferenceComparable(i);
29648
- if (!candidateContent) continue;
29649
- const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
29650
- if (!fuzzyMatch) continue;
29651
- if (hasFiniteTimestamp(candidate)) {
29652
- usedReferenceIndexes.add(i);
29653
- return candidate.timestamp;
29654
- }
29655
- }
29656
- return void 0;
29657
- };
29658
- return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
29659
- const role = message.role;
29660
- const content = typeof message.content === "string" ? message.content : String(message.content || "");
29661
- const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
29662
- const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(message, role, content, index);
29663
- const fallbackTimestamp = role === "user" ? scope?.startedAt || now : lastOutputAt || scope?.startedAt || now;
29664
- const timestamp = referenceTimestamp ?? fallbackTimestamp;
29665
- return {
29666
- ...message,
29667
- role,
29668
- content,
29669
- timestamp,
29670
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
29671
- };
29672
- });
29673
- }
29674
- function chooseMoreComparableCliMessage(left, right, leftComparable = normalizeComparableMessageContent(left.content || ""), rightComparable = normalizeComparableMessageContent(right.content || "")) {
29675
- if (leftComparable && leftComparable === rightComparable) {
29676
- const leftNewlines = String(left.content || "").split(/\r\n|\n|\r/g).length - 1;
29677
- const rightNewlines = String(right.content || "").split(/\r\n|\n|\r/g).length - 1;
29678
- return rightNewlines < leftNewlines ? right : left;
29679
- }
29680
- return rightComparable.length > leftComparable.length ? right : left;
29681
- }
29682
- function dedupeConsecutiveComparableCliMessages(messages) {
29683
- const deduped = [];
29684
- for (const message of messages) {
29685
- const current = {
29686
- ...message,
29687
- content: typeof message.content === "string" ? message.content : String(message.content || "")
29688
- };
29689
- const currentComparable = normalizeComparableMessageContent(current.content || "");
29690
- const previous = deduped[deduped.length - 1];
29691
- if (!previous) {
29692
- deduped.push({ message: current, comparable: currentComparable });
29693
- continue;
29694
- }
29695
- const sameRole = previous.message.role === current.role;
29696
- const sameKind = (previous.message.kind || "standard") === (current.kind || "standard");
29697
- const sameSender = (previous.message.senderName || "") === (current.senderName || "");
29698
- const comparableMatch = previous.comparable && previous.comparable === currentComparable;
29699
- if (sameRole && sameKind && sameSender && comparableMatch) {
29700
- const selected = chooseMoreComparableCliMessage(
29701
- previous.message,
29702
- current,
29703
- previous.comparable,
29704
- currentComparable
29705
- );
29706
- deduped[deduped.length - 1] = {
29707
- message: selected,
29708
- comparable: selected === current ? currentComparable : previous.comparable
29709
- };
29710
- continue;
29711
- }
29712
- deduped.push({ message: current, comparable: currentComparable });
29713
- }
29714
- return deduped.map((entry) => entry.message);
29715
- }
29716
- function normalizeCliParsedMessages(parsedMessages, options) {
29717
- return dedupeConsecutiveComparableCliMessages(hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
29718
- role: message.role,
29719
- content: message.content,
29720
- timestamp: message.timestamp,
29721
- receivedAt: message.receivedAt,
29722
- kind: message.kind,
29723
- id: message.id,
29724
- index: message.index,
29725
- providerUnitKey: message.providerUnitKey,
29726
- bubbleId: message.bubbleId,
29727
- bubbleState: message.bubbleState,
29728
- _turnKey: message._turnKey,
29729
- meta: message.meta,
29730
- senderName: message.senderName
29731
- })));
28965
+ function normalizeCliParsedMessages(parsedMessages, _options) {
28966
+ return Array.isArray(parsedMessages) ? parsedMessages : [];
29732
28967
  }
29733
28968
  function buildCliParseInput(options) {
29734
28969
  const {
@@ -29934,40 +29169,8 @@ var require_dist2 = __commonJS({
29934
29169
  __export2(provider_cli_adapter_exports, {
29935
29170
  ProviderCliAdapter: () => ProviderCliAdapter,
29936
29171
  appendBoundedText: () => appendBoundedText,
29937
- normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime,
29938
- sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent,
29939
- trimLastAssistantEchoForCliMessages: () => trimLastAssistantEchoForCliMessages
29940
- });
29941
- function normalizeComparableTranscriptText(value) {
29942
- return sanitizeTerminalText(String(value || "")).replace(/\s+/g, " ").trim();
29943
- }
29944
- function hasVisibleInterruptPrompt(text) {
29945
- const interruptCopyPattern = /\bEnter\s+to\s+interrupt\b(?:\s*,?\s*Ctrl\s*(?:\+|-)?\s*C\s+to\s+cancel)?/i;
29946
- return sanitizeTerminalText(text || "").split(/\r?\n/g).some((line) => {
29947
- const trimmed = line.trim();
29948
- if (!interruptCopyPattern.test(trimmed)) return false;
29949
- return /^(?:[^A-Za-z0-9\s]{1,8}\s+)?[❯›>]\s+/.test(trimmed);
29950
- });
29951
- }
29952
- function parsedTranscriptIsRicherThanCommitted(parsedMessages, committedMessages) {
29953
- if (!Array.isArray(parsedMessages) || !Array.isArray(committedMessages)) return false;
29954
- if (parsedMessages.length > committedMessages.length) return true;
29955
- if (parsedMessages.length !== committedMessages.length) return false;
29956
- for (let index = 0; index < parsedMessages.length; index += 1) {
29957
- const parsed = parsedMessages[index];
29958
- const committed = committedMessages[index];
29959
- if (!parsed || !committed) return false;
29960
- if ((parsed.role || "") !== (committed.role || "")) return false;
29961
- if (parsed.id && committed.id && String(parsed.id) !== String(committed.id)) return false;
29962
- if (typeof parsed.index === "number" && typeof committed.index === "number" && parsed.index !== committed.index) return false;
29963
- const parsedText = normalizeComparableTranscriptText(parsed.content);
29964
- const committedText = normalizeComparableTranscriptText(committed.content);
29965
- if (!parsedText || !committedText || parsedText === committedText) continue;
29966
- if (parsedText.length > committedText.length && parsedText.startsWith(committedText)) return true;
29967
- return false;
29968
- }
29969
- return false;
29970
- }
29172
+ normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
29173
+ });
29971
29174
  function appendBoundedText(current, chunk, maxChars) {
29972
29175
  if (!chunk) return current.length <= maxChars ? current : current.slice(-maxChars);
29973
29176
  if (maxChars <= 0) return "";
@@ -29976,77 +29179,7 @@ var require_dist2 = __commonJS({
29976
29179
  if (current.length <= keepFromCurrent) return current + chunk;
29977
29180
  return current.slice(-keepFromCurrent) + chunk;
29978
29181
  }
29979
- function isLikelyCommittedActivityPrefixContinuation(line) {
29980
- const trimmed = String(line || "").trim();
29981
- if (!trimmed) return false;
29982
- if (COMMITTED_ACTIVITY_PREFIX_BLOCK_RE.test(trimmed)) return false;
29983
- if (/\s/.test(trimmed)) return false;
29984
- if (/[가-힣]/.test(trimmed)) return false;
29985
- if (trimmed.length > 96) return false;
29986
- return /^[A-Za-z0-9_./:@+%=-]+$/.test(trimmed);
29987
- }
29988
- function parseCommittedActivityPrefixBlock(lines, index) {
29989
- const first = String(lines[index] || "").trim();
29990
- if (!COMMITTED_ACTIVITY_PREFIX_BLOCK_RE.test(first)) return null;
29991
- const parts = [first];
29992
- let nextIndex = index + 1;
29993
- while (nextIndex < lines.length && isLikelyCommittedActivityPrefixContinuation(lines[nextIndex])) {
29994
- parts.push(String(lines[nextIndex] || "").trim());
29995
- nextIndex += 1;
29996
- }
29997
- return { label: parts.join(""), nextIndex };
29998
- }
29999
- function sanitizeCliStandardMessageContent(content) {
30000
- const source = String(content || "").trim();
30001
- if (!source) return "";
30002
- const lines = source.split(/\r?\n/);
30003
- if (lines.length < 4) return source;
30004
- const counts = /* @__PURE__ */ new Map();
30005
- for (let index = 0; index < lines.length; index += 1) {
30006
- const block = parseCommittedActivityPrefixBlock(lines, index);
30007
- if (!block) continue;
30008
- counts.set(block.label, (counts.get(block.label) || 0) + 1);
30009
- index = block.nextIndex - 1;
30010
- }
30011
- const repeatedLabels = new Set(
30012
- Array.from(counts.entries()).filter(([, count]) => count >= 3).map(([label]) => label)
30013
- );
30014
- if (repeatedLabels.size === 0) return source;
30015
- const stripped = [];
30016
- let removed = 0;
30017
- for (let index = 0; index < lines.length; index += 1) {
30018
- const block = parseCommittedActivityPrefixBlock(lines, index);
30019
- if (block && repeatedLabels.has(block.label)) {
30020
- removed += 1;
30021
- index = block.nextIndex - 1;
30022
- continue;
30023
- }
30024
- stripped.push(lines[index]);
30025
- }
30026
- const next = stripped.join("\n").replace(/\n{3,}/g, "\n\n").trim();
30027
- return removed >= 3 && next.length >= 80 ? next : source;
30028
- }
30029
- function sanitizeCommittedMessageForDisplay(message) {
30030
- if (!message || message.role !== "assistant" || (message.kind || "standard") !== "standard") return message;
30031
- const content = sanitizeCliStandardMessageContent(message.content);
30032
- if (content === message.content) return message;
30033
- return { ...message, content };
30034
- }
30035
- function trimLastAssistantEchoForCliMessages(messages, prompt) {
30036
- if (!prompt) return;
30037
- for (let index = messages.length - 1; index >= 0; index -= 1) {
30038
- const message = messages[index];
30039
- if (!message || message.role !== "assistant" || typeof message.content !== "string") continue;
30040
- if ((message.kind || "standard") !== "standard") continue;
30041
- message.content = trimPromptEchoPrefix(message.content, prompt);
30042
- if (!message.content.trim()) {
30043
- messages.splice(index, 1);
30044
- }
30045
- return;
30046
- }
30047
- }
30048
29182
  var os11;
30049
- var COMMITTED_ACTIVITY_PREFIX_BLOCK_RE;
30050
29183
  var ProviderCliAdapter;
30051
29184
  var init_provider_cli_adapter = __esm2({
30052
29185
  "src/cli-adapters/provider-cli-adapter.ts"() {
@@ -30057,13 +29190,10 @@ var require_dist2 = __commonJS({
30057
29190
  init_terminal_screen();
30058
29191
  init_pty_transport();
30059
29192
  init_provider_cli_shared();
30060
- init_chat_message_normalization();
30061
- init_read_chat_contract();
30062
29193
  init_provider_cli_parse();
30063
29194
  init_provider_cli_config();
30064
29195
  init_provider_cli_runtime();
30065
29196
  init_provider_cli_shared();
30066
- COMMITTED_ACTIVITY_PREFIX_BLOCK_RE = /^(?:📖|💻|🔎|📚|📋|✏️|📝|🔧|🛠️|⚙️)\s+(.+)$/;
30067
29197
  ProviderCliAdapter = class _ProviderCliAdapter {
30068
29198
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
30069
29199
  this.extraArgs = extraArgs;
@@ -30106,11 +29236,6 @@ var require_dist2 = __commonJS({
30106
29236
  provider;
30107
29237
  ptyProcess = null;
30108
29238
  transportFactory;
30109
- messages = [];
30110
- committedMessages = [];
30111
- structuredMessages = [];
30112
- committedMessagesActivitySignature = "";
30113
- committedMessagesChangedAt = 0;
30114
29239
  currentStatus = "starting";
30115
29240
  onStatusChange = null;
30116
29241
  responseBuffer = "";
@@ -30190,11 +29315,8 @@ var require_dist2 = __commonJS({
30190
29315
  traceSeq = 0;
30191
29316
  traceSessionId = "";
30192
29317
  parsedStatusCache = null;
30193
- lastStatusHotPathParseAt = Number.NEGATIVE_INFINITY;
30194
- static STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1e3;
30195
29318
  static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
30196
29319
  static MAX_TRACE_ENTRIES = 250;
30197
- static PARSE_MESSAGE_TAIL_LIMIT = 100;
30198
29320
  providerResolutionMeta;
30199
29321
  static FINISH_RETRY_DELAY_MS = 300;
30200
29322
  static MAX_FINISH_RETRIES = 2;
@@ -30215,35 +29337,6 @@ var require_dist2 = __commonJS({
30215
29337
  recordBoundedAppendDrop(previousLength, appendedLength, nextLength) {
30216
29338
  return Math.max(0, previousLength + appendedLength - nextLength);
30217
29339
  }
30218
- buildCommittedMessagesActivitySignature() {
30219
- const last = this.committedMessages[this.committedMessages.length - 1];
30220
- return [
30221
- String(this.committedMessages.length),
30222
- String(last?.role || ""),
30223
- String(last?.kind || ""),
30224
- String(last?.senderName || ""),
30225
- String(last?.timestamp || ""),
30226
- String(last?.receivedAt || ""),
30227
- normalizeComparableMessageContent(last?.content || "").slice(-240)
30228
- ].join("|");
30229
- }
30230
- syncMessageViews() {
30231
- const signature = this.buildCommittedMessagesActivitySignature();
30232
- if (signature !== this.committedMessagesActivitySignature) {
30233
- this.committedMessagesActivitySignature = signature;
30234
- this.committedMessagesChangedAt = Date.now();
30235
- }
30236
- this.messages = [...this.committedMessages];
30237
- this.structuredMessages = [...this.committedMessages];
30238
- }
30239
- getLastCommittedMessageActivityAt() {
30240
- const last = this.committedMessages[this.committedMessages.length - 1];
30241
- const messageTime = Math.max(
30242
- typeof last?.receivedAt === "number" && Number.isFinite(last.receivedAt) ? last.receivedAt : 0,
30243
- typeof last?.timestamp === "number" && Number.isFinite(last.timestamp) ? last.timestamp : 0
30244
- );
30245
- return Math.max(messageTime, this.committedMessagesChangedAt || 0);
30246
- }
30247
29340
  readTerminalScreenText(now = Date.now()) {
30248
29341
  const screenText = this.terminalScreen.getText() || "";
30249
29342
  this.lastScreenText = screenText;
@@ -30263,7 +29356,7 @@ var require_dist2 = __commonJS({
30263
29356
  }
30264
29357
  getFreshParsedStatusCache() {
30265
29358
  const cached2 = this.parsedStatusCache;
30266
- if (cached2 && cached2.committedMessagesRef === this.committedMessages && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.screenText === this.lastScreenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName) {
29359
+ if (cached2 && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.screenText === this.lastScreenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName) {
30267
29360
  return cached2.result;
30268
29361
  }
30269
29362
  return null;
@@ -30274,45 +29367,6 @@ var require_dist2 = __commonJS({
30274
29367
  shouldUseFullProviderTranscriptContext() {
30275
29368
  return this.providerOwnsTranscript() && this.provider.transcriptContext === "full";
30276
29369
  }
30277
- selectParseBaseMessages(baseMessages) {
30278
- if (this.shouldUseFullProviderTranscriptContext()) return baseMessages;
30279
- if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
30280
- return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
30281
- }
30282
- messagesShareStableIdentity(left, right) {
30283
- if (left === right) return true;
30284
- if (!left || !right) return false;
30285
- if ((left.role || "") !== (right.role || "")) return false;
30286
- if (left.id && right.id && String(left.id) === String(right.id)) return true;
30287
- if (typeof left.index === "number" && typeof right.index === "number" && left.index === right.index) return true;
30288
- return false;
30289
- }
30290
- messagesComparable(left, right) {
30291
- if (this.messagesShareStableIdentity(left, right)) return true;
30292
- if (!left || !right) return false;
30293
- if ((left.role || "") !== (right.role || "")) return false;
30294
- const leftText = normalizeComparableTranscriptText(left.content);
30295
- const rightText = normalizeComparableTranscriptText(right.content);
30296
- return !!leftText && leftText === rightText;
30297
- }
30298
- stitchParsedMessagesWithCommittedBase(parsedMessages, fullBaseMessages, parseBaseMessages) {
30299
- if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
30300
- if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
30301
- const parsedFirst = parsedMessages[0];
30302
- const fullFirst = fullBaseMessages[0];
30303
- if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
30304
- return parsedMessages;
30305
- }
30306
- const tailFirst = parseBaseMessages[0];
30307
- if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
30308
- const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
30309
- const prefix = fullBaseMessages.slice(0, prefixLength);
30310
- const shouldSanitizePrefix = !!this.currentTurnScope || this.currentStatus !== "idle" || !!this.activeModal;
30311
- const nextPrefix = shouldSanitizePrefix ? prefix.map((message) => sanitizeCommittedMessageForDisplay(message)) : prefix;
30312
- return [...nextPrefix, ...parsedMessages];
30313
- }
30314
- return [...fullBaseMessages, ...parsedMessages];
30315
- }
30316
29370
  getIdleFinishConfirmMs() {
30317
29371
  return this.timeouts.idleFinishConfirm;
30318
29372
  }
@@ -30765,9 +29819,6 @@ var require_dist2 = __commonJS({
30765
29819
  `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
30766
29820
  );
30767
29821
  }
30768
- trimLastAssistantEcho(messages, prompt) {
30769
- trimLastAssistantEchoForCliMessages(messages, prompt);
30770
- }
30771
29822
  clearAllTimers() {
30772
29823
  if (this.responseTimeout) {
30773
29824
  clearTimeout(this.responseTimeout);
@@ -30863,10 +29914,10 @@ var require_dist2 = __commonJS({
30863
29914
  }
30864
29915
  const session = this.runParseSession();
30865
29916
  if (!session) return;
30866
- const { status, messages, modal, parsedStatus } = session;
29917
+ const { status, messages, parsedStatus } = session;
29918
+ const modal = session.activeModal ?? session.modal ?? null;
30867
29919
  const parsedMessages = normalizeCliParsedMessages(messages, {
30868
- committedMessages: this.committedMessages,
30869
- scope: this.currentTurnScope,
29920
+ scope: null,
30870
29921
  lastOutputAt: this.lastOutputAt
30871
29922
  });
30872
29923
  if (this.maybeCommitVisibleIdleTranscript(session, parsedMessages)) return;
@@ -31046,7 +30097,7 @@ var require_dist2 = __commonJS({
31046
30097
  const effectiveScreenText = screenText || this.accumulatedBuffer;
31047
30098
  const noActiveTurn = !this.currentTurnScope;
31048
30099
  const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText);
31049
- const parsedShowsLiveAssistantProgress = parsedStatus === "generating" && !!lastParsedAssistant && parsedMessages.length > this.committedMessages.length;
30100
+ const parsedShowsLiveAssistantProgress = parsedStatus === "generating" && !!lastParsedAssistant;
31050
30101
  if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
31051
30102
  return;
31052
30103
  }
@@ -31203,10 +30254,7 @@ var require_dist2 = __commonJS({
31203
30254
  }
31204
30255
  const visibleAssistant = [...parsedMessages].reverse().find((m) => m.role === "assistant" && m.content.trim());
31205
30256
  if (!visibleAssistant) return false;
31206
- this.committedMessages = parsedMessages;
31207
- this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
31208
30257
  this.clearAllTimers();
31209
- this.syncMessageViews();
31210
30258
  this.responseBuffer = "";
31211
30259
  this.isWaitingForResponse = false;
31212
30260
  this.responseSettleIgnoreUntil = 0;
@@ -31218,37 +30266,34 @@ var require_dist2 = __commonJS({
31218
30266
  this.setStatus("idle", "script_idle_commit");
31219
30267
  this.onStatusChange?.();
31220
30268
  this.recordTrace("script_idle_commit", {
31221
- messageCount: this.committedMessages.length,
30269
+ messageCount: parsedMessages.length,
31222
30270
  lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320)
31223
30271
  });
31224
30272
  return true;
31225
30273
  }
31226
30274
  commitCurrentTranscript() {
31227
30275
  const parsed = this.parseCurrentTranscript(
31228
- this.committedMessages,
30276
+ [],
31229
30277
  this.responseBuffer,
31230
30278
  this.currentTurnScope
31231
30279
  );
31232
30280
  if (parsed && Array.isArray(parsed.messages)) {
31233
- this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
31234
- committedMessages: this.committedMessages,
31235
- scope: this.currentTurnScope,
30281
+ const parsedMessages = normalizeCliParsedMessages(parsed.messages, {
30282
+ scope: null,
31236
30283
  lastOutputAt: this.lastOutputAt
31237
30284
  });
31238
- this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
31239
- this.syncMessageViews();
31240
- const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
30285
+ const lastAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
31241
30286
  if (this.currentTurnScope) {
31242
30287
  LOG2.info(
31243
30288
  "CLI",
31244
- `[${this.cliType}] commitCurrentTranscript committedMessages=${this.committedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
30289
+ `[${this.cliType}] commitCurrentTranscript parserMessages=${parsedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
31245
30290
  );
31246
30291
  }
31247
30292
  this.recordTrace("commit_transcript", {
31248
30293
  parsedStatus: parsed.status || null,
31249
- messageCount: this.committedMessages.length,
30294
+ messageCount: parsedMessages.length,
31250
30295
  lastAssistant: lastAssistant ? summarizeCliTraceText(lastAssistant.content, 320) : "",
31251
- messages: summarizeCliTraceMessages(this.committedMessages),
30296
+ messages: summarizeCliTraceMessages(parsedMessages),
31252
30297
  ...buildCliTraceParseSnapshot({
31253
30298
  accumulatedBuffer: this.accumulatedBuffer,
31254
30299
  accumulatedRawBuffer: this.accumulatedRawBuffer,
@@ -31282,63 +30327,31 @@ var require_dist2 = __commonJS({
31282
30327
  }
31283
30328
  // ─── Script Execution ──────────────────────────
31284
30329
  runParseSession() {
31285
- if (typeof this.cliScripts?.parseSession === "function") {
31286
- try {
31287
- const screenText = this.terminalScreen.getText();
31288
- const tail = this.recentOutputBuffer.slice(-500);
31289
- const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
31290
- const input = buildCliParseInput({
31291
- accumulatedBuffer: this.accumulatedBuffer,
31292
- accumulatedRawBuffer: this.accumulatedRawBuffer,
31293
- recentOutputBuffer: this.recentOutputBuffer,
31294
- terminalScreenText: screenText,
31295
- baseMessages: parseBaseMessages,
31296
- partialResponse: this.responseBuffer,
31297
- isWaitingForResponse: this.isWaitingForResponse,
31298
- scope: this.currentTurnScope,
31299
- runtimeSettings: this.runtimeSettings
31300
- });
31301
- const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
31302
- if (session && typeof session === "object" && Array.isArray(session.messages)) {
31303
- session.messages = this.stitchParsedMessagesWithCommittedBase(
31304
- session.messages,
31305
- this.committedMessages,
31306
- parseBaseMessages
31307
- );
31308
- }
31309
- this.parseErrorMessage = null;
31310
- return session && typeof session === "object" ? session : null;
31311
- } catch (e) {
31312
- const message = e?.message || String(e);
31313
- this.parseErrorMessage = message;
31314
- LOG2.warn("CLI", `[${this.cliType}] parseSession error: ${message}`);
31315
- return null;
31316
- }
30330
+ if (typeof this.cliScripts?.parseSession !== "function") {
30331
+ this.parseErrorMessage = `${this.cliType} parseSession unavailable`;
30332
+ return null;
31317
30333
  }
31318
- if (!this.cliScripts?.detectStatus && !this.cliScripts?.parseOutput) return null;
31319
30334
  try {
31320
- const tail = this.settledBuffer;
31321
- const parsedTranscript = this.parseCurrentTranscript(
31322
- this.committedMessages,
31323
- this.responseBuffer,
31324
- this.currentTurnScope
31325
- );
31326
- const parsedModal = parsedTranscript?.activeModal && Array.isArray(parsedTranscript.activeModal.buttons) && parsedTranscript.activeModal.buttons.some((b2) => typeof b2 === "string" && b2.trim()) ? parsedTranscript.activeModal : null;
31327
- const approval = this.runParseApproval(tail);
31328
- const modal = approval || parsedModal;
31329
- const rawStatus = this.runDetectStatus(tail);
31330
- const parsedStatus = typeof parsedTranscript?.status === "string" ? parsedTranscript.status : null;
31331
- const effectiveStatus = parsedStatus === "waiting_approval" && modal ? "waiting_approval" : rawStatus || parsedStatus || "idle";
31332
- return {
31333
- status: effectiveStatus,
31334
- messages: Array.isArray(parsedTranscript?.messages) ? parsedTranscript.messages : [],
31335
- modal,
31336
- parsedStatus
31337
- };
30335
+ const screenText = this.terminalScreen.getText();
30336
+ const tail = this.recentOutputBuffer.slice(-500);
30337
+ const input = buildCliParseInput({
30338
+ accumulatedBuffer: this.accumulatedBuffer,
30339
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
30340
+ recentOutputBuffer: this.recentOutputBuffer,
30341
+ terminalScreenText: screenText,
30342
+ baseMessages: [],
30343
+ partialResponse: this.responseBuffer,
30344
+ isWaitingForResponse: this.isWaitingForResponse,
30345
+ scope: this.currentTurnScope,
30346
+ runtimeSettings: this.runtimeSettings
30347
+ });
30348
+ const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
30349
+ this.parseErrorMessage = null;
30350
+ return session && typeof session === "object" ? session : null;
31338
30351
  } catch (e) {
31339
30352
  const message = e?.message || String(e);
31340
30353
  this.parseErrorMessage = message;
31341
- LOG2.warn("CLI", `[${this.cliType}] parseSession fallback error: ${message}`);
30354
+ LOG2.warn("CLI", `[${this.cliType}] parseSession error: ${message}`);
31342
30355
  return null;
31343
30356
  }
31344
30357
  }
@@ -31388,45 +30401,14 @@ var require_dist2 = __commonJS({
31388
30401
  if (this.isWaitingForResponse && this.currentTurnScope && this.currentStatus !== "stopped") return "generating";
31389
30402
  return this.currentStatus;
31390
30403
  }
31391
- suppressStaleParsedApproval(parsed, recentBuffer, screenText) {
31392
- const actionableParsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
31393
- if (!parsed || parsed?.status !== "waiting_approval" || !actionableParsedModal) {
31394
- return parsed;
31395
- }
31396
- const inApprovalCooldown = this.lastApprovalResolvedAt > 0 && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
31397
- if (!inApprovalCooldown) {
31398
- return parsed;
31399
- }
31400
- const visibleModal = this.runParseApproval(recentBuffer);
31401
- if (visibleModal) {
31402
- return parsed;
31403
- }
31404
- const detectedStatus = this.runDetectStatus(recentBuffer);
31405
- const resolvedStatus = detectedStatus && detectedStatus !== "waiting_approval" ? detectedStatus : this.isWaitingForResponse || this.currentTurnScope ? "generating" : this.currentStatus === "waiting_approval" ? "idle" : this.currentStatus;
31406
- return {
31407
- ...parsed,
31408
- status: resolvedStatus,
31409
- activeModal: null
31410
- };
31411
- }
31412
30404
  // ─── Public API (CliAdapter) ───────────────────
31413
30405
  getStatus(options = {}) {
31414
30406
  const allowParse = options.allowParse !== false;
31415
30407
  const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
31416
30408
  let effectiveStatus = this.projectEffectiveStatus(startupModal);
31417
30409
  let effectiveModal = startupModal || this.activeModal;
31418
- if (allowParse && !startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
31419
- let parsed = this.getFreshParsedStatusCache();
31420
- if (!parsed && effectiveStatus !== "idle") {
31421
- const now = Date.now();
31422
- if (now - this.lastStatusHotPathParseAt >= _ProviderCliAdapter.STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS) {
31423
- this.lastStatusHotPathParseAt = now;
31424
- try {
31425
- parsed = this.getScriptParsedStatus();
31426
- } catch {
31427
- }
31428
- }
31429
- }
30410
+ if (allowParse && !startupModal && !effectiveModal) {
30411
+ const parsed = this.getFreshParsedStatusCache();
31430
30412
  const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
31431
30413
  if (parsed?.status === "waiting_approval" && parsedModal) {
31432
30414
  effectiveStatus = "waiting_approval";
@@ -31436,7 +30418,7 @@ var require_dist2 = __commonJS({
31436
30418
  const bufferState = this.getBufferState();
31437
30419
  return {
31438
30420
  status: effectiveStatus,
31439
- messages: [...this.committedMessages],
30421
+ messages: [],
31440
30422
  workingDir: this.workingDir,
31441
30423
  activeModal: effectiveModal,
31442
30424
  errorMessage: this.parseErrorMessage || void 0,
@@ -31444,98 +30426,6 @@ var require_dist2 = __commonJS({
31444
30426
  ...bufferState ? { bufferState } : {}
31445
30427
  };
31446
30428
  }
31447
- seedCommittedMessages(messages) {
31448
- const normalized = (Array.isArray(messages) ? messages : []).filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
31449
- role: message.role,
31450
- content: typeof message.content === "string" ? message.content : String(message.content || ""),
31451
- timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0,
31452
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : void 0,
31453
- kind: typeof message.kind === "string" ? message.kind : void 0,
31454
- id: typeof message.id === "string" ? message.id : void 0,
31455
- index: typeof message.index === "number" ? message.index : void 0,
31456
- providerUnitKey: typeof message.providerUnitKey === "string" ? message.providerUnitKey : void 0,
31457
- bubbleId: typeof message.bubbleId === "string" ? message.bubbleId : void 0,
31458
- bubbleState: typeof message.bubbleState === "string" ? message.bubbleState : void 0,
31459
- _turnKey: typeof message._turnKey === "string" ? message._turnKey : void 0,
31460
- meta: message.meta && typeof message.meta === "object" ? { ...message.meta } : void 0,
31461
- senderName: typeof message.senderName === "string" ? message.senderName : void 0
31462
- }));
31463
- this.committedMessages = normalized;
31464
- this.syncMessageViews();
31465
- }
31466
- getSharedCommittedPrefixLength(parsedMessages) {
31467
- const committedMessages = this.committedMessages;
31468
- const max = Math.min(parsedMessages.length, committedMessages.length);
31469
- let index = 0;
31470
- while (index < max && this.messagesShareStableIdentity(parsedMessages[index], committedMessages[index])) {
31471
- index += 1;
31472
- }
31473
- return index;
31474
- }
31475
- hydrateCommittedPrefixForParsedStatus(parsedMessages) {
31476
- const sharedPrefixLength = this.getSharedCommittedPrefixLength(parsedMessages);
31477
- if (sharedPrefixLength !== this.committedMessages.length) return null;
31478
- const committedHydratedMessages = this.committedMessages.map((message, index) => {
31479
- const timestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : this.lastOutputAt || this.currentTurnScope?.startedAt || Date.now();
31480
- const contentValue = message.content;
31481
- return {
31482
- role: message.role,
31483
- content: typeof contentValue === "string" ? contentValue : String(contentValue || ""),
31484
- timestamp,
31485
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp,
31486
- kind: message.kind,
31487
- id: message.id || `msg_${index}`,
31488
- index: typeof message.index === "number" ? message.index : index,
31489
- providerUnitKey: message.providerUnitKey,
31490
- bubbleId: message.bubbleId,
31491
- bubbleState: message.bubbleState,
31492
- _turnKey: message._turnKey,
31493
- meta: message.meta,
31494
- senderName: message.senderName
31495
- };
31496
- });
31497
- const extraMessages = parsedMessages.slice(sharedPrefixLength);
31498
- if (extraMessages.length === 0) return committedHydratedMessages;
31499
- const extraHydratedMessages = hydrateCliParsedMessages(extraMessages, {
31500
- committedMessages: [],
31501
- scope: this.currentTurnScope,
31502
- lastOutputAt: this.lastOutputAt
31503
- }).map((message, offset) => ({
31504
- ...message,
31505
- id: message.id || `msg_${sharedPrefixLength + offset}`,
31506
- index: typeof message.index === "number" ? message.index : sharedPrefixLength + offset
31507
- }));
31508
- return [...committedHydratedMessages, ...extraHydratedMessages];
31509
- }
31510
- hydrateParsedMessagesForStatus(parsedMessages) {
31511
- return this.hydrateCommittedPrefixForParsedStatus(parsedMessages) || hydrateCliParsedMessages(parsedMessages, {
31512
- committedMessages: this.committedMessages,
31513
- scope: this.currentTurnScope,
31514
- lastOutputAt: this.lastOutputAt
31515
- });
31516
- }
31517
- buildCommittedChatMessages() {
31518
- return this.committedMessages.map((message, index) => {
31519
- const rawContentValue = message.content;
31520
- const rawContent = typeof rawContentValue === "string" ? rawContentValue : String(rawContentValue || "");
31521
- const content = message.role === "assistant" && (message.kind || "standard") === "standard" ? sanitizeCliStandardMessageContent(rawContent) : rawContent;
31522
- return buildChatMessage({
31523
- role: message.role,
31524
- content,
31525
- timestamp: message.timestamp,
31526
- kind: message.kind,
31527
- meta: message.meta,
31528
- senderName: message.senderName,
31529
- id: message.id || `msg_${index}`,
31530
- index: typeof message.index === "number" ? message.index : index,
31531
- providerUnitKey: message.providerUnitKey,
31532
- bubbleId: message.bubbleId,
31533
- bubbleState: message.bubbleState,
31534
- _turnKey: message._turnKey,
31535
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
31536
- });
31537
- });
31538
- }
31539
30429
  /**
31540
30430
  * Script-based full parse — returns ReadChatResult.
31541
30431
  * Called by command handler / dashboard for rich content rendering.
@@ -31543,125 +30433,30 @@ var require_dist2 = __commonJS({
31543
30433
  getScriptParsedStatus() {
31544
30434
  const screenText = this.readTerminalScreenText();
31545
30435
  const cached2 = this.parsedStatusCache;
31546
- if (cached2 && cached2.committedMessagesRef === this.committedMessages && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.screenText === screenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName) {
30436
+ if (cached2 && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.screenText === screenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName) {
31547
30437
  return cached2.result;
31548
30438
  }
31549
- const parsed = this.parseCurrentTranscript(
31550
- this.committedMessages,
31551
- this.responseBuffer,
31552
- this.currentTurnScope,
31553
- screenText
31554
- );
31555
- const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
31556
- if (parsedModal && parsed?.status === "waiting_approval") {
31557
- this.activeModal = parsedModal;
31558
- this.isWaitingForResponse = true;
31559
- if (this.currentStatus !== "waiting_approval") {
31560
- this.setStatus("waiting_approval", "parsed_waiting_approval");
31561
- this.onStatusChange?.();
31562
- }
30439
+ const parsed = this.runParseSession();
30440
+ if (!parsed || !Array.isArray(parsed.messages)) {
30441
+ throw new Error(this.parseErrorMessage || `${this.cliType} parseSession did not return messages`);
31563
30442
  }
31564
- if (parsed && Array.isArray(parsed.messages) && this.provider.allowInputDuringGeneration === true) {
31565
- const hydratedForCommit = normalizeCliParsedMessages(parsed.messages, {
31566
- committedMessages: this.committedMessages,
31567
- scope: this.currentTurnScope,
30443
+ const activeModal = parsed.activeModal ?? parsed.modal ?? null;
30444
+ const bufferState = this.getBufferState();
30445
+ const result = {
30446
+ id: parsed.id || "cli_session",
30447
+ status: parsed.status || this.currentStatus,
30448
+ title: parsed.title || this.cliName,
30449
+ messages: normalizeCliParsedMessages(parsed.messages, {
30450
+ scope: null,
31568
30451
  lastOutputAt: this.lastOutputAt
31569
- });
31570
- const fakeSession = {
31571
- status: parsed.status || "idle",
31572
- messages: parsed.messages,
31573
- modal: parsedModal,
31574
- parsedStatus: parsed.status || null
31575
- };
31576
- if (this.maybeCommitVisibleIdleTranscript(fakeSession, hydratedForCommit)) {
31577
- return this.getScriptParsedStatus();
31578
- }
31579
- }
31580
- const shouldPreferCommittedMessages = !this.currentTurnScope && !this.activeModal && this.currentStatus === "idle";
31581
- let result;
31582
- if (parsed && Array.isArray(parsed.messages)) {
31583
- const parsedHydratedMessages = this.hydrateParsedMessagesForStatus(parsed.messages);
31584
- const parsedLastAssistant = [...parsedHydratedMessages].reverse().find((message) => message.role === "assistant" && typeof message.content === "string" && message.content.trim());
31585
- const shouldAdoptParsedIdleReplay = !this.currentTurnScope && !this.activeModal && !!parsedLastAssistant && parsedTranscriptIsRicherThanCommitted(parsedHydratedMessages, this.committedMessages) && (this.currentStatus === "idle" || this.currentStatus === "generating" && this.isWaitingForResponse && parsed.status === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle");
31586
- if (shouldAdoptParsedIdleReplay) {
31587
- this.committedMessages = this.getSharedCommittedPrefixLength(parsed.messages) === this.committedMessages.length ? parsedHydratedMessages.map((message) => ({
31588
- role: message.role,
31589
- content: typeof message.content === "string" ? message.content : String(message.content || ""),
31590
- timestamp: message.timestamp,
31591
- receivedAt: message.receivedAt,
31592
- kind: message.kind,
31593
- id: message.id,
31594
- index: message.index,
31595
- meta: message.meta,
31596
- senderName: message.senderName
31597
- })) : normalizeCliParsedMessages(parsed.messages, {
31598
- committedMessages: this.committedMessages,
31599
- scope: this.currentTurnScope,
31600
- lastOutputAt: this.lastOutputAt
31601
- });
31602
- this.syncMessageViews();
31603
- if (this.currentStatus !== "idle" || this.isWaitingForResponse) {
31604
- this.responseBuffer = "";
31605
- this.isWaitingForResponse = false;
31606
- this.responseSettleIgnoreUntil = 0;
31607
- this.submitRetryUsed = false;
31608
- this.submitRetryPromptSnippet = "";
31609
- this.finishRetryCount = 0;
31610
- this.currentTurnScope = null;
31611
- this.activeModal = null;
31612
- this.setStatus("idle", "parsed_idle_replay_commit");
31613
- this.onStatusChange?.();
31614
- }
31615
- }
31616
- const shouldPreferCommittedHistoryReplay = !this.currentTurnScope && !this.activeModal && this.committedMessages.length > parsedHydratedMessages.length;
31617
- const shouldPreferCommittedIdleReplay = shouldPreferCommittedMessages && !shouldAdoptParsedIdleReplay;
31618
- const hydratedMessages = shouldPreferCommittedIdleReplay || shouldPreferCommittedHistoryReplay ? this.buildCommittedChatMessages() : parsedHydratedMessages;
31619
- result = {
31620
- id: parsed.id || "cli_session",
31621
- status: parsed.status || this.currentStatus,
31622
- title: parsed.title || this.cliName,
31623
- messages: hydratedMessages,
31624
- activeModal: parsed.activeModal ?? this.activeModal,
31625
- providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
31626
- ...this.getBufferState() ? { bufferState: this.getBufferState() } : {},
31627
- ...this.providerOwnsTranscript() ? { transcriptAuthority: "provider", coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
31628
- };
31629
- } else {
31630
- const messages = [...this.committedMessages];
31631
- const bufferState = this.getBufferState();
31632
- result = {
31633
- id: "cli_session",
31634
- status: this.currentStatus,
31635
- title: this.cliName,
31636
- messages: messages.map((message, index) => buildChatMessage({
31637
- ...message,
31638
- id: message.id || `msg_${index}`,
31639
- index: typeof message.index === "number" ? message.index : index,
31640
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
31641
- })),
31642
- activeModal: this.activeModal,
31643
- ...bufferState ? { bufferState } : {}
31644
- };
31645
- }
31646
- const hasVisibleAssistantMessage = Array.isArray(result?.messages) && result.messages.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
31647
- const shouldClampStaleGeneratingToIdle = result?.status === "generating" && this.currentStatus === "idle" && !this.currentTurnScope && !result?.activeModal && hasVisibleAssistantMessage && !hasVisibleInterruptPrompt(screenText);
31648
- if (shouldClampStaleGeneratingToIdle) {
31649
- result = {
31650
- ...result,
31651
- status: "idle",
31652
- messages: Array.isArray(result.messages) ? result.messages.map((message) => {
31653
- if (message?.role !== "assistant" || !message?.meta?.streaming) return message;
31654
- const nextMeta = { ...message.meta || {} };
31655
- delete nextMeta.streaming;
31656
- return {
31657
- ...message,
31658
- ...Object.keys(nextMeta).length > 0 ? { meta: nextMeta } : { meta: void 0 }
31659
- };
31660
- }) : result.messages
31661
- };
31662
- }
30452
+ }),
30453
+ activeModal,
30454
+ providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
30455
+ ...bufferState ? { bufferState } : {},
30456
+ ...parsed.transcriptAuthority === "provider" || parsed.transcriptAuthority === "daemon" ? { transcriptAuthority: parsed.transcriptAuthority } : this.providerOwnsTranscript() ? { transcriptAuthority: "provider" } : {},
30457
+ ...parsed.coverage === "full" || parsed.coverage === "tail" || parsed.coverage === "current-turn" ? { coverage: parsed.coverage } : this.providerOwnsTranscript() ? { coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
30458
+ };
31663
30459
  this.parsedStatusCache = {
31664
- committedMessagesRef: this.committedMessages,
31665
30460
  responseBuffer: this.responseBuffer,
31666
30461
  currentTurnScope: this.currentTurnScope,
31667
30462
  recentOutputBuffer: this.recentOutputBuffer,
@@ -31684,7 +30479,7 @@ var require_dist2 = __commonJS({
31684
30479
  accumulatedRawBuffer: this.accumulatedRawBuffer,
31685
30480
  recentOutputBuffer: this.recentOutputBuffer,
31686
30481
  terminalScreenText: this.terminalScreen.getText(),
31687
- baseMessages: this.committedMessages,
30482
+ baseMessages: [],
31688
30483
  partialResponse: this.responseBuffer,
31689
30484
  isWaitingForResponse: this.isWaitingForResponse,
31690
30485
  scope: this.currentTurnScope,
@@ -31695,46 +30490,8 @@ var require_dist2 = __commonJS({
31695
30490
  args: args && typeof args === "object" ? { ...args } : {}
31696
30491
  }));
31697
30492
  }
31698
- parseCurrentTranscript(baseMessages, partialResponse, scope, screenTextOverride) {
31699
- if (!this.cliScripts?.parseOutput) {
31700
- this.parseErrorMessage = null;
31701
- return null;
31702
- }
31703
- try {
31704
- const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.terminalScreen.getText();
31705
- const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
31706
- const input = buildCliParseInput({
31707
- accumulatedBuffer: this.accumulatedBuffer,
31708
- accumulatedRawBuffer: this.accumulatedRawBuffer,
31709
- recentOutputBuffer: this.recentOutputBuffer,
31710
- terminalScreenText: screenText,
31711
- baseMessages: parseBaseMessages,
31712
- partialResponse,
31713
- isWaitingForResponse: this.isWaitingForResponse,
31714
- scope,
31715
- runtimeSettings: this.runtimeSettings
31716
- });
31717
- const parsed = this.cliScripts.parseOutput(input);
31718
- if (parsed && typeof parsed === "object") {
31719
- Object.assign(parsed, validateReadChatResultPayload(parsed, `${this.cliType} parseOutput`));
31720
- }
31721
- const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
31722
- if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
31723
- normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
31724
- normalizedParsed.messages,
31725
- baseMessages,
31726
- parseBaseMessages
31727
- );
31728
- this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
31729
- }
31730
- this.parseErrorMessage = null;
31731
- return normalizedParsed;
31732
- } catch (e) {
31733
- const message = e?.message || String(e);
31734
- this.parseErrorMessage = message;
31735
- LOG2.warn("CLI", `[${this.cliType}] parseOutput error: ${message}`);
31736
- throw e;
31737
- }
30493
+ parseCurrentTranscript(_baseMessages, _partialResponse, _scope, _screenTextOverride) {
30494
+ return this.runParseSession();
31738
30495
  }
31739
30496
  /** Whether this adapter has CLI scripts loaded */
31740
30497
  hasCliScripts() {
@@ -31796,8 +30553,6 @@ var require_dist2 = __commonJS({
31796
30553
  commitSendUserTurn(state) {
31797
30554
  if (state.didCommitUserTurn) return;
31798
30555
  state.didCommitUserTurn = true;
31799
- this.committedMessages.push({ role: "user", content: state.text, timestamp: Date.now() });
31800
- this.syncMessageViews();
31801
30556
  }
31802
30557
  armResponseTimeout() {
31803
30558
  if (this.responseTimeout) clearTimeout(this.responseTimeout);
@@ -31989,11 +30744,6 @@ var require_dist2 = __commonJS({
31989
30744
  }
31990
30745
  })() : null;
31991
30746
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
31992
- const parsedMessagesBeforeSend = Array.isArray(parsedStatusBeforeSend?.messages) ? parsedStatusBeforeSend.messages.filter((message) => message && (message.role === "user" || message.role === "assistant")) : [];
31993
- const shouldCommitParsedIdleBeforeSend = !allowInputDuringGeneration && parsedSessionStatus === "idle" && parsedMessagesBeforeSend.length > this.committedMessages.length && parsedMessagesBeforeSend.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
31994
- if (shouldCommitParsedIdleBeforeSend) {
31995
- this.commitCurrentTranscript();
31996
- }
31997
30747
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
31998
30748
  throw new Error(`${this.cliName} is still processing the previous prompt`);
31999
30749
  }
@@ -32099,9 +30849,6 @@ var require_dist2 = __commonJS({
32099
30849
  activeModal: this.activeModal,
32100
30850
  parseErrorMessage: this.parseErrorMessage,
32101
30851
  messageCounts: {
32102
- committed: this.committedMessages.length,
32103
- structured: this.structuredMessages.length,
32104
- visible: this.messages.length,
32105
30852
  parsedCache: Array.isArray(parsedResult?.messages) ? parsedResult.messages.length : void 0
32106
30853
  },
32107
30854
  buffers: {
@@ -32152,8 +30899,7 @@ var require_dist2 = __commonJS({
32152
30899
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
32153
30900
  responseEpoch: this.responseEpoch,
32154
30901
  resizeSuppressUntil: this.resizeSuppressUntil,
32155
- lastApprovalResolvedAt: this.lastApprovalResolvedAt,
32156
- committedMessagesChangedAt: this.committedMessagesChangedAt
30902
+ lastApprovalResolvedAt: this.lastApprovalResolvedAt
32157
30903
  },
32158
30904
  finish: {
32159
30905
  idleFinishCandidate: this.idleFinishCandidate,
@@ -32278,8 +31024,6 @@ var require_dist2 = __commonJS({
32278
31024
  }
32279
31025
  clearHistory() {
32280
31026
  this.clearIdleFinishCandidate("clear_history");
32281
- this.committedMessages = [];
32282
- this.syncMessageViews();
32283
31027
  this.accumulatedBuffer = "";
32284
31028
  this.accumulatedRawBuffer = "";
32285
31029
  this.currentTurnScope = null;
@@ -32320,7 +31064,7 @@ var require_dist2 = __commonJS({
32320
31064
  }
32321
31065
  resolveModal(buttonIndex) {
32322
31066
  let modal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
32323
- if (!modal && typeof this.cliScripts?.parseOutput === "function") {
31067
+ if (!modal && typeof this.cliScripts?.parseSession === "function") {
32324
31068
  try {
32325
31069
  const parsed = this.getScriptParsedStatus();
32326
31070
  const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
@@ -32387,10 +31131,8 @@ var require_dist2 = __commonJS({
32387
31131
  startupParseGate: this.startupParseGate,
32388
31132
  spawnAt: this.spawnAt,
32389
31133
  workingDir: this.workingDir,
32390
- messages: this.messages,
32391
- committedMessages: this.committedMessages,
32392
- structuredMessages: this.structuredMessages,
32393
- messageCount: this.committedMessages.length,
31134
+ messages: [],
31135
+ messageCount: 0,
32394
31136
  screenText: screenText.slice(-4e3),
32395
31137
  currentTurnScope: this.currentTurnScope,
32396
31138
  startupBuffer: this.startupBuffer.slice(-4e3),
@@ -32442,7 +31184,7 @@ var require_dist2 = __commonJS({
32442
31184
  lifecycleStatus: this.isWaitingForResponse ? "awaiting_response" : "idle",
32443
31185
  activeModal: this.activeModal,
32444
31186
  currentTurnScope: this.currentTurnScope,
32445
- messages: summarizeCliTraceMessages(this.committedMessages, 5)
31187
+ messages: []
32446
31188
  };
32447
31189
  }
32448
31190
  getProviderResolutionMeta() {
@@ -36023,173 +34765,380 @@ var require_dist2 = __commonJS({
36023
34765
  index: i,
36024
34766
  tag: el.tagName?.toLowerCase(),
36025
34767
  id: el.id || null,
36026
- class: el.className && typeof el.className === 'string' ? el.className.trim().slice(0, 200) : null,
36027
- role: el.getAttribute?.('role') || null,
36028
- 'data-testid': el.getAttribute?.('data-testid') || null,
34768
+ class: el.className && typeof el.className === 'string' ? el.className.trim().slice(0, 200) : null,
34769
+ role: el.getAttribute?.('role') || null,
34770
+ 'data-testid': el.getAttribute?.('data-testid') || null,
34771
+ rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
34772
+ visible: el.offsetParent !== null || el.offsetWidth > 0,
34773
+ };
34774
+ ${content ? `item.text = (el.textContent || '').trim().slice(0, 200);` : ""}
34775
+ ${content ? `item.value = el.value !== undefined ? String(el.value).slice(0, 200) : undefined;` : ""}
34776
+ results.push(item);
34777
+ }
34778
+ return JSON.stringify({ total: els.length, results });
34779
+ } catch(e) {
34780
+ return JSON.stringify({ error: e.message });
34781
+ }
34782
+ })()`;
34783
+ try {
34784
+ let raw;
34785
+ if (sessionId) {
34786
+ raw = await this.getCdp().evaluateInSessionFrame(sessionId, expression);
34787
+ } else {
34788
+ raw = await this.getCdp().evaluate(expression, 15e3);
34789
+ }
34790
+ const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
34791
+ return { success: true, ...parsed, selector };
34792
+ } catch (e) {
34793
+ return { success: false, error: e.message };
34794
+ }
34795
+ }
34796
+ /**
34797
+ * CDP DOM Debug — IDE AI panel specialized analysis
34798
+ * Collect all essential info at once when supporting new IDE
34799
+ *
34800
+ * args:
34801
+ * ideType?: string — IDE type hint
34802
+ * sessionId?: string — agent webview session ID
34803
+ */
34804
+ async handleDomDebug(args) {
34805
+ if (!this.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
34806
+ const sessionId = args?.sessionId;
34807
+ const expression = `(() => {
34808
+ const result = {
34809
+ url: location.href,
34810
+ title: document.title,
34811
+ viewport: { w: window.innerWidth, h: window.innerHeight },
34812
+
34813
+ // Input field info
34814
+ inputs: [],
34815
+ // Textarea info
34816
+ textareas: [],
34817
+ // Contenteditable info
34818
+ editables: [],
34819
+ // Buttons (send, submit etc)
34820
+ buttons: [],
34821
+ // iframes (agent webviews)
34822
+ iframes: [],
34823
+ // role="textbox" info
34824
+ textboxes: [],
34825
+ };
34826
+
34827
+ // Input fields
34828
+ document.querySelectorAll('input[type="text"], input:not([type])').forEach((el, i) => {
34829
+ if (i >= 10) return;
34830
+ result.inputs.push({
34831
+ tag: 'input',
34832
+ id: el.id || null,
34833
+ class: (el.className || '').toString().slice(0, 150),
34834
+ placeholder: el.getAttribute('placeholder') || null,
34835
+ name: el.name || null,
34836
+ value: el.value?.slice(0, 100) || null,
34837
+ visible: el.offsetParent !== null,
34838
+ rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
34839
+ });
34840
+ });
34841
+
34842
+ // textarea
34843
+ document.querySelectorAll('textarea').forEach((el, i) => {
34844
+ if (i >= 10) return;
34845
+ result.textareas.push({
34846
+ id: el.id || null,
34847
+ class: (el.className || '').toString().slice(0, 150),
34848
+ placeholder: el.getAttribute('placeholder') || null,
34849
+ rows: el.rows,
34850
+ value: el.value?.slice(0, 100) || null,
34851
+ visible: el.offsetParent !== null,
34852
+ rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
34853
+ });
34854
+ });
34855
+
34856
+ // contenteditable
34857
+ document.querySelectorAll('[contenteditable="true"]').forEach((el, i) => {
34858
+ if (i >= 10) return;
34859
+ result.editables.push({
34860
+ tag: el.tagName?.toLowerCase(),
34861
+ id: el.id || null,
34862
+ class: (el.className || '').toString().slice(0, 150),
34863
+ role: el.getAttribute('role') || null,
34864
+ text: (el.textContent || '').trim().slice(0, 100),
34865
+ visible: el.offsetParent !== null,
34866
+ rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
34867
+ });
34868
+ });
34869
+
34870
+ // role="textbox"
34871
+ document.querySelectorAll('[role="textbox"]').forEach((el, i) => {
34872
+ if (i >= 10) return;
34873
+ result.textboxes.push({
34874
+ tag: el.tagName?.toLowerCase(),
34875
+ id: el.id || null,
34876
+ class: (el.className || '').toString().slice(0, 150),
34877
+ 'aria-label': el.getAttribute('aria-label') || null,
34878
+ text: (el.textContent || '').trim().slice(0, 100),
34879
+ visible: el.offsetParent !== null,
34880
+ rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
34881
+ });
34882
+ });
34883
+
34884
+ // Buttons (send, submit, accept, reject, approve etc)
34885
+ const btnKeywords = /send|submit|accept|reject|approve|deny|cancel|confirm|run|execute|apply/i;
34886
+ document.querySelectorAll('button, [role="button"], input[type="submit"]').forEach((el, i) => {
34887
+ const text = (el.textContent || el.getAttribute('aria-label') || '').trim();
34888
+ if (i < 30 && (text.length < 30 || btnKeywords.test(text))) {
34889
+ result.buttons.push({
34890
+ tag: el.tagName?.toLowerCase(),
34891
+ id: el.id || null,
34892
+ class: (el.className || '').toString().slice(0, 150),
34893
+ text: text.slice(0, 80),
34894
+ 'aria-label': el.getAttribute('aria-label') || null,
34895
+ disabled: el.disabled || el.getAttribute('disabled') !== null,
34896
+ visible: el.offsetParent !== null,
36029
34897
  rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
36030
- visible: el.offsetParent !== null || el.offsetWidth > 0,
36031
- };
36032
- ${content ? `item.text = (el.textContent || '').trim().slice(0, 200);` : ""}
36033
- ${content ? `item.value = el.value !== undefined ? String(el.value).slice(0, 200) : undefined;` : ""}
36034
- results.push(item);
34898
+ });
36035
34899
  }
36036
- return JSON.stringify({ total: els.length, results });
36037
- } catch(e) {
36038
- return JSON.stringify({ error: e.message });
36039
- }
34900
+ });
34901
+
34902
+ // iframes
34903
+ document.querySelectorAll('iframe, webview').forEach((el, i) => {
34904
+ if (i >= 20) return;
34905
+ result.iframes.push({
34906
+ tag: el.tagName?.toLowerCase(),
34907
+ id: el.id || null,
34908
+ class: (el.className || '').toString().slice(0, 150),
34909
+ src: el.getAttribute('src')?.slice(0, 200) || null,
34910
+ title: el.getAttribute('title') || null,
34911
+ visible: el.offsetParent !== null,
34912
+ rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
34913
+ });
34914
+ });
34915
+
34916
+ return JSON.stringify(result);
36040
34917
  })()`;
36041
34918
  try {
36042
34919
  let raw;
36043
34920
  if (sessionId) {
36044
34921
  raw = await this.getCdp().evaluateInSessionFrame(sessionId, expression);
36045
34922
  } else {
36046
- raw = await this.getCdp().evaluate(expression, 15e3);
34923
+ raw = await this.getCdp().evaluate(expression, 3e4);
36047
34924
  }
36048
34925
  const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
36049
- return { success: true, ...parsed, selector };
34926
+ return { success: true, ...parsed };
36050
34927
  } catch (e) {
36051
34928
  return { success: false, error: e.message };
36052
34929
  }
36053
34930
  }
36054
- /**
36055
- * CDP DOM Debug — IDE AI panel specialized analysis
36056
- * Collect all essential info at once when supporting new IDE
36057
- *
36058
- * args:
36059
- * ideType?: string — IDE type hint
36060
- * sessionId?: string — agent webview session ID
36061
- */
36062
- async handleDomDebug(args) {
36063
- if (!this.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
36064
- const sessionId = args?.sessionId;
36065
- const expression = `(() => {
36066
- const result = {
36067
- url: location.href,
36068
- title: document.title,
36069
- viewport: { w: window.innerWidth, h: window.innerHeight },
36070
-
36071
- // Input field info
36072
- inputs: [],
36073
- // Textarea info
36074
- textareas: [],
36075
- // Contenteditable info
36076
- editables: [],
36077
- // Buttons (send, submit etc)
36078
- buttons: [],
36079
- // iframes (agent webviews)
36080
- iframes: [],
36081
- // role="textbox" info
36082
- textboxes: [],
36083
- };
36084
-
36085
- // Input fields
36086
- document.querySelectorAll('input[type="text"], input:not([type])').forEach((el, i) => {
36087
- if (i >= 10) return;
36088
- result.inputs.push({
36089
- tag: 'input',
36090
- id: el.id || null,
36091
- class: (el.className || '').toString().slice(0, 150),
36092
- placeholder: el.getAttribute('placeholder') || null,
36093
- name: el.name || null,
36094
- value: el.value?.slice(0, 100) || null,
36095
- visible: el.offsetParent !== null,
36096
- rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
36097
- });
36098
- });
36099
-
36100
- // textarea
36101
- document.querySelectorAll('textarea').forEach((el, i) => {
36102
- if (i >= 10) return;
36103
- result.textareas.push({
36104
- id: el.id || null,
36105
- class: (el.className || '').toString().slice(0, 150),
36106
- placeholder: el.getAttribute('placeholder') || null,
36107
- rows: el.rows,
36108
- value: el.value?.slice(0, 100) || null,
36109
- visible: el.offsetParent !== null,
36110
- rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
36111
- });
36112
- });
36113
-
36114
- // contenteditable
36115
- document.querySelectorAll('[contenteditable="true"]').forEach((el, i) => {
36116
- if (i >= 10) return;
36117
- result.editables.push({
36118
- tag: el.tagName?.toLowerCase(),
36119
- id: el.id || null,
36120
- class: (el.className || '').toString().slice(0, 150),
36121
- role: el.getAttribute('role') || null,
36122
- text: (el.textContent || '').trim().slice(0, 100),
36123
- visible: el.offsetParent !== null,
36124
- rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
36125
- });
36126
- });
36127
-
36128
- // role="textbox"
36129
- document.querySelectorAll('[role="textbox"]').forEach((el, i) => {
36130
- if (i >= 10) return;
36131
- result.textboxes.push({
36132
- tag: el.tagName?.toLowerCase(),
36133
- id: el.id || null,
36134
- class: (el.className || '').toString().slice(0, 150),
36135
- 'aria-label': el.getAttribute('aria-label') || null,
36136
- text: (el.textContent || '').trim().slice(0, 100),
36137
- visible: el.offsetParent !== null,
36138
- rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
36139
- });
36140
- });
36141
-
36142
- // Buttons (send, submit, accept, reject, approve etc)
36143
- const btnKeywords = /send|submit|accept|reject|approve|deny|cancel|confirm|run|execute|apply/i;
36144
- document.querySelectorAll('button, [role="button"], input[type="submit"]').forEach((el, i) => {
36145
- const text = (el.textContent || el.getAttribute('aria-label') || '').trim();
36146
- if (i < 30 && (text.length < 30 || btnKeywords.test(text))) {
36147
- result.buttons.push({
36148
- tag: el.tagName?.toLowerCase(),
36149
- id: el.id || null,
36150
- class: (el.className || '').toString().slice(0, 150),
36151
- text: text.slice(0, 80),
36152
- 'aria-label': el.getAttribute('aria-label') || null,
36153
- disabled: el.disabled || el.getAttribute('disabled') !== null,
36154
- visible: el.offsetParent !== null,
36155
- rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
36156
- });
36157
- }
36158
- });
36159
-
36160
- // iframes
36161
- document.querySelectorAll('iframe, webview').forEach((el, i) => {
36162
- if (i >= 20) return;
36163
- result.iframes.push({
36164
- tag: el.tagName?.toLowerCase(),
36165
- id: el.id || null,
36166
- class: (el.className || '').toString().slice(0, 150),
36167
- src: el.getAttribute('src')?.slice(0, 200) || null,
36168
- title: el.getAttribute('title') || null,
36169
- visible: el.offsetParent !== null,
36170
- rect: (() => { try { const r = el.getBoundingClientRect(); return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) }; } catch { return null; } })(),
36171
- });
36172
- });
36173
-
36174
- return JSON.stringify(result);
36175
- })()`;
36176
- try {
36177
- let raw;
36178
- if (sessionId) {
36179
- raw = await this.getCdp().evaluateInSessionFrame(sessionId, expression);
36180
- } else {
36181
- raw = await this.getCdp().evaluate(expression, 3e4);
34931
+ };
34932
+ var crypto2 = __toESM2(require("crypto"));
34933
+ function normalizeInputEnvelope(input) {
34934
+ const normalized = normalizeInputEnvelopePayload(input);
34935
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
34936
+ return {
34937
+ parts: normalized.parts,
34938
+ textFallback,
34939
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
34940
+ };
34941
+ }
34942
+ function normalizeMessageParts(content) {
34943
+ if (typeof content === "string") return [{ type: "text", text: content }];
34944
+ if (!Array.isArray(content)) {
34945
+ if (content && typeof content === "object" && typeof content.text === "string") {
34946
+ return [{ type: "text", text: String(content.text) }];
34947
+ }
34948
+ return [];
34949
+ }
34950
+ const parts = [];
34951
+ for (const raw of content) {
34952
+ if (typeof raw === "string") {
34953
+ parts.push({ type: "text", text: raw });
34954
+ continue;
34955
+ }
34956
+ if (!raw || typeof raw !== "object") continue;
34957
+ const part = normalizeMessagePartObject(raw);
34958
+ if (part) parts.push(part);
34959
+ }
34960
+ return parts;
34961
+ }
34962
+ function flattenMessageParts(parts) {
34963
+ return parts.map((part) => {
34964
+ if (part.type === "text") return part.text;
34965
+ if (part.type === "resource") return part.resource.text || "";
34966
+ return "";
34967
+ }).filter((value) => value.length > 0).join("\n");
34968
+ }
34969
+ function normalizeInputEnvelopePayload(input) {
34970
+ if (typeof input === "string") {
34971
+ return { parts: [{ type: "text", text: input }], textFallback: input };
34972
+ }
34973
+ if (!input || typeof input !== "object") {
34974
+ return { parts: [], textFallback: "" };
34975
+ }
34976
+ const record2 = input;
34977
+ const nestedInput = record2.input;
34978
+ if (nestedInput && typeof nestedInput === "object") {
34979
+ const nested = nestedInput;
34980
+ return {
34981
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
34982
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
34983
+ metadata: normalizeInputMetadata(nested.metadata)
34984
+ };
34985
+ }
34986
+ const directText = typeof record2.text === "string" ? record2.text : typeof record2.message === "string" ? record2.message : void 0;
34987
+ if (directText !== void 0) {
34988
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
34989
+ }
34990
+ const directParts = normalizeInputParts(record2.parts ?? record2.prompt);
34991
+ return {
34992
+ parts: directParts,
34993
+ textFallback: typeof record2.textFallback === "string" ? record2.textFallback : void 0,
34994
+ metadata: normalizeInputMetadata(record2.metadata)
34995
+ };
34996
+ }
34997
+ function normalizeInputMetadata(value) {
34998
+ if (!value || typeof value !== "object") return void 0;
34999
+ const record2 = value;
35000
+ const metadata = {};
35001
+ if (record2.source === "dashboard" || record2.source === "shortcut_api" || record2.source === "provider_script" || record2.source === "session_replay") {
35002
+ metadata.source = record2.source;
35003
+ }
35004
+ if (typeof record2.clientTimestamp === "number" && Number.isFinite(record2.clientTimestamp)) {
35005
+ metadata.clientTimestamp = record2.clientTimestamp;
35006
+ }
35007
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
35008
+ }
35009
+ function normalizeInputParts(value) {
35010
+ if (!Array.isArray(value)) return [];
35011
+ const parts = [];
35012
+ for (const raw of value) {
35013
+ if (typeof raw === "string") {
35014
+ parts.push({ type: "text", text: raw });
35015
+ continue;
35016
+ }
35017
+ if (!raw || typeof raw !== "object") continue;
35018
+ const part = normalizeInputPartObject(raw);
35019
+ if (part) parts.push(part);
35020
+ }
35021
+ return parts;
35022
+ }
35023
+ function normalizeInputPartObject(raw) {
35024
+ const type = raw.type;
35025
+ if (type === "text" && typeof raw.text === "string") {
35026
+ return { type, text: raw.text };
35027
+ }
35028
+ if (type === "image" && typeof raw.mimeType === "string") {
35029
+ return {
35030
+ type,
35031
+ mimeType: raw.mimeType,
35032
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
35033
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
35034
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
35035
+ };
35036
+ }
35037
+ if (type === "audio" && typeof raw.mimeType === "string") {
35038
+ return {
35039
+ type,
35040
+ mimeType: raw.mimeType,
35041
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
35042
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
35043
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
35044
+ };
35045
+ }
35046
+ if (type === "video" && typeof raw.mimeType === "string") {
35047
+ return {
35048
+ type,
35049
+ mimeType: raw.mimeType,
35050
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
35051
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
35052
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
35053
+ };
35054
+ }
35055
+ if (type === "resource" && typeof raw.uri === "string") {
35056
+ return {
35057
+ type,
35058
+ uri: raw.uri,
35059
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
35060
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
35061
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
35062
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
35063
+ };
35064
+ }
35065
+ if (type === "resource_link" && typeof raw.uri === "string") {
35066
+ return {
35067
+ type: "resource",
35068
+ uri: raw.uri,
35069
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
35070
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
35071
+ };
35072
+ }
35073
+ return null;
35074
+ }
35075
+ function normalizeMessagePartObject(raw) {
35076
+ const type = raw.type;
35077
+ if (type === "text" && typeof raw.text === "string") {
35078
+ return { type, text: raw.text };
35079
+ }
35080
+ if (type === "image" && typeof raw.mimeType === "string") {
35081
+ return {
35082
+ type,
35083
+ mimeType: raw.mimeType,
35084
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
35085
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
35086
+ };
35087
+ }
35088
+ if (type === "audio" && typeof raw.mimeType === "string") {
35089
+ return {
35090
+ type,
35091
+ mimeType: raw.mimeType,
35092
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
35093
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
35094
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
35095
+ };
35096
+ }
35097
+ if (type === "video" && typeof raw.mimeType === "string") {
35098
+ return {
35099
+ type,
35100
+ mimeType: raw.mimeType,
35101
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
35102
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
35103
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
35104
+ };
35105
+ }
35106
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
35107
+ return {
35108
+ type,
35109
+ uri: raw.uri,
35110
+ name: raw.name,
35111
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
35112
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
35113
+ };
35114
+ }
35115
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
35116
+ const resource = raw.resource;
35117
+ if (typeof resource.uri !== "string") return null;
35118
+ return {
35119
+ type,
35120
+ resource: {
35121
+ uri: resource.uri,
35122
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
35123
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
35124
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
36182
35125
  }
36183
- const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
36184
- return { success: true, ...parsed };
36185
- } catch (e) {
36186
- return { success: false, error: e.message };
36187
- }
35126
+ };
36188
35127
  }
36189
- };
36190
- var crypto2 = __toESM2(require("crypto"));
36191
- init_contracts();
36192
- init_contracts();
35128
+ return null;
35129
+ }
35130
+ function flattenInputParts(parts) {
35131
+ return parts.map((part) => {
35132
+ if (part.type === "text") return part.text;
35133
+ if (part.type === "audio") return part.transcript || "";
35134
+ if (part.type === "resource") return part.text || "";
35135
+ return "";
35136
+ }).filter((value) => value.length > 0).join("\n");
35137
+ }
35138
+ function flattenContent(content) {
35139
+ if (typeof content === "string") return content;
35140
+ return flattenMessageParts(normalizeMessageParts(content));
35141
+ }
36193
35142
  var DEFAULT_MONITOR_CONFIG = {
36194
35143
  approvalAlert: true,
36195
35144
  longGeneratingAlert: true,
@@ -36300,8 +35249,148 @@ var require_dist2 = __commonJS({
36300
35249
  }
36301
35250
  }
36302
35251
  };
36303
- init_contracts();
36304
- init_chat_message_normalization();
35252
+ var BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
35253
+ var KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
35254
+ var CHAT_MESSAGE_KIND_ALIASES = {
35255
+ text: "standard",
35256
+ message: "standard",
35257
+ assistant: "standard",
35258
+ thinking: "thought",
35259
+ think: "thought",
35260
+ reasoning: "thought",
35261
+ reason: "thought",
35262
+ toolcall: "tool",
35263
+ tool_call: "tool",
35264
+ tooluse: "tool",
35265
+ tool_use: "tool",
35266
+ action: "tool",
35267
+ command: "terminal",
35268
+ cmd: "terminal",
35269
+ shell: "terminal",
35270
+ console: "terminal"
35271
+ };
35272
+ function canonicalizeKindHint(value) {
35273
+ return value.trim().toLowerCase().replace(/[\s-]+/g, "_");
35274
+ }
35275
+ function resolveBuiltinOrAliasKind(kind) {
35276
+ if (typeof kind !== "string") return null;
35277
+ const normalizedKind = canonicalizeKindHint(kind);
35278
+ if (!normalizedKind) return null;
35279
+ if (KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
35280
+ return CHAT_MESSAGE_KIND_ALIASES[normalizedKind] || null;
35281
+ }
35282
+ function inferHintKind(value) {
35283
+ const direct = resolveBuiltinOrAliasKind(value);
35284
+ if (direct) return direct;
35285
+ if (typeof value !== "string") return null;
35286
+ const normalized = canonicalizeKindHint(value);
35287
+ if (!normalized) return null;
35288
+ if (/thought|thinking|reasoning/.test(normalized)) return "thought";
35289
+ if (/tool/.test(normalized)) return "tool";
35290
+ if (/terminal|command|shell|console/.test(normalized)) return "terminal";
35291
+ return null;
35292
+ }
35293
+ function inferKindFromToolCalls(message) {
35294
+ const toolCalls = Array.isArray(message?.toolCalls) ? message.toolCalls : [];
35295
+ if (toolCalls.length === 0) return null;
35296
+ if (toolCalls.some((toolCall) => toolCall?.kind === "think")) return "thought";
35297
+ if (toolCalls.some((toolCall) => toolCall?.kind === "execute")) return "terminal";
35298
+ if (toolCalls.some((toolCall) => Array.isArray(toolCall?.content) && toolCall.content.some((entry) => entry?.type === "terminal"))) {
35299
+ return "terminal";
35300
+ }
35301
+ return "tool";
35302
+ }
35303
+ function inferMissingChatMessageKind(message) {
35304
+ const role = typeof message?.role === "string" ? message.role.trim().toLowerCase() : "";
35305
+ if (role === "system") return "system";
35306
+ const meta3 = message?.meta && typeof message.meta === "object" ? message.meta : void 0;
35307
+ const hintCandidates = [
35308
+ message?._sub,
35309
+ message?._type,
35310
+ meta3?.label,
35311
+ typeof message?.senderName === "string" ? message.senderName : void 0
35312
+ ];
35313
+ for (const candidate of hintCandidates) {
35314
+ const inferred = inferHintKind(candidate);
35315
+ if (inferred) return inferred;
35316
+ }
35317
+ const inferredFromToolCalls = inferKindFromToolCalls(message);
35318
+ if (inferredFromToolCalls) return inferredFromToolCalls;
35319
+ return null;
35320
+ }
35321
+ function isBuiltinChatMessageKind(kind) {
35322
+ return resolveBuiltinOrAliasKind(kind) !== null;
35323
+ }
35324
+ function normalizeChatMessageKind(kind, role) {
35325
+ const resolvedKind = resolveBuiltinOrAliasKind(kind);
35326
+ if (resolvedKind) return resolvedKind;
35327
+ const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
35328
+ return normalizedRole === "system" ? "system" : "standard";
35329
+ }
35330
+ function resolveChatMessageKind(message) {
35331
+ const explicitKind = resolveBuiltinOrAliasKind(message?.kind);
35332
+ if (explicitKind) return explicitKind;
35333
+ const inferredKind = inferMissingChatMessageKind(message);
35334
+ if (inferredKind) return inferredKind;
35335
+ return normalizeChatMessageKind(message?.kind, message?.role);
35336
+ }
35337
+ function buildChatMessage(message) {
35338
+ return {
35339
+ ...message,
35340
+ kind: resolveChatMessageKind(message)
35341
+ };
35342
+ }
35343
+ function buildSystemChatMessage(message) {
35344
+ return buildChatMessage({
35345
+ ...message,
35346
+ role: "system",
35347
+ kind: message?.kind || "system"
35348
+ });
35349
+ }
35350
+ function buildRuntimeSystemChatMessage(message) {
35351
+ return buildSystemChatMessage({
35352
+ ...message,
35353
+ senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
35354
+ });
35355
+ }
35356
+ function buildAssistantChatMessage(message) {
35357
+ return buildChatMessage({
35358
+ ...message,
35359
+ role: "assistant",
35360
+ kind: message?.kind || "standard"
35361
+ });
35362
+ }
35363
+ function buildThoughtChatMessage(message) {
35364
+ return buildAssistantChatMessage({
35365
+ ...message,
35366
+ kind: message?.kind || "thought"
35367
+ });
35368
+ }
35369
+ function buildToolChatMessage(message) {
35370
+ return buildAssistantChatMessage({
35371
+ ...message,
35372
+ kind: message?.kind || "tool"
35373
+ });
35374
+ }
35375
+ function buildTerminalChatMessage(message) {
35376
+ return buildAssistantChatMessage({
35377
+ ...message,
35378
+ kind: message?.kind || "terminal"
35379
+ });
35380
+ }
35381
+ function buildUserChatMessage(message) {
35382
+ return buildChatMessage({
35383
+ ...message,
35384
+ role: "user",
35385
+ kind: message?.kind || "standard"
35386
+ });
35387
+ }
35388
+ function normalizeChatMessage(message) {
35389
+ return buildChatMessage(message);
35390
+ }
35391
+ function normalizeChatMessages(messages) {
35392
+ return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
35393
+ }
36305
35394
  function extractProviderControlValues(controls, data) {
36306
35395
  if (!data || typeof data !== "object") return void 0;
36307
35396
  const values = {};
@@ -36496,7 +35585,6 @@ ${cleanBody}`;
36496
35585
  var fs32 = __toESM2(require("fs"));
36497
35586
  var path10 = __toESM2(require("path"));
36498
35587
  var os52 = __toESM2(require("os"));
36499
- init_chat_message_normalization();
36500
35588
  var HISTORY_DIR = path10.join(os52.homedir(), ".adhdev", "history");
36501
35589
  var RETAIN_DAYS = 30;
36502
35590
  var SAVED_HISTORY_INDEX_VERSION = 1;
@@ -37772,7 +36860,6 @@ ${cleanBody}`;
37772
36860
  })
37773
36861
  };
37774
36862
  }
37775
- init_chat_message_normalization();
37776
36863
  var IDE_PROVIDER_SESSION_CAPABILITIES_BASE = [
37777
36864
  "read_chat",
37778
36865
  "send_message",
@@ -38201,7 +37288,141 @@ ${effect.notification.body || ""}`.trim();
38201
37288
  }
38202
37289
  };
38203
37290
  init_logger();
38204
- init_read_chat_contract();
37291
+ var VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "streaming", "long_generating"];
37292
+ var VALID_ROLES = ["user", "assistant", "system", "human"];
37293
+ var VALID_BUBBLE_STATES = ["draft", "streaming", "final", "removed"];
37294
+ var VALID_TURN_STATUSES = ["open", "waiting_approval", "complete", "error"];
37295
+ function isPlainObject3(value) {
37296
+ return !!value && typeof value === "object" && !Array.isArray(value);
37297
+ }
37298
+ function isFiniteNumber(value) {
37299
+ return typeof value === "number" && Number.isFinite(value);
37300
+ }
37301
+ function validateStatus(status, source) {
37302
+ if (typeof status !== "string" || !VALID_STATUSES.includes(status)) {
37303
+ throw new Error(`${source}: status must be one of ${VALID_STATUSES.join(", ")}`);
37304
+ }
37305
+ return status;
37306
+ }
37307
+ function validateRole(role, source, index) {
37308
+ if (typeof role !== "string" || !VALID_ROLES.includes(role)) {
37309
+ throw new Error(`${source}: messages[${index}].role must be one of ${VALID_ROLES.join(", ")}`);
37310
+ }
37311
+ return role;
37312
+ }
37313
+ function validateBubbleState(state, source, index) {
37314
+ if (typeof state !== "string" || !VALID_BUBBLE_STATES.includes(state)) {
37315
+ throw new Error(`${source}: messages[${index}].bubbleState must be one of ${VALID_BUBBLE_STATES.join(", ")}`);
37316
+ }
37317
+ return state;
37318
+ }
37319
+ function validateTurnStatus(turnStatus, source) {
37320
+ if (typeof turnStatus !== "string" || !VALID_TURN_STATUSES.includes(turnStatus)) {
37321
+ throw new Error(`${source}: turnStatus must be one of ${VALID_TURN_STATUSES.join(", ")}`);
37322
+ }
37323
+ return turnStatus;
37324
+ }
37325
+ function validateMessageContent(content, source, index) {
37326
+ if (typeof content === "string") return content;
37327
+ if (Array.isArray(content)) return normalizeMessageParts(content);
37328
+ throw new Error(`${source}: messages[${index}].content must be a string or structured content array`);
37329
+ }
37330
+ function validateMessage(message, source, index) {
37331
+ if (!isPlainObject3(message)) {
37332
+ throw new Error(`${source}: messages[${index}] must be an object`);
37333
+ }
37334
+ const normalized = {
37335
+ role: validateRole(message.role, source, index),
37336
+ content: validateMessageContent(message.content, source, index)
37337
+ };
37338
+ if (typeof message.kind === "string") normalized.kind = message.kind;
37339
+ if (typeof message.id === "string") normalized.id = message.id;
37340
+ if (typeof message.bubbleId === "string") normalized.bubbleId = message.bubbleId;
37341
+ if (typeof message.providerUnitKey === "string") normalized.providerUnitKey = message.providerUnitKey;
37342
+ if (message.bubbleState !== void 0) normalized.bubbleState = validateBubbleState(message.bubbleState, source, index);
37343
+ if (isFiniteNumber(message.index)) normalized.index = message.index;
37344
+ if (isFiniteNumber(message.timestamp)) normalized.timestamp = message.timestamp;
37345
+ if (isFiniteNumber(message.receivedAt)) normalized.receivedAt = message.receivedAt;
37346
+ if (typeof message._turnKey === "string") normalized._turnKey = message._turnKey;
37347
+ if (Array.isArray(message.toolCalls)) normalized.toolCalls = message.toolCalls;
37348
+ if (isPlainObject3(message.meta)) normalized.meta = message.meta;
37349
+ if (typeof message.senderName === "string") normalized.senderName = message.senderName;
37350
+ if (typeof message._type === "string") normalized._type = message._type;
37351
+ if (typeof message._sub === "string") normalized._sub = message._sub;
37352
+ return normalized;
37353
+ }
37354
+ function validateModal(activeModal, status, source) {
37355
+ if (activeModal == null) {
37356
+ if (status === "waiting_approval") {
37357
+ throw new Error(`${source}: waiting_approval status requires activeModal with buttons`);
37358
+ }
37359
+ return activeModal === null ? null : void 0;
37360
+ }
37361
+ if (!isPlainObject3(activeModal)) {
37362
+ throw new Error(`${source}: activeModal must be an object when provided`);
37363
+ }
37364
+ if (typeof activeModal.message !== "string") {
37365
+ throw new Error(`${source}: activeModal.message must be a string`);
37366
+ }
37367
+ if (!Array.isArray(activeModal.buttons) || activeModal.buttons.some((button) => typeof button !== "string" || !button.trim())) {
37368
+ throw new Error(`${source}: activeModal.buttons must be a non-empty string array`);
37369
+ }
37370
+ const normalized = {
37371
+ message: activeModal.message,
37372
+ buttons: activeModal.buttons.map((button) => button.trim())
37373
+ };
37374
+ if (isFiniteNumber(activeModal.width)) normalized.width = activeModal.width;
37375
+ if (isFiniteNumber(activeModal.height)) normalized.height = activeModal.height;
37376
+ return normalized;
37377
+ }
37378
+ function validateControlValues(controlValues, source) {
37379
+ if (controlValues === void 0) return void 0;
37380
+ if (!isPlainObject3(controlValues)) {
37381
+ throw new Error(`${source}: controlValues must be an object when provided`);
37382
+ }
37383
+ const normalized = {};
37384
+ for (const [key, value] of Object.entries(controlValues)) {
37385
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
37386
+ throw new Error(`${source}: controlValues.${key} must be string, number, or boolean`);
37387
+ }
37388
+ normalized[key] = value;
37389
+ }
37390
+ return normalized;
37391
+ }
37392
+ function validateReadChatResultPayload(raw, source = "read_chat") {
37393
+ if (!isPlainObject3(raw)) {
37394
+ throw new Error(`${source}: payload must be an object`);
37395
+ }
37396
+ const status = validateStatus(raw.status, source);
37397
+ if (!Array.isArray(raw.messages)) {
37398
+ throw new Error(`${source}: messages must be an array`);
37399
+ }
37400
+ const messages = raw.messages.map((message, index) => validateMessage(message, source, index));
37401
+ const activeModal = validateModal(raw.activeModal, status, source);
37402
+ const controlValues = validateControlValues(raw.controlValues, source);
37403
+ const normalized = {
37404
+ status,
37405
+ messages
37406
+ };
37407
+ if (activeModal !== void 0) normalized.activeModal = activeModal;
37408
+ if (typeof raw.id === "string") normalized.id = raw.id;
37409
+ if (typeof raw.title === "string") normalized.title = raw.title;
37410
+ if (typeof raw.currentTurnId === "string") normalized.currentTurnId = raw.currentTurnId;
37411
+ if (raw.turnStatus !== void 0) normalized.turnStatus = validateTurnStatus(raw.turnStatus, source);
37412
+ if (typeof raw.agentType === "string") normalized.agentType = raw.agentType;
37413
+ if (typeof raw.agentName === "string") normalized.agentName = raw.agentName;
37414
+ if (typeof raw.extensionId === "string") normalized.extensionId = raw.extensionId;
37415
+ if (typeof raw.inputContent === "string") normalized.inputContent = raw.inputContent;
37416
+ if (typeof raw.isVisible === "boolean") normalized.isVisible = raw.isVisible;
37417
+ if (typeof raw.isWelcomeScreen === "boolean") normalized.isWelcomeScreen = raw.isWelcomeScreen;
37418
+ if (controlValues) normalized.controlValues = controlValues;
37419
+ if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
37420
+ if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
37421
+ if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
37422
+ if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
37423
+ if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
37424
+ return normalized;
37425
+ }
38205
37426
  var DEFAULT_APPROVAL_POSITIVE_HINTS = [
38206
37427
  "yes",
38207
37428
  "allow once",
@@ -38247,7 +37468,6 @@ ${effect.notification.body || ""}`.trim();
38247
37468
  if (cleanMessage) lines.push(cleanMessage);
38248
37469
  return lines.join("\n");
38249
37470
  }
38250
- init_chat_message_normalization();
38251
37471
  var IdeProviderInstance = class {
38252
37472
  type;
38253
37473
  category = "ide";
@@ -39688,7 +38908,6 @@ ${effect.notification.body || ""}`.trim();
39688
38908
  var os62 = __toESM2(require("os"));
39689
38909
  var path11 = __toESM2(require("path"));
39690
38910
  var import_node_crypto = require("crypto");
39691
- init_contracts();
39692
38911
  var VALID_INPUT_MEDIA_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "resource"]);
39693
38912
  function getProviderLabel(provider) {
39694
38913
  return provider?.name || provider?.type || "This provider";
@@ -39742,7 +38961,6 @@ ${effect.notification.body || ""}`.trim();
39742
38961
  throw new Error(`${label} does not support multipart input`);
39743
38962
  }
39744
38963
  }
39745
- init_read_chat_contract();
39746
38964
  init_logger();
39747
38965
  init_debug_config();
39748
38966
  function summarizeString(value) {
@@ -39866,10 +39084,6 @@ ${effect.notification.body || ""}`.trim();
39866
39084
  payload.historySessionId || "",
39867
39085
  payload.status,
39868
39086
  payload.title || "",
39869
- payload.syncMode,
39870
- String(payload.replaceFrom),
39871
- String(payload.totalMessages),
39872
- payload.lastMessageSignature,
39873
39087
  payload.activeModal ? `${payload.activeModal.message}|${payload.activeModal.buttons.join("")}` : "",
39874
39088
  stringifySignatureMessages(payload.messages)
39875
39089
  ]);
@@ -39883,7 +39097,6 @@ ${effect.notification.body || ""}`.trim();
39883
39097
  Array.isArray(payload.modalButtons) ? payload.modalButtons.join("") : ""
39884
39098
  ]);
39885
39099
  }
39886
- init_chat_message_normalization();
39887
39100
  var RECENT_SEND_WINDOW_MS = 1200;
39888
39101
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
39889
39102
  var recentSendByTarget = /* @__PURE__ */ new Map();
@@ -39984,99 +39197,13 @@ ${effect.notification.body || ""}`.trim();
39984
39197
  return value;
39985
39198
  }
39986
39199
  }
39987
- function getChatMessageSignature(message) {
39988
- return buildChatMessageSignature(message);
39989
- }
39990
- function normalizeReadChatCursor(args) {
39991
- const knownMessageCount = Math.max(0, Number(args?.knownMessageCount || 0));
39992
- const lastMessageSignature = typeof args?.lastMessageSignature === "string" ? args.lastMessageSignature : "";
39993
- const tailLimit = Math.max(0, Number(args?.tailLimit || 0));
39994
- return { knownMessageCount, lastMessageSignature, tailLimit };
39200
+ function normalizeReadChatTailLimit(args) {
39201
+ const value = Number(args?.tailLimit || 0);
39202
+ return Number.isFinite(value) ? Math.max(0, value) : 0;
39995
39203
  }
39996
39204
  function normalizeReadChatMessages(payload) {
39997
39205
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
39998
- return normalizeChatMessages(messages);
39999
- }
40000
- function normalizeReadChatReplayTextContent(content) {
40001
- return flattenContent(content || "").replace(/\s+/g, " ").trim();
40002
- }
40003
- function getReadChatReplayCollapseInfo(message) {
40004
- if (!message) return null;
40005
- const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
40006
- const kind = typeof message.kind === "string" ? message.kind.trim().toLowerCase() : "standard";
40007
- const senderName = typeof message.senderName === "string" ? message.senderName.trim().toLowerCase() : "";
40008
- const collapsible = role === "assistant" || role === "system";
40009
- if (!collapsible) return { role, kind, senderName, content: "", signature: "", collapsible };
40010
- const content = normalizeReadChatReplayTextContent(message.content);
40011
- return {
40012
- role,
40013
- kind,
40014
- senderName,
40015
- content,
40016
- signature: `${role}:${kind}:${senderName}:${content}`,
40017
- collapsible
40018
- };
40019
- }
40020
- function isStableReadChatAssistantAnswerInfo(info) {
40021
- if (!info) return false;
40022
- if (info.role !== "assistant") return false;
40023
- if (info.kind && info.kind !== "standard") return false;
40024
- if (info.content.length < 160) return false;
40025
- if (/^(bash|shell|terminal) command\b/i.test(info.content)) return false;
40026
- return true;
40027
- }
40028
- function isReplayedAssistantAnswerAfterStableAnswerInfo(info, stableContent) {
40029
- if (!info || !stableContent) return false;
40030
- if (info.role !== "assistant") return false;
40031
- if (info.kind && info.kind !== "standard") return false;
40032
- const content = info.content;
40033
- if (content.length < 80 || stableContent.length < 80) return false;
40034
- return content === stableContent || content.startsWith(stableContent) || stableContent.startsWith(content);
40035
- }
40036
- function collapseReplayDuplicatesFromReadChat(messages) {
40037
- const collapsed = [];
40038
- const replaySignaturesInCurrentTurn = /* @__PURE__ */ new Set();
40039
- let stableAssistantAnswerContentInCurrentTurn = "";
40040
- let stableAssistantAnswerCollapsedIndex = -1;
40041
- let stableAssistantAnswerHadInterveningActivity = false;
40042
- let previousReplaySignature = "";
40043
- for (const message of messages) {
40044
- const info = getReadChatReplayCollapseInfo(message);
40045
- if (info?.role === "user") {
40046
- replaySignaturesInCurrentTurn.clear();
40047
- stableAssistantAnswerContentInCurrentTurn = "";
40048
- stableAssistantAnswerCollapsedIndex = -1;
40049
- stableAssistantAnswerHadInterveningActivity = false;
40050
- previousReplaySignature = "";
40051
- }
40052
- if (info?.collapsible && info.signature) {
40053
- if (previousReplaySignature === info.signature) continue;
40054
- if (replaySignaturesInCurrentTurn.has(info.signature)) continue;
40055
- if (isReplayedAssistantAnswerAfterStableAnswerInfo(info, stableAssistantAnswerContentInCurrentTurn)) {
40056
- const isAdjacentFullerAssistantAnswer = info.role === "assistant" && (!info.kind || info.kind === "standard") && stableAssistantAnswerCollapsedIndex >= 0 && stableAssistantAnswerCollapsedIndex === collapsed.length - 1 && !stableAssistantAnswerHadInterveningActivity && info.content.length > stableAssistantAnswerContentInCurrentTurn.length && info.content.startsWith(stableAssistantAnswerContentInCurrentTurn);
40057
- if (isAdjacentFullerAssistantAnswer) {
40058
- collapsed[stableAssistantAnswerCollapsedIndex] = message;
40059
- replaySignaturesInCurrentTurn.add(info.signature);
40060
- stableAssistantAnswerContentInCurrentTurn = info.content;
40061
- previousReplaySignature = info.signature;
40062
- }
40063
- continue;
40064
- }
40065
- }
40066
- collapsed.push(message);
40067
- previousReplaySignature = info?.collapsible ? info.signature : "";
40068
- if (info?.collapsible && info.signature) {
40069
- replaySignaturesInCurrentTurn.add(info.signature);
40070
- }
40071
- if (isStableReadChatAssistantAnswerInfo(info)) {
40072
- stableAssistantAnswerContentInCurrentTurn = info?.content || "";
40073
- stableAssistantAnswerCollapsedIndex = collapsed.length - 1;
40074
- stableAssistantAnswerHadInterveningActivity = false;
40075
- } else if (stableAssistantAnswerContentInCurrentTurn && info?.role === "assistant" && (!info.kind || info.kind !== "standard")) {
40076
- stableAssistantAnswerHadInterveningActivity = true;
40077
- }
40078
- }
40079
- return collapsed;
39206
+ return messages;
40080
39207
  }
40081
39208
  function deriveHistoryDedupKey(message) {
40082
39209
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -40101,127 +39228,12 @@ ${effect.notification.body || ""}`.trim();
40101
39228
  historyDedupKey: deriveHistoryDedupKey(message)
40102
39229
  }));
40103
39230
  }
40104
- function findLastMessageIndexBySignature(messages, signature) {
40105
- if (!signature) return -1;
40106
- for (let index = messages.length - 1; index >= 0; index -= 1) {
40107
- if (getChatMessageSignature(messages[index]) === signature) {
40108
- return index;
40109
- }
40110
- }
40111
- return -1;
40112
- }
40113
- function isReadChatConversationAnchorMessage(message) {
40114
- if (!message) return false;
40115
- const role = String(message.role || "").trim().toLowerCase();
40116
- if (role !== "user" && role !== "assistant") return false;
40117
- const kind = String(message.kind || "standard").trim().toLowerCase();
40118
- return !kind || kind === "standard";
40119
- }
40120
- function buildVisibleReadChatTailMessages(messages, tailLimit) {
40121
- const totalMessages = messages.length;
40122
- if (tailLimit <= 0 || totalMessages <= tailLimit) return messages;
40123
- const tailMessages = messages.slice(-tailLimit);
40124
- if (tailMessages.some(isReadChatConversationAnchorMessage)) return tailMessages;
40125
- const hiddenMessages = messages.slice(0, totalMessages - tailLimit);
40126
- const anchors = [];
40127
- const seenRoles = /* @__PURE__ */ new Set();
40128
- for (let index = hiddenMessages.length - 1; index >= 0 && anchors.length < 2; index -= 1) {
40129
- const message = hiddenMessages[index];
40130
- if (!isReadChatConversationAnchorMessage(message)) continue;
40131
- const role = String(message.role || "").trim().toLowerCase();
40132
- if (seenRoles.has(role)) continue;
40133
- seenRoles.add(role);
40134
- anchors.unshift(message);
40135
- }
40136
- return anchors.length > 0 ? [...anchors, ...tailMessages] : tailMessages;
40137
- }
40138
- function buildBoundedTailSync(messages, cursor) {
39231
+ function buildFullTail(messages, tailLimit) {
40139
39232
  const totalMessages = messages.length;
40140
- const tailMessages = buildVisibleReadChatTailMessages(messages, cursor.tailLimit);
39233
+ const tailMessages = tailLimit > 0 ? messages.slice(-tailLimit) : messages;
40141
39234
  return {
40142
- syncMode: "full",
40143
- replaceFrom: 0,
40144
39235
  messages: tailMessages,
40145
- totalMessages,
40146
- lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1])
40147
- };
40148
- }
40149
- function computeReadChatSync(messages, cursor) {
40150
- const totalMessages = messages.length;
40151
- const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
40152
- const { knownMessageCount, lastMessageSignature: knownSignature } = cursor;
40153
- if (!knownMessageCount || !knownSignature) {
40154
- return {
40155
- syncMode: "full",
40156
- replaceFrom: 0,
40157
- messages,
40158
- totalMessages,
40159
- lastMessageSignature
40160
- };
40161
- }
40162
- if (knownMessageCount > totalMessages) {
40163
- return {
40164
- syncMode: "full",
40165
- replaceFrom: 0,
40166
- messages,
40167
- totalMessages,
40168
- lastMessageSignature
40169
- };
40170
- }
40171
- if (knownMessageCount === totalMessages && knownSignature === lastMessageSignature) {
40172
- return {
40173
- syncMode: "noop",
40174
- replaceFrom: totalMessages,
40175
- messages: [],
40176
- totalMessages,
40177
- lastMessageSignature
40178
- };
40179
- }
40180
- if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
40181
- const requestedTailCount = Math.min(totalMessages, cursor.tailLimit);
40182
- if (knownMessageCount >= requestedTailCount) {
40183
- return {
40184
- syncMode: "noop",
40185
- replaceFrom: totalMessages,
40186
- messages: [],
40187
- totalMessages,
40188
- lastMessageSignature
40189
- };
40190
- }
40191
- return buildBoundedTailSync(messages, cursor);
40192
- }
40193
- if (knownMessageCount < totalMessages) {
40194
- const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
40195
- if (anchorSignature === knownSignature) {
40196
- return {
40197
- syncMode: "append",
40198
- replaceFrom: knownMessageCount,
40199
- messages: messages.slice(knownMessageCount),
40200
- totalMessages,
40201
- lastMessageSignature
40202
- };
40203
- }
40204
- if (cursor.tailLimit > 0) {
40205
- const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
40206
- if (signatureIndex >= 0) {
40207
- return {
40208
- syncMode: "append",
40209
- replaceFrom: knownMessageCount,
40210
- messages: messages.slice(signatureIndex + 1),
40211
- totalMessages,
40212
- lastMessageSignature
40213
- };
40214
- }
40215
- return buildBoundedTailSync(messages, cursor);
40216
- }
40217
- }
40218
- const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
40219
- return {
40220
- syncMode: replaceFrom === 0 ? "full" : "replace_tail",
40221
- replaceFrom,
40222
- messages: replaceFrom === 0 ? messages : messages.slice(replaceFrom),
40223
- totalMessages,
40224
- lastMessageSignature
39236
+ totalMessages
40225
39237
  };
40226
39238
  }
40227
39239
  function hasNonEmptyModalButtons(activeModal) {
@@ -40256,31 +39268,13 @@ ${effect.notification.body || ""}`.trim();
40256
39268
  } catch (error48) {
40257
39269
  return { success: false, error: error48?.message || String(error48) };
40258
39270
  }
40259
- const messages = collapseReplayDuplicatesFromReadChat(normalizeReadChatMessages(validatedPayload));
40260
- const cursor = normalizeReadChatCursor(args);
40261
- if (!cursor.knownMessageCount && !cursor.lastMessageSignature && cursor.tailLimit > 0 && messages.length > cursor.tailLimit) {
40262
- const tailMessages = buildVisibleReadChatTailMessages(messages, cursor.tailLimit);
40263
- const lastMessageSignature = getChatMessageSignature(messages[messages.length - 1]);
40264
- return {
40265
- success: true,
40266
- ...validatedPayload,
40267
- messages: tailMessages,
40268
- syncMode: "full",
40269
- replaceFrom: 0,
40270
- totalMessages: messages.length,
40271
- lastMessageSignature,
40272
- ...debugReadChat ? { debugReadChat } : {}
40273
- };
40274
- }
40275
- const sync = computeReadChatSync(messages, cursor);
39271
+ const messages = normalizeReadChatMessages(validatedPayload);
39272
+ const sync = buildFullTail(messages, normalizeReadChatTailLimit(args));
40276
39273
  return {
40277
39274
  success: true,
40278
39275
  ...validatedPayload,
40279
39276
  messages: sync.messages,
40280
- syncMode: sync.syncMode,
40281
- replaceFrom: sync.replaceFrom,
40282
39277
  totalMessages: sync.totalMessages,
40283
- lastMessageSignature: sync.lastMessageSignature,
40284
39278
  ...debugReadChat ? { debugReadChat } : {}
40285
39279
  };
40286
39280
  }
@@ -40505,10 +39499,6 @@ ${effect.notification.body || ""}`.trim();
40505
39499
  status: readResult.status,
40506
39500
  title: readResult.title,
40507
39501
  totalMessages: readResult.totalMessages,
40508
- returnedMessages: Array.isArray(readResult.messages) ? readResult.messages.length : void 0,
40509
- syncMode: readResult.syncMode,
40510
- replaceFrom: readResult.replaceFrom,
40511
- lastMessageSignature: readResult.lastMessageSignature,
40512
39502
  providerSessionId: readResult.providerSessionId,
40513
39503
  transcriptAuthority: readResult.transcriptAuthority,
40514
39504
  coverage: readResult.coverage,
@@ -40618,22 +39608,13 @@ ${effect.notification.body || ""}`.trim();
40618
39608
  return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
40619
39609
  }
40620
39610
  function getCliVisibleTranscriptCount(adapter) {
40621
- const adapterStatus = adapter?.getStatus?.() || {};
40622
- const adapterMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
40623
- let parsedRecord = null;
40624
- if (typeof adapter?.getScriptParsedStatus === "function") {
40625
- try {
40626
- const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
40627
- parsedRecord = parsed && typeof parsed === "object" ? parsed : null;
40628
- } catch {
40629
- parsedRecord = null;
40630
- }
39611
+ if (typeof adapter?.getScriptParsedStatus !== "function") return 0;
39612
+ try {
39613
+ const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
39614
+ return Array.isArray(parsed?.messages) ? parsed.messages.length : 0;
39615
+ } catch {
39616
+ return 0;
40631
39617
  }
40632
- const parsedMessages = Array.isArray(parsedRecord?.messages) ? parsedRecord.messages : [];
40633
- if (!parsedRecord) return adapterMessages.length;
40634
- const parsedIsProviderAuthoritative = parsedRecord.transcriptAuthority === "provider" || parsedRecord.coverage === "full";
40635
- const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && adapterMessages.length > 0 && adapterMessages.length > parsedMessages.length;
40636
- return shouldPreferAdapterMessages ? adapterMessages.length : parsedMessages.length;
40637
39618
  }
40638
39619
  async function getStableExtensionBaseline(h) {
40639
39620
  const first = await readExtensionChatState(h);
@@ -40695,52 +39676,46 @@ ${effect.notification.body || ""}`.trim();
40695
39676
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
40696
39677
  if (adapter) {
40697
39678
  _log(`${transport} adapter: ${adapter.cliType}`);
39679
+ if (typeof adapter.getScriptParsedStatus !== "function") {
39680
+ return { success: false, error: `${transport} adapter parseSession unavailable` };
39681
+ }
40698
39682
  let parsedStatus = null;
40699
- if (typeof adapter.getScriptParsedStatus === "function") {
40700
- try {
40701
- parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
40702
- } catch (error48) {
40703
- return { success: false, error: error48?.message || String(error48) };
40704
- }
39683
+ try {
39684
+ parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
39685
+ } catch (error48) {
39686
+ return { success: false, error: error48?.message || String(error48) };
40705
39687
  }
40706
39688
  const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
40707
- const adapterStatus = adapter.getStatus();
40708
- const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.coverage === "full";
40709
- const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
40710
- const parsedShowsApproval = hasNonEmptyModalButtons(parsedRecord?.activeModal) && parsedRecord?.status === "waiting_approval";
40711
- const status = parsedRecord ? {
40712
- ...parsedRecord,
40713
- messages: shouldPreferAdapterMessages ? adapterStatus.messages : parsedRecord.messages,
40714
- status: parsedShowsApproval ? parsedRecord.status : adapterStatus.status !== "idle" ? adapterStatus.status : parsedRecord.status || adapterStatus.status,
40715
- activeModal: parsedRecord.activeModal || adapterStatus.activeModal
40716
- } : adapterStatus;
40717
- const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
40718
- const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
40719
- const transcriptAuthority = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
40720
- const coverage = parsedRecord?.coverage === "full" || parsedRecord?.coverage === "tail" || parsedRecord?.coverage === "current-turn" ? parsedRecord.coverage : void 0;
40721
- if (status) {
40722
- LOG2.debug("Command", `[read_chat] cli-like resolved provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord?.status || "")} shouldPreferAdapterMessages=${String(shouldPreferAdapterMessages)} adapterMsgCount=${Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0} parsedMsgCount=${Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0} returnedMsgCount=${Array.isArray(status.messages) ? status.messages.length : 0}`);
40723
- return buildReadChatCommandResult({
40724
- messages: status.messages || [],
40725
- status: status.status,
40726
- activeModal: status.activeModal,
40727
- debugReadChat: {
40728
- provider: adapter.cliType,
40729
- targetSessionId: String(args?.targetSessionId || ""),
40730
- adapterStatus: String(adapterStatus.status || ""),
40731
- parsedStatus: String(parsedRecord?.status || ""),
40732
- returnedStatus: String(status.status || ""),
40733
- shouldPreferAdapterMessages,
40734
- adapterMsgCount: Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0,
40735
- parsedMsgCount: Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0,
40736
- returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
40737
- },
40738
- ...title ? { title } : {},
40739
- ...providerSessionId ? { providerSessionId } : {},
40740
- ...transcriptAuthority ? { transcriptAuthority } : {},
40741
- ...coverage ? { coverage } : {}
40742
- }, args);
40743
- }
39689
+ if (!parsedRecord || !Array.isArray(parsedRecord.messages)) {
39690
+ return { success: false, error: `${transport} parser did not return messages` };
39691
+ }
39692
+ const adapterStatus = typeof adapter.getStatus === "function" ? adapter.getStatus() : {};
39693
+ const title = typeof parsedRecord.title === "string" ? parsedRecord.title : void 0;
39694
+ const providerSessionId = typeof parsedRecord.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
39695
+ const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
39696
+ const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
39697
+ const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
39698
+ const returnedStatus = parsedRecord.status || "idle";
39699
+ LOG2.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length}`);
39700
+ return buildReadChatCommandResult({
39701
+ messages: parsedRecord.messages,
39702
+ status: returnedStatus,
39703
+ activeModal,
39704
+ debugReadChat: {
39705
+ provider: adapter.cliType,
39706
+ targetSessionId: String(args?.targetSessionId || ""),
39707
+ adapterStatus: String(adapterStatus.status || ""),
39708
+ parsedStatus: String(parsedRecord.status || ""),
39709
+ returnedStatus: String(returnedStatus || ""),
39710
+ shouldPreferAdapterMessages: false,
39711
+ parsedMsgCount: parsedRecord.messages.length,
39712
+ returnedMsgCount: parsedRecord.messages.length
39713
+ },
39714
+ ...title ? { title } : {},
39715
+ ...providerSessionId ? { providerSessionId } : {},
39716
+ ...transcriptAuthority ? { transcriptAuthority } : {},
39717
+ ...coverage ? { coverage } : {}
39718
+ }, args);
40744
39719
  }
40745
39720
  return { success: false, error: `${transport} adapter not found` };
40746
39721
  }
@@ -43026,7 +42001,6 @@ ${effect.notification.body || ""}`.trim();
43026
42001
  var crypto3 = __toESM2(require("crypto"));
43027
42002
  var fs6 = __toESM2(require("fs"));
43028
42003
  var import_node_module = require("module");
43029
- init_contracts();
43030
42004
  init_provider_cli_adapter();
43031
42005
  init_logger();
43032
42006
  function normalizeProviderSessionId(provider, providerSessionId) {
@@ -43044,7 +42018,6 @@ ${effect.notification.body || ""}`.trim();
43044
42018
  }
43045
42019
  return normalizedId;
43046
42020
  }
43047
- init_chat_message_normalization();
43048
42021
  function normalizePersistableCliHistoryContent(content) {
43049
42022
  return flattenContent(content).replace(/\s+/g, " ").trim();
43050
42023
  }
@@ -43284,17 +42257,11 @@ ${effect.notification.body || ""}`.trim();
43284
42257
  }
43285
42258
  const runtime = this.adapter.getRuntimeMetadata();
43286
42259
  this.maybeAppendRuntimeRecoveryMessage(runtime);
43287
- let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : parseErrorMessage ? normalizeChatMessages(Array.isArray(adapterStatus.messages) ? adapterStatus.messages : []) : [];
42260
+ let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
43288
42261
  const historyMessageCount = Number.isFinite(parsedStatus?.historyMessageCount) ? Math.max(0, Number(parsedStatus.historyMessageCount)) : null;
43289
42262
  if (historyMessageCount !== null) {
43290
42263
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
43291
42264
  }
43292
- const committedMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
43293
- const isActiveNonIdle = adapterStatus.status !== "idle";
43294
- const shouldApplyCommittedFloor = parsedMessages.length < committedMessages.length && (adapterStatus.status === "waiting_approval" || isActiveNonIdle && historyMessageCount === null);
43295
- if (shouldApplyCommittedFloor) {
43296
- parsedMessages = normalizeChatMessages(committedMessages);
43297
- }
43298
42265
  const mergedMessages = this.mergeConversationMessages(parsedMessages);
43299
42266
  const canonicalBackedHistory = this.syncCanonicalSavedHistoryIfNeeded();
43300
42267
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
@@ -43387,11 +42354,9 @@ ${effect.notification.body || ""}`.trim();
43387
42354
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
43388
42355
  const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
43389
42356
  const runtime = this.adapter.getRuntimeMetadata();
43390
- const lastCommittedMessageActivityAt = typeof this.adapter.getLastCommittedMessageActivityAt === "function" ? this.adapter.getLastCommittedMessageActivityAt() : 0;
43391
42357
  return {
43392
42358
  id: this.instanceId,
43393
42359
  status: visibleStatus,
43394
- lastMessageAt: lastCommittedMessageActivityAt || void 0,
43395
42360
  runtimeLifecycle: runtime?.lifecycle ?? null,
43396
42361
  runtimeSurfaceKind: runtime?.surfaceKind,
43397
42362
  runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
@@ -43497,7 +42462,7 @@ ${effect.notification.body || ""}`.trim();
43497
42462
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
43498
42463
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
43499
42464
  const partial2 = this.adapter.getPartialResponse();
43500
- const progressFingerprint = newStatus === "generating" ? `${partial2 || ""}::${adapterStatus.messages.at(-1)?.content || ""}`.slice(-2e3) : void 0;
42465
+ const progressFingerprint = newStatus === "generating" ? `${partial2 || ""}`.slice(-2e3) : void 0;
43501
42466
  const previousStatus = this.lastStatus;
43502
42467
  if (newStatus !== this.lastStatus) {
43503
42468
  LOG2.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
@@ -43943,18 +42908,6 @@ ${effect.notification.body || ""}`.trim();
43943
42908
  receivedAt: message.receivedAt
43944
42909
  }));
43945
42910
  this.suppressIdleHistoryReplay = restoredHistory.messages.length > 0;
43946
- if (restoredHistory.messages.length > 0) {
43947
- this.adapter.seedCommittedMessages(
43948
- restoredHistory.messages.map((message) => ({
43949
- role: message.role,
43950
- content: message.content,
43951
- timestamp: message.receivedAt,
43952
- receivedAt: message.receivedAt,
43953
- kind: message.kind,
43954
- senderName: message.senderName
43955
- }))
43956
- );
43957
- }
43958
42911
  }
43959
42912
  getProbeDirectories() {
43960
42913
  const dirs = /* @__PURE__ */ new Set();
@@ -44002,8 +42955,6 @@ ${effect.notification.body || ""}`.trim();
44002
42955
  var import_stream = require("stream");
44003
42956
  var import_child_process5 = require("child_process");
44004
42957
  var import_sdk = (init_acp(), __toCommonJS(acp_exports));
44005
- init_contracts();
44006
- init_chat_message_normalization();
44007
42958
  init_logger();
44008
42959
  function getPromptCapabilityFlags(agentCapabilities) {
44009
42960
  const prompt = agentCapabilities?.promptCapabilities || {};
@@ -45145,7 +44096,6 @@ ${rawInput}` : rawInput;
45145
44096
  return this.agentCapabilities;
45146
44097
  }
45147
44098
  };
45148
- init_contracts();
45149
44099
  init_logger();
45150
44100
  function shouldRestoreHostedRuntime(record2, managerTag) {
45151
44101
  if (!managerTag) return true;
@@ -48063,13 +47013,24 @@ Run 'adhdev doctor' for detailed diagnostics.`
48063
47013
  break;
48064
47014
  }
48065
47015
  }
47016
+ if (!cdpReady) {
47017
+ return {
47018
+ success: false,
47019
+ ideId: targetIde.id,
47020
+ ideName: targetIde.displayName,
47021
+ port,
47022
+ action: "failed",
47023
+ message: "",
47024
+ error: `${targetIde.displayName} launched but CDP did not become available on port ${port}`
47025
+ };
47026
+ }
48066
47027
  return {
48067
47028
  success: true,
48068
47029
  ideId: targetIde.id,
48069
47030
  ideName: targetIde.displayName,
48070
47031
  port,
48071
47032
  action: alreadyRunning ? "restarted" : "started",
48072
- message: cdpReady ? `${targetIde.displayName} launched with CDP on port ${port}` : `${targetIde.displayName} launched (CDP may take a moment to initialize)`
47033
+ message: `${targetIde.displayName} launched with CDP on port ${port}`
48073
47034
  };
48074
47035
  } catch (e) {
48075
47036
  return {
@@ -49977,9 +48938,6 @@ Run 'adhdev doctor' for detailed diagnostics.`
49977
48938
  init_debug_config();
49978
48939
  var DEFAULT_DAEMON_PORT = 19222;
49979
48940
  var DAEMON_WS_PATH = "/ipc";
49980
- function normalizeSyncMode(syncMode) {
49981
- return syncMode === "append" || syncMode === "replace_tail" || syncMode === "noop" || syncMode === "full" ? syncMode : "full";
49982
- }
49983
48941
  function normalizeModalButtons(value) {
49984
48942
  return Array.isArray(value) ? value.filter((button) => typeof button === "string") : [];
49985
48943
  }
@@ -50006,55 +48964,39 @@ Run 'adhdev doctor' for detailed diagnostics.`
50006
48964
  modalButtons: normalizeModalButtons(activeModal.buttons)
50007
48965
  };
50008
48966
  }
50009
- function buildNextChatCursor(cursor, result) {
50010
- return {
50011
- knownMessageCount: Math.max(0, Number(result.totalMessages || cursor.knownMessageCount)),
50012
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : cursor.lastMessageSignature,
50013
- tailLimit: cursor.tailLimit
50014
- };
50015
- }
50016
48967
  function prepareSessionChatTailUpdate2(input) {
50017
48968
  const result = input.result;
50018
- if (!result?.success || result.syncMode === "noop") {
48969
+ if (!result?.success) {
50019
48970
  return {
50020
- cursor: result?.success ? buildNextChatCursor(input.cursor, result) : input.cursor,
48971
+ cursor: input.cursor,
50021
48972
  seq: input.seq,
50022
48973
  lastDeliveredSignature: input.lastDeliveredSignature,
50023
48974
  update: null
50024
48975
  };
50025
48976
  }
50026
- const syncMode = normalizeSyncMode(result.syncMode);
50027
- const cursor = {
50028
- knownMessageCount: Math.max(0, Number(result.totalMessages || 0)),
50029
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : "",
50030
- tailLimit: input.cursor.tailLimit
50031
- };
48977
+ const messages = Array.isArray(result.messages) ? result.messages : [];
50032
48978
  const title = typeof result.title === "string" ? result.title : void 0;
50033
48979
  const activeModal = normalizeChatTailActiveModal(result.activeModal);
50034
48980
  const status = typeof result.status === "string" ? result.status : "idle";
50035
48981
  const deliverySignature = buildChatTailDeliverySignature({
50036
48982
  sessionId: input.sessionId,
50037
48983
  ...input.historySessionId ? { historySessionId: input.historySessionId } : {},
50038
- messages: Array.isArray(result.messages) ? result.messages : [],
48984
+ messages,
50039
48985
  status,
50040
48986
  ...title ? { title } : {},
50041
- ...activeModal ? { activeModal } : {},
50042
- syncMode,
50043
- replaceFrom: Number(result.replaceFrom || 0),
50044
- totalMessages: Number(result.totalMessages || 0),
50045
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
48987
+ ...activeModal ? { activeModal } : {}
50046
48988
  });
50047
48989
  const seq = input.seq + 1;
50048
48990
  if (deliverySignature === input.lastDeliveredSignature) {
50049
48991
  return {
50050
- cursor,
48992
+ cursor: input.cursor,
50051
48993
  seq,
50052
48994
  lastDeliveredSignature: input.lastDeliveredSignature,
50053
48995
  update: null
50054
48996
  };
50055
48997
  }
50056
48998
  return {
50057
- cursor,
48999
+ cursor: input.cursor,
50058
49000
  seq,
50059
49001
  lastDeliveredSignature: deliverySignature,
50060
49002
  update: {
@@ -50065,14 +49007,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
50065
49007
  ...input.interactionId ? { interactionId: input.interactionId } : {},
50066
49008
  seq,
50067
49009
  timestamp: input.timestamp,
50068
- messages: Array.isArray(result.messages) ? result.messages : [],
49010
+ messages,
50069
49011
  status,
50070
49012
  ...title ? { title } : {},
50071
- ...activeModal ? { activeModal } : {},
50072
- syncMode,
50073
- replaceFrom: Number(result.replaceFrom || 0),
50074
- totalMessages: Number(result.totalMessages || 0),
50075
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
49013
+ ...activeModal ? { activeModal } : {}
50076
49014
  }
50077
49015
  };
50078
49016
  }
@@ -50128,8 +49066,6 @@ Run 'adhdev doctor' for detailed diagnostics.`
50128
49066
  });
50129
49067
  await Promise.all(runners);
50130
49068
  }
50131
- init_read_chat_contract();
50132
- init_chat_message_normalization();
50133
49069
  var ProviderStreamAdapter = class {
50134
49070
  agentType;
50135
49071
  agentName;
@@ -50810,7 +49746,6 @@ Run 'adhdev doctor' for detailed diagnostics.`
50810
49746
  }
50811
49747
  };
50812
49748
  init_logger();
50813
- init_chat_message_normalization();
50814
49749
  var AgentStreamPoller = class {
50815
49750
  deps;
50816
49751
  timer = null;
@@ -51284,8 +50219,6 @@ Run 'adhdev doctor' for detailed diagnostics.`
51284
50219
  this.eventListeners = [];
51285
50220
  }
51286
50221
  };
51287
- init_io_contracts();
51288
- init_chat_message_normalization();
51289
50222
  var fs11 = __toESM2(require("fs"));
51290
50223
  var path21 = __toESM2(require("path"));
51291
50224
  var os19 = __toESM2(require("os"));
@@ -54710,7 +53643,7 @@ async (params) => {
54710
53643
  lines.push("Provider category: `cli`");
54711
53644
  lines.push("");
54712
53645
  const funcToFile = {
54713
- parseOutput: "parse_output.js",
53646
+ parseSession: "parse_session.js",
54714
53647
  detectStatus: "detect_status.js",
54715
53648
  parseApproval: "parse_approval.js"
54716
53649
  };
@@ -54799,7 +53732,7 @@ async (params) => {
54799
53732
  lines.push("");
54800
53733
  lines.push("| Function | Input | Return |");
54801
53734
  lines.push("|---|---|---|");
54802
- lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
53735
+ lines.push("| `parseSession` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
54803
53736
  lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
54804
53737
  lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
54805
53738
  lines.push("");
@@ -55019,7 +53952,7 @@ async (params) => {
55019
53952
  lines.push("");
55020
53953
  lines.push("## Required Validation");
55021
53954
  lines.push("1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.");
55022
- lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
53955
+ lines.push("2. Confirm `parseSession` produces a stable transcript without duplicating past turns when the PTY redraws.");
55023
53956
  lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
55024
53957
  lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
55025
53958
  lines.push("5. Confirm the Python file was actually created and executed, not just described in chat text.");
@@ -56287,7 +55220,7 @@ data: ${JSON.stringify(msg.data)}
56287
55220
  lines.push("Provider category: `cli`");
56288
55221
  lines.push("");
56289
55222
  const funcToFile = {
56290
- parseOutput: "parse_output.js",
55223
+ parseSession: "parse_session.js",
56291
55224
  detectStatus: "detect_status.js",
56292
55225
  parseApproval: "parse_approval.js"
56293
55226
  };
@@ -56376,7 +55309,7 @@ data: ${JSON.stringify(msg.data)}
56376
55309
  lines.push("");
56377
55310
  lines.push("| Function | Input | Return |");
56378
55311
  lines.push("|---|---|---|");
56379
- lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
55312
+ lines.push("| `parseSession` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
56380
55313
  lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
56381
55314
  lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
56382
55315
  lines.push("");
@@ -56471,7 +55404,7 @@ data: ${JSON.stringify(msg.data)}
56471
55404
  lines.push("");
56472
55405
  lines.push("## Required Validation");
56473
55406
  lines.push("1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.");
56474
- lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
55407
+ lines.push("2. Confirm `parseSession` produces a stable transcript without duplicating past turns when the PTY redraws.");
56475
55408
  lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
56476
55409
  lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
56477
55410
  lines.push("5. Confirm the Python file was actually created and executed, not just described in chat text.");
@@ -59199,8 +58132,6 @@ var StandaloneServer = class {
59199
58132
  },
59200
58133
  seq: 0,
59201
58134
  cursor: {
59202
- knownMessageCount: Math.max(0, Number(params.knownMessageCount || 0)),
59203
- lastMessageSignature: typeof params.lastMessageSignature === "string" ? params.lastMessageSignature : "",
59204
58135
  tailLimit: Math.max(0, Number(params.tailLimit || 0))
59205
58136
  },
59206
58137
  lastDeliveredSignature: ""
@@ -59324,8 +58255,6 @@ var StandaloneServer = class {
59324
58255
  const result = await this.executeCommand("read_chat", {
59325
58256
  targetSessionId: request.targetSessionId,
59326
58257
  ...request.historySessionId ? { historySessionId: request.historySessionId } : {},
59327
- knownMessageCount: state.cursor.knownMessageCount,
59328
- lastMessageSignature: state.cursor.lastMessageSignature,
59329
58258
  ...state.cursor.tailLimit > 0 ? { tailLimit: state.cursor.tailLimit } : {}
59330
58259
  });
59331
58260
  const prepared = (0, import_daemon_core2.prepareSessionChatTailUpdate)({