@adhdev/daemon-core 0.9.63 → 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.
Files changed (35) hide show
  1. package/dist/chat/chat-signatures.d.ts +0 -4
  2. package/dist/chat/chat-signatures.js +0 -4
  3. package/dist/chat/chat-signatures.js.map +1 -1
  4. package/dist/chat/chat-signatures.mjs +0 -4
  5. package/dist/chat/chat-signatures.mjs.map +1 -1
  6. package/dist/chat/subscription-updates.d.ts +0 -2
  7. package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -30
  8. package/dist/cli-adapters/provider-cli-parse.d.ts +1 -8
  9. package/dist/cli-adapters/provider-cli-shared.d.ts +8 -3
  10. package/dist/commands/chat-commands.d.ts +0 -2
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +646 -1687
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +646 -1687
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/shared-types.d.ts +0 -7
  17. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  18. package/package.json +1 -1
  19. package/src/chat/chat-signatures.ts +0 -8
  20. package/src/chat/subscription-updates.ts +7 -46
  21. package/src/cli-adapters/provider-cli-adapter.d.ts +2 -10
  22. package/src/cli-adapters/provider-cli-adapter.ts +66 -692
  23. package/src/cli-adapters/provider-cli-parse.d.ts +0 -7
  24. package/src/cli-adapters/provider-cli-parse.ts +2 -226
  25. package/src/cli-adapters/provider-cli-shared.d.ts +0 -1
  26. package/src/cli-adapters/provider-cli-shared.ts +8 -3
  27. package/src/commands/chat-commands.ts +54 -338
  28. package/src/daemon/dev-auto-implement.ts +3 -3
  29. package/src/daemon/dev-server.ts +3 -3
  30. package/src/index.d.ts +1 -1
  31. package/src/index.ts +0 -1
  32. package/src/launch.ts +10 -3
  33. package/src/providers/cli-provider-instance.ts +2 -39
  34. package/src/shared-types.d.ts +0 -7
  35. package/src/shared-types.ts +0 -8
package/dist/index.mjs CHANGED
@@ -477,525 +477,6 @@ var init_logger = __esm({
477
477
  }
478
478
  });
479
479
 
480
- // src/providers/io-contracts.ts
481
- function normalizeInputEnvelope(input) {
482
- const normalized = normalizeInputEnvelopePayload(input);
483
- const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
484
- return {
485
- parts: normalized.parts,
486
- textFallback,
487
- ...normalized.metadata ? { metadata: normalized.metadata } : {}
488
- };
489
- }
490
- function normalizeMessageParts(content) {
491
- if (typeof content === "string") return [{ type: "text", text: content }];
492
- if (!Array.isArray(content)) {
493
- if (content && typeof content === "object" && typeof content.text === "string") {
494
- return [{ type: "text", text: String(content.text) }];
495
- }
496
- return [];
497
- }
498
- const parts = [];
499
- for (const raw of content) {
500
- if (typeof raw === "string") {
501
- parts.push({ type: "text", text: raw });
502
- continue;
503
- }
504
- if (!raw || typeof raw !== "object") continue;
505
- const part = normalizeMessagePartObject(raw);
506
- if (part) parts.push(part);
507
- }
508
- return parts;
509
- }
510
- function flattenMessageParts(parts) {
511
- return parts.map((part) => {
512
- if (part.type === "text") return part.text;
513
- if (part.type === "resource") return part.resource.text || "";
514
- return "";
515
- }).filter((value) => value.length > 0).join("\n");
516
- }
517
- function normalizeInputEnvelopePayload(input) {
518
- if (typeof input === "string") {
519
- return { parts: [{ type: "text", text: input }], textFallback: input };
520
- }
521
- if (!input || typeof input !== "object") {
522
- return { parts: [], textFallback: "" };
523
- }
524
- const record = input;
525
- const nestedInput = record.input;
526
- if (nestedInput && typeof nestedInput === "object") {
527
- const nested = nestedInput;
528
- return {
529
- parts: normalizeInputParts(nested.parts ?? nested.prompt),
530
- textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
531
- metadata: normalizeInputMetadata(nested.metadata)
532
- };
533
- }
534
- const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
535
- if (directText !== void 0) {
536
- return { parts: [{ type: "text", text: directText }], textFallback: directText };
537
- }
538
- const directParts = normalizeInputParts(record.parts ?? record.prompt);
539
- return {
540
- parts: directParts,
541
- textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
542
- metadata: normalizeInputMetadata(record.metadata)
543
- };
544
- }
545
- function normalizeInputMetadata(value) {
546
- if (!value || typeof value !== "object") return void 0;
547
- const record = value;
548
- const metadata = {};
549
- if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
550
- metadata.source = record.source;
551
- }
552
- if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
553
- metadata.clientTimestamp = record.clientTimestamp;
554
- }
555
- return Object.keys(metadata).length > 0 ? metadata : void 0;
556
- }
557
- function normalizeInputParts(value) {
558
- if (!Array.isArray(value)) return [];
559
- const parts = [];
560
- for (const raw of value) {
561
- if (typeof raw === "string") {
562
- parts.push({ type: "text", text: raw });
563
- continue;
564
- }
565
- if (!raw || typeof raw !== "object") continue;
566
- const part = normalizeInputPartObject(raw);
567
- if (part) parts.push(part);
568
- }
569
- return parts;
570
- }
571
- function normalizeInputPartObject(raw) {
572
- const type = raw.type;
573
- if (type === "text" && typeof raw.text === "string") {
574
- return { type, text: raw.text };
575
- }
576
- if (type === "image" && typeof raw.mimeType === "string") {
577
- return {
578
- type,
579
- mimeType: raw.mimeType,
580
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
581
- ...typeof raw.data === "string" ? { data: raw.data } : {},
582
- ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
583
- };
584
- }
585
- if (type === "audio" && typeof raw.mimeType === "string") {
586
- return {
587
- type,
588
- mimeType: raw.mimeType,
589
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
590
- ...typeof raw.data === "string" ? { data: raw.data } : {},
591
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
592
- };
593
- }
594
- if (type === "video" && typeof raw.mimeType === "string") {
595
- return {
596
- type,
597
- mimeType: raw.mimeType,
598
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
599
- ...typeof raw.data === "string" ? { data: raw.data } : {},
600
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
601
- };
602
- }
603
- if (type === "resource" && typeof raw.uri === "string") {
604
- return {
605
- type,
606
- uri: raw.uri,
607
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
608
- ...typeof raw.name === "string" ? { name: raw.name } : {},
609
- ...typeof raw.text === "string" ? { text: raw.text } : {},
610
- ...typeof raw.data === "string" ? { data: raw.data } : {}
611
- };
612
- }
613
- if (type === "resource_link" && typeof raw.uri === "string") {
614
- return {
615
- type: "resource",
616
- uri: raw.uri,
617
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
618
- ...typeof raw.name === "string" ? { name: raw.name } : {}
619
- };
620
- }
621
- return null;
622
- }
623
- function normalizeMessagePartObject(raw) {
624
- const type = raw.type;
625
- if (type === "text" && typeof raw.text === "string") {
626
- return { type, text: raw.text };
627
- }
628
- if (type === "image" && typeof raw.mimeType === "string") {
629
- return {
630
- type,
631
- mimeType: raw.mimeType,
632
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
633
- ...typeof raw.data === "string" ? { data: raw.data } : {}
634
- };
635
- }
636
- if (type === "audio" && typeof raw.mimeType === "string") {
637
- return {
638
- type,
639
- mimeType: raw.mimeType,
640
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
641
- ...typeof raw.data === "string" ? { data: raw.data } : {},
642
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
643
- };
644
- }
645
- if (type === "video" && typeof raw.mimeType === "string") {
646
- return {
647
- type,
648
- mimeType: raw.mimeType,
649
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
650
- ...typeof raw.data === "string" ? { data: raw.data } : {},
651
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
652
- };
653
- }
654
- if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
655
- return {
656
- type,
657
- uri: raw.uri,
658
- name: raw.name,
659
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
660
- ...typeof raw.size === "number" ? { size: raw.size } : {}
661
- };
662
- }
663
- if (type === "resource" && raw.resource && typeof raw.resource === "object") {
664
- const resource = raw.resource;
665
- if (typeof resource.uri !== "string") return null;
666
- return {
667
- type,
668
- resource: {
669
- uri: resource.uri,
670
- ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
671
- ...typeof resource.text === "string" ? { text: resource.text } : {},
672
- ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
673
- }
674
- };
675
- }
676
- return null;
677
- }
678
- function flattenInputParts(parts) {
679
- return parts.map((part) => {
680
- if (part.type === "text") return part.text;
681
- if (part.type === "audio") return part.transcript || "";
682
- if (part.type === "resource") return part.text || "";
683
- return "";
684
- }).filter((value) => value.length > 0).join("\n");
685
- }
686
- var init_io_contracts = __esm({
687
- "src/providers/io-contracts.ts"() {
688
- "use strict";
689
- }
690
- });
691
-
692
- // src/providers/contracts.ts
693
- function flattenContent(content) {
694
- if (typeof content === "string") return content;
695
- return flattenMessageParts(normalizeMessageParts(content));
696
- }
697
- var init_contracts = __esm({
698
- "src/providers/contracts.ts"() {
699
- "use strict";
700
- init_io_contracts();
701
- init_io_contracts();
702
- }
703
- });
704
-
705
- // src/providers/chat-message-normalization.ts
706
- function canonicalizeKindHint(value) {
707
- return value.trim().toLowerCase().replace(/[\s-]+/g, "_");
708
- }
709
- function resolveBuiltinOrAliasKind(kind) {
710
- if (typeof kind !== "string") return null;
711
- const normalizedKind = canonicalizeKindHint(kind);
712
- if (!normalizedKind) return null;
713
- if (KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
714
- return CHAT_MESSAGE_KIND_ALIASES[normalizedKind] || null;
715
- }
716
- function inferHintKind(value) {
717
- const direct = resolveBuiltinOrAliasKind(value);
718
- if (direct) return direct;
719
- if (typeof value !== "string") return null;
720
- const normalized = canonicalizeKindHint(value);
721
- if (!normalized) return null;
722
- if (/thought|thinking|reasoning/.test(normalized)) return "thought";
723
- if (/tool/.test(normalized)) return "tool";
724
- if (/terminal|command|shell|console/.test(normalized)) return "terminal";
725
- return null;
726
- }
727
- function inferKindFromToolCalls(message) {
728
- const toolCalls = Array.isArray(message?.toolCalls) ? message.toolCalls : [];
729
- if (toolCalls.length === 0) return null;
730
- if (toolCalls.some((toolCall) => toolCall?.kind === "think")) return "thought";
731
- if (toolCalls.some((toolCall) => toolCall?.kind === "execute")) return "terminal";
732
- if (toolCalls.some((toolCall) => Array.isArray(toolCall?.content) && toolCall.content.some((entry) => entry?.type === "terminal"))) {
733
- return "terminal";
734
- }
735
- return "tool";
736
- }
737
- function inferMissingChatMessageKind(message) {
738
- const role = typeof message?.role === "string" ? message.role.trim().toLowerCase() : "";
739
- if (role === "system") return "system";
740
- const meta = message?.meta && typeof message.meta === "object" ? message.meta : void 0;
741
- const hintCandidates = [
742
- message?._sub,
743
- message?._type,
744
- meta?.label,
745
- typeof message?.senderName === "string" ? message.senderName : void 0
746
- ];
747
- for (const candidate of hintCandidates) {
748
- const inferred = inferHintKind(candidate);
749
- if (inferred) return inferred;
750
- }
751
- const inferredFromToolCalls = inferKindFromToolCalls(message);
752
- if (inferredFromToolCalls) return inferredFromToolCalls;
753
- return null;
754
- }
755
- function isBuiltinChatMessageKind(kind) {
756
- return resolveBuiltinOrAliasKind(kind) !== null;
757
- }
758
- function normalizeChatMessageKind(kind, role) {
759
- const resolvedKind = resolveBuiltinOrAliasKind(kind);
760
- if (resolvedKind) return resolvedKind;
761
- const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
762
- return normalizedRole === "system" ? "system" : "standard";
763
- }
764
- function resolveChatMessageKind(message) {
765
- const explicitKind = resolveBuiltinOrAliasKind(message?.kind);
766
- if (explicitKind) return explicitKind;
767
- const inferredKind = inferMissingChatMessageKind(message);
768
- if (inferredKind) return inferredKind;
769
- return normalizeChatMessageKind(message?.kind, message?.role);
770
- }
771
- function buildChatMessage(message) {
772
- return {
773
- ...message,
774
- kind: resolveChatMessageKind(message)
775
- };
776
- }
777
- function buildSystemChatMessage(message) {
778
- return buildChatMessage({
779
- ...message,
780
- role: "system",
781
- kind: message?.kind || "system"
782
- });
783
- }
784
- function buildRuntimeSystemChatMessage(message) {
785
- return buildSystemChatMessage({
786
- ...message,
787
- senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
788
- });
789
- }
790
- function buildAssistantChatMessage(message) {
791
- return buildChatMessage({
792
- ...message,
793
- role: "assistant",
794
- kind: message?.kind || "standard"
795
- });
796
- }
797
- function buildThoughtChatMessage(message) {
798
- return buildAssistantChatMessage({
799
- ...message,
800
- kind: message?.kind || "thought"
801
- });
802
- }
803
- function buildToolChatMessage(message) {
804
- return buildAssistantChatMessage({
805
- ...message,
806
- kind: message?.kind || "tool"
807
- });
808
- }
809
- function buildTerminalChatMessage(message) {
810
- return buildAssistantChatMessage({
811
- ...message,
812
- kind: message?.kind || "terminal"
813
- });
814
- }
815
- function buildUserChatMessage(message) {
816
- return buildChatMessage({
817
- ...message,
818
- role: "user",
819
- kind: message?.kind || "standard"
820
- });
821
- }
822
- function normalizeChatMessage(message) {
823
- return buildChatMessage(message);
824
- }
825
- function normalizeChatMessages(messages) {
826
- return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
827
- }
828
- var BUILTIN_CHAT_MESSAGE_KINDS, KNOWN_CHAT_MESSAGE_KINDS, CHAT_MESSAGE_KIND_ALIASES;
829
- var init_chat_message_normalization = __esm({
830
- "src/providers/chat-message-normalization.ts"() {
831
- "use strict";
832
- BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
833
- KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
834
- CHAT_MESSAGE_KIND_ALIASES = {
835
- text: "standard",
836
- message: "standard",
837
- assistant: "standard",
838
- thinking: "thought",
839
- think: "thought",
840
- reasoning: "thought",
841
- reason: "thought",
842
- toolcall: "tool",
843
- tool_call: "tool",
844
- tooluse: "tool",
845
- tool_use: "tool",
846
- action: "tool",
847
- command: "terminal",
848
- cmd: "terminal",
849
- shell: "terminal",
850
- console: "terminal"
851
- };
852
- }
853
- });
854
-
855
- // src/providers/read-chat-contract.ts
856
- function isPlainObject3(value) {
857
- return !!value && typeof value === "object" && !Array.isArray(value);
858
- }
859
- function isFiniteNumber(value) {
860
- return typeof value === "number" && Number.isFinite(value);
861
- }
862
- function validateStatus(status, source) {
863
- if (typeof status !== "string" || !VALID_STATUSES.includes(status)) {
864
- throw new Error(`${source}: status must be one of ${VALID_STATUSES.join(", ")}`);
865
- }
866
- return status;
867
- }
868
- function validateRole(role, source, index) {
869
- if (typeof role !== "string" || !VALID_ROLES.includes(role)) {
870
- throw new Error(`${source}: messages[${index}].role must be one of ${VALID_ROLES.join(", ")}`);
871
- }
872
- return role;
873
- }
874
- function validateBubbleState(state, source, index) {
875
- if (typeof state !== "string" || !VALID_BUBBLE_STATES.includes(state)) {
876
- throw new Error(`${source}: messages[${index}].bubbleState must be one of ${VALID_BUBBLE_STATES.join(", ")}`);
877
- }
878
- return state;
879
- }
880
- function validateTurnStatus(turnStatus, source) {
881
- if (typeof turnStatus !== "string" || !VALID_TURN_STATUSES.includes(turnStatus)) {
882
- throw new Error(`${source}: turnStatus must be one of ${VALID_TURN_STATUSES.join(", ")}`);
883
- }
884
- return turnStatus;
885
- }
886
- function validateMessageContent(content, source, index) {
887
- if (typeof content === "string") return content;
888
- if (Array.isArray(content)) return normalizeMessageParts(content);
889
- throw new Error(`${source}: messages[${index}].content must be a string or structured content array`);
890
- }
891
- function validateMessage(message, source, index) {
892
- if (!isPlainObject3(message)) {
893
- throw new Error(`${source}: messages[${index}] must be an object`);
894
- }
895
- const normalized = {
896
- role: validateRole(message.role, source, index),
897
- content: validateMessageContent(message.content, source, index)
898
- };
899
- if (typeof message.kind === "string") normalized.kind = message.kind;
900
- if (typeof message.id === "string") normalized.id = message.id;
901
- if (typeof message.bubbleId === "string") normalized.bubbleId = message.bubbleId;
902
- if (typeof message.providerUnitKey === "string") normalized.providerUnitKey = message.providerUnitKey;
903
- if (message.bubbleState !== void 0) normalized.bubbleState = validateBubbleState(message.bubbleState, source, index);
904
- if (isFiniteNumber(message.index)) normalized.index = message.index;
905
- if (isFiniteNumber(message.timestamp)) normalized.timestamp = message.timestamp;
906
- if (isFiniteNumber(message.receivedAt)) normalized.receivedAt = message.receivedAt;
907
- if (typeof message._turnKey === "string") normalized._turnKey = message._turnKey;
908
- if (Array.isArray(message.toolCalls)) normalized.toolCalls = message.toolCalls;
909
- if (isPlainObject3(message.meta)) normalized.meta = message.meta;
910
- if (typeof message.senderName === "string") normalized.senderName = message.senderName;
911
- if (typeof message._type === "string") normalized._type = message._type;
912
- if (typeof message._sub === "string") normalized._sub = message._sub;
913
- return normalized;
914
- }
915
- function validateModal(activeModal, status, source) {
916
- if (activeModal == null) {
917
- if (status === "waiting_approval") {
918
- throw new Error(`${source}: waiting_approval status requires activeModal with buttons`);
919
- }
920
- return activeModal === null ? null : void 0;
921
- }
922
- if (!isPlainObject3(activeModal)) {
923
- throw new Error(`${source}: activeModal must be an object when provided`);
924
- }
925
- if (typeof activeModal.message !== "string") {
926
- throw new Error(`${source}: activeModal.message must be a string`);
927
- }
928
- if (!Array.isArray(activeModal.buttons) || activeModal.buttons.some((button) => typeof button !== "string" || !button.trim())) {
929
- throw new Error(`${source}: activeModal.buttons must be a non-empty string array`);
930
- }
931
- const normalized = {
932
- message: activeModal.message,
933
- buttons: activeModal.buttons.map((button) => button.trim())
934
- };
935
- if (isFiniteNumber(activeModal.width)) normalized.width = activeModal.width;
936
- if (isFiniteNumber(activeModal.height)) normalized.height = activeModal.height;
937
- return normalized;
938
- }
939
- function validateControlValues(controlValues, source) {
940
- if (controlValues === void 0) return void 0;
941
- if (!isPlainObject3(controlValues)) {
942
- throw new Error(`${source}: controlValues must be an object when provided`);
943
- }
944
- const normalized = {};
945
- for (const [key, value] of Object.entries(controlValues)) {
946
- if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
947
- throw new Error(`${source}: controlValues.${key} must be string, number, or boolean`);
948
- }
949
- normalized[key] = value;
950
- }
951
- return normalized;
952
- }
953
- function validateReadChatResultPayload(raw, source = "read_chat") {
954
- if (!isPlainObject3(raw)) {
955
- throw new Error(`${source}: payload must be an object`);
956
- }
957
- const status = validateStatus(raw.status, source);
958
- if (!Array.isArray(raw.messages)) {
959
- throw new Error(`${source}: messages must be an array`);
960
- }
961
- const messages = raw.messages.map((message, index) => validateMessage(message, source, index));
962
- const activeModal = validateModal(raw.activeModal, status, source);
963
- const controlValues = validateControlValues(raw.controlValues, source);
964
- const normalized = {
965
- status,
966
- messages
967
- };
968
- if (activeModal !== void 0) normalized.activeModal = activeModal;
969
- if (typeof raw.id === "string") normalized.id = raw.id;
970
- if (typeof raw.title === "string") normalized.title = raw.title;
971
- if (typeof raw.currentTurnId === "string") normalized.currentTurnId = raw.currentTurnId;
972
- if (raw.turnStatus !== void 0) normalized.turnStatus = validateTurnStatus(raw.turnStatus, source);
973
- if (typeof raw.agentType === "string") normalized.agentType = raw.agentType;
974
- if (typeof raw.agentName === "string") normalized.agentName = raw.agentName;
975
- if (typeof raw.extensionId === "string") normalized.extensionId = raw.extensionId;
976
- if (typeof raw.inputContent === "string") normalized.inputContent = raw.inputContent;
977
- if (typeof raw.isVisible === "boolean") normalized.isVisible = raw.isVisible;
978
- if (typeof raw.isWelcomeScreen === "boolean") normalized.isWelcomeScreen = raw.isWelcomeScreen;
979
- if (controlValues) normalized.controlValues = controlValues;
980
- if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
981
- if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
982
- if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
983
- if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
984
- if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
985
- return normalized;
986
- }
987
- var VALID_STATUSES, VALID_ROLES, VALID_BUBBLE_STATES, VALID_TURN_STATUSES;
988
- var init_read_chat_contract = __esm({
989
- "src/providers/read-chat-contract.ts"() {
990
- "use strict";
991
- init_contracts();
992
- VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "streaming", "long_generating"];
993
- VALID_ROLES = ["user", "assistant", "system", "human"];
994
- VALID_BUBBLE_STATES = ["draft", "streaming", "final", "removed"];
995
- VALID_TURN_STATUSES = ["open", "waiting_approval", "complete", "error"];
996
- }
997
- });
998
-
999
480
  // src/logging/debug-config.ts
1000
481
  function normalizeCategories(categories) {
1001
482
  if (!Array.isArray(categories)) return [];
@@ -1563,67 +1044,6 @@ function promptLikelyVisible(screenText, promptSnippet) {
1563
1044
  function normalizeScreenSnapshot(text) {
1564
1045
  return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
1565
1046
  }
1566
- function shouldReflowComparableMessageLines(lines) {
1567
- 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));
1568
- }
1569
- function joinComparableMessageLines(lines) {
1570
- return lines.reduce((acc, line) => {
1571
- const next = String(line || "").trim();
1572
- if (!next) return acc;
1573
- if (!acc) return next;
1574
- if (/[,\d]$/.test(acc) && /^\d/.test(next)) {
1575
- return `${acc}${next}`;
1576
- }
1577
- if (/[A-Za-z]$/.test(acc) && /^\d/.test(next)) {
1578
- return `${acc}${next}`;
1579
- }
1580
- const fragmentMatch = acc.match(/([A-Za-z]{1,4})$/);
1581
- const fragment = fragmentMatch ? fragmentMatch[1].toLowerCase() : "";
1582
- if (/^[a-z]/.test(next) && fragment && !COMMON_COMPARABLE_WRAP_WORDS.has(fragment)) {
1583
- return `${acc}${next}`;
1584
- }
1585
- return `${acc} ${next}`;
1586
- }, "").replace(/\s+([,.;:!?])/g, "$1").replace(/(\d)\s+,/g, "$1,").replace(/\s+/g, " ").trim();
1587
- }
1588
- function normalizeComparableMessageContent(text) {
1589
- const lines = String(text || "").split(/\r\n|\n|\r/g).map((line) => line.trim()).filter(Boolean);
1590
- if (lines.length === 0) return "";
1591
- if (shouldReflowComparableMessageLines(lines)) {
1592
- return joinComparableMessageLines(lines);
1593
- }
1594
- return lines.join(" ").replace(/\s+/g, " ").trim();
1595
- }
1596
- function trimPromptEchoPrefix(text, promptText) {
1597
- const prompt = normalizeComparableMessageContent(String(promptText || ""));
1598
- if (!prompt) return String(text || "");
1599
- const lines = String(text || "").split(/\r\n|\n|\r/g);
1600
- let dropCount = 0;
1601
- for (let index = 0; index < Math.min(lines.length, 6); index += 1) {
1602
- const fragment = normalizeComparableMessageContent(lines[index].replace(/^[.…]+\s*/, ""));
1603
- if (!fragment) {
1604
- if (dropCount === index) dropCount = index + 1;
1605
- continue;
1606
- }
1607
- const fragmentWordCount = fragment ? fragment.split(/\s+/).filter(Boolean).length : 0;
1608
- const canBePromptEcho = fragment.length >= 16 || fragmentWordCount >= 4;
1609
- if (canBePromptEcho && prompt.includes(fragment)) {
1610
- dropCount = index + 1;
1611
- continue;
1612
- }
1613
- break;
1614
- }
1615
- return lines.slice(dropCount).join("\n").trim();
1616
- }
1617
- function getLastUserPromptText(messages) {
1618
- const items = Array.isArray(messages) ? messages : [];
1619
- for (let index = items.length - 1; index >= 0; index -= 1) {
1620
- const message = items[index];
1621
- if (message?.role === "user" && typeof message.content === "string" && message.content.trim()) {
1622
- return message.content;
1623
- }
1624
- }
1625
- return "";
1626
- }
1627
1047
  function parsePatternEntry(x) {
1628
1048
  if (x instanceof RegExp) return x;
1629
1049
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -1650,38 +1070,12 @@ function normalizeCliProviderForRuntime(raw) {
1650
1070
  }
1651
1071
  };
1652
1072
  }
1653
- var buildCliSpawnEnv, COMMON_COMPARABLE_WRAP_WORDS;
1073
+ var buildCliSpawnEnv;
1654
1074
  var init_provider_cli_shared = __esm({
1655
1075
  "src/cli-adapters/provider-cli-shared.ts"() {
1656
1076
  "use strict";
1657
1077
  init_spawn_env();
1658
1078
  buildCliSpawnEnv = sanitizeSpawnEnv;
1659
- COMMON_COMPARABLE_WRAP_WORDS = /* @__PURE__ */ new Set([
1660
- "a",
1661
- "an",
1662
- "and",
1663
- "as",
1664
- "at",
1665
- "but",
1666
- "by",
1667
- "for",
1668
- "from",
1669
- "in",
1670
- "into",
1671
- "is",
1672
- "it",
1673
- "of",
1674
- "on",
1675
- "or",
1676
- "that",
1677
- "the",
1678
- "their",
1679
- "then",
1680
- "this",
1681
- "to",
1682
- "was",
1683
- "with"
1684
- ]);
1685
1079
  }
1686
1080
  });
1687
1081
 
@@ -1692,169 +1086,8 @@ function sliceFromOffset(text, start) {
1692
1086
  if (start >= text.length) return "";
1693
1087
  return text.slice(start);
1694
1088
  }
1695
- function hydrateCliParsedMessages(parsedMessages, options) {
1696
- const { committedMessages, scope, lastOutputAt } = options;
1697
- const referenceMessages = [...committedMessages];
1698
- const referenceComparables = new Array(referenceMessages.length);
1699
- const usedReferenceIndexes = /* @__PURE__ */ new Set();
1700
- const now = options.now ?? Date.now();
1701
- let exactReferenceIndexesByKey = null;
1702
- const exactReferenceCursorByKey = /* @__PURE__ */ new Map();
1703
- const hasFiniteTimestamp = (message) => typeof message?.timestamp === "number" && Number.isFinite(message.timestamp);
1704
- const getReferenceComparable = (index) => {
1705
- if (typeof referenceComparables[index] === "string") return referenceComparables[index] || "";
1706
- const comparable = normalizeComparableMessageContent(referenceMessages[index]?.content || "");
1707
- referenceComparables[index] = comparable;
1708
- return comparable;
1709
- };
1710
- const messagesShareStableIdentity = (parsed, reference) => {
1711
- if (!parsed || !reference) return false;
1712
- const parsedId = typeof parsed.id === "string" ? parsed.id.trim() : "";
1713
- const referenceId = typeof reference.id === "string" ? reference.id.trim() : "";
1714
- if (parsedId && referenceId && parsedId === referenceId) return true;
1715
- return typeof parsed.index === "number" && Number.isFinite(parsed.index) && typeof reference.index === "number" && Number.isFinite(reference.index) && parsed.index === reference.index;
1716
- };
1717
- const exactReferenceKey = (role, comparable) => `${role}\0${comparable}`;
1718
- const ensureExactReferenceIndex = () => {
1719
- if (exactReferenceIndexesByKey) return exactReferenceIndexesByKey;
1720
- const byKey = /* @__PURE__ */ new Map();
1721
- for (let i = 0; i < referenceMessages.length; i++) {
1722
- const candidate = referenceMessages[i];
1723
- if (!candidate || candidate.role !== "user" && candidate.role !== "assistant" || !hasFiniteTimestamp(candidate)) continue;
1724
- const comparable = getReferenceComparable(i);
1725
- if (!comparable) continue;
1726
- const key = exactReferenceKey(candidate.role, comparable);
1727
- const indexes = byKey.get(key);
1728
- if (indexes) {
1729
- indexes.push(i);
1730
- } else {
1731
- byKey.set(key, [i]);
1732
- }
1733
- }
1734
- exactReferenceIndexesByKey = byKey;
1735
- return byKey;
1736
- };
1737
- const takeExactReferenceTimestamp = (role, normalizedContent) => {
1738
- const key = exactReferenceKey(role, normalizedContent);
1739
- const indexes = ensureExactReferenceIndex().get(key);
1740
- if (!indexes) return void 0;
1741
- let cursor = exactReferenceCursorByKey.get(key) || 0;
1742
- while (cursor < indexes.length) {
1743
- const candidateIndex = indexes[cursor];
1744
- cursor += 1;
1745
- if (usedReferenceIndexes.has(candidateIndex)) continue;
1746
- const candidate = referenceMessages[candidateIndex];
1747
- if (!candidate || candidate.role !== role || !hasFiniteTimestamp(candidate)) continue;
1748
- usedReferenceIndexes.add(candidateIndex);
1749
- exactReferenceCursorByKey.set(key, cursor);
1750
- return candidate.timestamp;
1751
- }
1752
- exactReferenceCursorByKey.set(key, cursor);
1753
- return void 0;
1754
- };
1755
- const findReferenceTimestamp = (message, role, content, parsedIndex) => {
1756
- const sameIndex = referenceMessages[parsedIndex];
1757
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && hasFiniteTimestamp(sameIndex) && messagesShareStableIdentity(message, sameIndex)) {
1758
- usedReferenceIndexes.add(parsedIndex);
1759
- return sameIndex.timestamp;
1760
- }
1761
- const normalizedContent = normalizeComparableMessageContent(content);
1762
- if (!normalizedContent) return void 0;
1763
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && getReferenceComparable(parsedIndex) === normalizedContent && hasFiniteTimestamp(sameIndex)) {
1764
- usedReferenceIndexes.add(parsedIndex);
1765
- return sameIndex.timestamp;
1766
- }
1767
- const exactTimestamp = takeExactReferenceTimestamp(role, normalizedContent);
1768
- if (typeof exactTimestamp === "number") return exactTimestamp;
1769
- for (let i = 0; i < referenceMessages.length; i++) {
1770
- if (usedReferenceIndexes.has(i)) continue;
1771
- const candidate = referenceMessages[i];
1772
- if (!candidate || candidate.role !== role) continue;
1773
- const candidateContent = getReferenceComparable(i);
1774
- if (!candidateContent) continue;
1775
- const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1776
- if (!fuzzyMatch) continue;
1777
- if (hasFiniteTimestamp(candidate)) {
1778
- usedReferenceIndexes.add(i);
1779
- return candidate.timestamp;
1780
- }
1781
- }
1782
- return void 0;
1783
- };
1784
- return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1785
- const role = message.role;
1786
- const content = typeof message.content === "string" ? message.content : String(message.content || "");
1787
- const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1788
- const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(message, role, content, index);
1789
- const fallbackTimestamp = role === "user" ? scope?.startedAt || now : lastOutputAt || scope?.startedAt || now;
1790
- const timestamp = referenceTimestamp ?? fallbackTimestamp;
1791
- return {
1792
- ...message,
1793
- role,
1794
- content,
1795
- timestamp,
1796
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
1797
- };
1798
- });
1799
- }
1800
- function chooseMoreComparableCliMessage(left, right, leftComparable = normalizeComparableMessageContent(left.content || ""), rightComparable = normalizeComparableMessageContent(right.content || "")) {
1801
- if (leftComparable && leftComparable === rightComparable) {
1802
- const leftNewlines = String(left.content || "").split(/\r\n|\n|\r/g).length - 1;
1803
- const rightNewlines = String(right.content || "").split(/\r\n|\n|\r/g).length - 1;
1804
- return rightNewlines < leftNewlines ? right : left;
1805
- }
1806
- return rightComparable.length > leftComparable.length ? right : left;
1807
- }
1808
- function dedupeConsecutiveComparableCliMessages(messages) {
1809
- const deduped = [];
1810
- for (const message of messages) {
1811
- const current = {
1812
- ...message,
1813
- content: typeof message.content === "string" ? message.content : String(message.content || "")
1814
- };
1815
- const currentComparable = normalizeComparableMessageContent(current.content || "");
1816
- const previous = deduped[deduped.length - 1];
1817
- if (!previous) {
1818
- deduped.push({ message: current, comparable: currentComparable });
1819
- continue;
1820
- }
1821
- const sameRole = previous.message.role === current.role;
1822
- const sameKind = (previous.message.kind || "standard") === (current.kind || "standard");
1823
- const sameSender = (previous.message.senderName || "") === (current.senderName || "");
1824
- const comparableMatch = previous.comparable && previous.comparable === currentComparable;
1825
- if (sameRole && sameKind && sameSender && comparableMatch) {
1826
- const selected = chooseMoreComparableCliMessage(
1827
- previous.message,
1828
- current,
1829
- previous.comparable,
1830
- currentComparable
1831
- );
1832
- deduped[deduped.length - 1] = {
1833
- message: selected,
1834
- comparable: selected === current ? currentComparable : previous.comparable
1835
- };
1836
- continue;
1837
- }
1838
- deduped.push({ message: current, comparable: currentComparable });
1839
- }
1840
- return deduped.map((entry) => entry.message);
1841
- }
1842
- function normalizeCliParsedMessages(parsedMessages, options) {
1843
- return dedupeConsecutiveComparableCliMessages(hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
1844
- role: message.role,
1845
- content: message.content,
1846
- timestamp: message.timestamp,
1847
- receivedAt: message.receivedAt,
1848
- kind: message.kind,
1849
- id: message.id,
1850
- index: message.index,
1851
- providerUnitKey: message.providerUnitKey,
1852
- bubbleId: message.bubbleId,
1853
- bubbleState: message.bubbleState,
1854
- _turnKey: message._turnKey,
1855
- meta: message.meta,
1856
- senderName: message.senderName
1857
- })));
1089
+ function normalizeCliParsedMessages(parsedMessages, _options) {
1090
+ return Array.isArray(parsedMessages) ? parsedMessages : [];
1858
1091
  }
1859
1092
  function buildCliParseInput(options) {
1860
1093
  const {
@@ -2063,41 +1296,9 @@ var provider_cli_adapter_exports = {};
2063
1296
  __export(provider_cli_adapter_exports, {
2064
1297
  ProviderCliAdapter: () => ProviderCliAdapter,
2065
1298
  appendBoundedText: () => appendBoundedText,
2066
- normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime,
2067
- sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent,
2068
- trimLastAssistantEchoForCliMessages: () => trimLastAssistantEchoForCliMessages
1299
+ normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
2069
1300
  });
2070
1301
  import * as os11 from "os";
2071
- function normalizeComparableTranscriptText(value) {
2072
- return sanitizeTerminalText(String(value || "")).replace(/\s+/g, " ").trim();
2073
- }
2074
- function hasVisibleInterruptPrompt(text) {
2075
- const interruptCopyPattern = /\bEnter\s+to\s+interrupt\b(?:\s*,?\s*Ctrl\s*(?:\+|-)?\s*C\s+to\s+cancel)?/i;
2076
- return sanitizeTerminalText(text || "").split(/\r?\n/g).some((line) => {
2077
- const trimmed = line.trim();
2078
- if (!interruptCopyPattern.test(trimmed)) return false;
2079
- return /^(?:[^A-Za-z0-9\s]{1,8}\s+)?[❯›>]\s+/.test(trimmed);
2080
- });
2081
- }
2082
- function parsedTranscriptIsRicherThanCommitted(parsedMessages, committedMessages) {
2083
- if (!Array.isArray(parsedMessages) || !Array.isArray(committedMessages)) return false;
2084
- if (parsedMessages.length > committedMessages.length) return true;
2085
- if (parsedMessages.length !== committedMessages.length) return false;
2086
- for (let index = 0; index < parsedMessages.length; index += 1) {
2087
- const parsed = parsedMessages[index];
2088
- const committed = committedMessages[index];
2089
- if (!parsed || !committed) return false;
2090
- if ((parsed.role || "") !== (committed.role || "")) return false;
2091
- if (parsed.id && committed.id && String(parsed.id) !== String(committed.id)) return false;
2092
- if (typeof parsed.index === "number" && typeof committed.index === "number" && parsed.index !== committed.index) return false;
2093
- const parsedText = normalizeComparableTranscriptText(parsed.content);
2094
- const committedText = normalizeComparableTranscriptText(committed.content);
2095
- if (!parsedText || !committedText || parsedText === committedText) continue;
2096
- if (parsedText.length > committedText.length && parsedText.startsWith(committedText)) return true;
2097
- return false;
2098
- }
2099
- return false;
2100
- }
2101
1302
  function appendBoundedText(current, chunk, maxChars) {
2102
1303
  if (!chunk) return current.length <= maxChars ? current : current.slice(-maxChars);
2103
1304
  if (maxChars <= 0) return "";
@@ -2106,76 +1307,7 @@ function appendBoundedText(current, chunk, maxChars) {
2106
1307
  if (current.length <= keepFromCurrent) return current + chunk;
2107
1308
  return current.slice(-keepFromCurrent) + chunk;
2108
1309
  }
2109
- function isLikelyCommittedActivityPrefixContinuation(line) {
2110
- const trimmed = String(line || "").trim();
2111
- if (!trimmed) return false;
2112
- if (COMMITTED_ACTIVITY_PREFIX_BLOCK_RE.test(trimmed)) return false;
2113
- if (/\s/.test(trimmed)) return false;
2114
- if (/[가-힣]/.test(trimmed)) return false;
2115
- if (trimmed.length > 96) return false;
2116
- return /^[A-Za-z0-9_./:@+%=-]+$/.test(trimmed);
2117
- }
2118
- function parseCommittedActivityPrefixBlock(lines, index) {
2119
- const first = String(lines[index] || "").trim();
2120
- if (!COMMITTED_ACTIVITY_PREFIX_BLOCK_RE.test(first)) return null;
2121
- const parts = [first];
2122
- let nextIndex = index + 1;
2123
- while (nextIndex < lines.length && isLikelyCommittedActivityPrefixContinuation(lines[nextIndex])) {
2124
- parts.push(String(lines[nextIndex] || "").trim());
2125
- nextIndex += 1;
2126
- }
2127
- return { label: parts.join(""), nextIndex };
2128
- }
2129
- function sanitizeCliStandardMessageContent(content) {
2130
- const source = String(content || "").trim();
2131
- if (!source) return "";
2132
- const lines = source.split(/\r?\n/);
2133
- if (lines.length < 4) return source;
2134
- const counts = /* @__PURE__ */ new Map();
2135
- for (let index = 0; index < lines.length; index += 1) {
2136
- const block = parseCommittedActivityPrefixBlock(lines, index);
2137
- if (!block) continue;
2138
- counts.set(block.label, (counts.get(block.label) || 0) + 1);
2139
- index = block.nextIndex - 1;
2140
- }
2141
- const repeatedLabels = new Set(
2142
- Array.from(counts.entries()).filter(([, count]) => count >= 3).map(([label]) => label)
2143
- );
2144
- if (repeatedLabels.size === 0) return source;
2145
- const stripped = [];
2146
- let removed = 0;
2147
- for (let index = 0; index < lines.length; index += 1) {
2148
- const block = parseCommittedActivityPrefixBlock(lines, index);
2149
- if (block && repeatedLabels.has(block.label)) {
2150
- removed += 1;
2151
- index = block.nextIndex - 1;
2152
- continue;
2153
- }
2154
- stripped.push(lines[index]);
2155
- }
2156
- const next = stripped.join("\n").replace(/\n{3,}/g, "\n\n").trim();
2157
- return removed >= 3 && next.length >= 80 ? next : source;
2158
- }
2159
- function sanitizeCommittedMessageForDisplay(message) {
2160
- if (!message || message.role !== "assistant" || (message.kind || "standard") !== "standard") return message;
2161
- const content = sanitizeCliStandardMessageContent(message.content);
2162
- if (content === message.content) return message;
2163
- return { ...message, content };
2164
- }
2165
- function trimLastAssistantEchoForCliMessages(messages, prompt) {
2166
- if (!prompt) return;
2167
- for (let index = messages.length - 1; index >= 0; index -= 1) {
2168
- const message = messages[index];
2169
- if (!message || message.role !== "assistant" || typeof message.content !== "string") continue;
2170
- if ((message.kind || "standard") !== "standard") continue;
2171
- message.content = trimPromptEchoPrefix(message.content, prompt);
2172
- if (!message.content.trim()) {
2173
- messages.splice(index, 1);
2174
- }
2175
- return;
2176
- }
2177
- }
2178
- var COMMITTED_ACTIVITY_PREFIX_BLOCK_RE, ProviderCliAdapter;
1310
+ var ProviderCliAdapter;
2179
1311
  var init_provider_cli_adapter = __esm({
2180
1312
  "src/cli-adapters/provider-cli-adapter.ts"() {
2181
1313
  "use strict";
@@ -2184,13 +1316,10 @@ var init_provider_cli_adapter = __esm({
2184
1316
  init_terminal_screen();
2185
1317
  init_pty_transport();
2186
1318
  init_provider_cli_shared();
2187
- init_chat_message_normalization();
2188
- init_read_chat_contract();
2189
1319
  init_provider_cli_parse();
2190
1320
  init_provider_cli_config();
2191
1321
  init_provider_cli_runtime();
2192
1322
  init_provider_cli_shared();
2193
- COMMITTED_ACTIVITY_PREFIX_BLOCK_RE = /^(?:📖|💻|🔎|📚|📋|✏️|📝|🔧|🛠️|⚙️)\s+(.+)$/;
2194
1323
  ProviderCliAdapter = class _ProviderCliAdapter {
2195
1324
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
2196
1325
  this.extraArgs = extraArgs;
@@ -2233,11 +1362,6 @@ var init_provider_cli_adapter = __esm({
2233
1362
  provider;
2234
1363
  ptyProcess = null;
2235
1364
  transportFactory;
2236
- messages = [];
2237
- committedMessages = [];
2238
- structuredMessages = [];
2239
- committedMessagesActivitySignature = "";
2240
- committedMessagesChangedAt = 0;
2241
1365
  currentStatus = "starting";
2242
1366
  onStatusChange = null;
2243
1367
  responseBuffer = "";
@@ -2317,11 +1441,8 @@ var init_provider_cli_adapter = __esm({
2317
1441
  traceSeq = 0;
2318
1442
  traceSessionId = "";
2319
1443
  parsedStatusCache = null;
2320
- lastStatusHotPathParseAt = Number.NEGATIVE_INFINITY;
2321
- static STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1e3;
2322
1444
  static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
2323
1445
  static MAX_TRACE_ENTRIES = 250;
2324
- static PARSE_MESSAGE_TAIL_LIMIT = 100;
2325
1446
  providerResolutionMeta;
2326
1447
  static FINISH_RETRY_DELAY_MS = 300;
2327
1448
  static MAX_FINISH_RETRIES = 2;
@@ -2342,35 +1463,6 @@ var init_provider_cli_adapter = __esm({
2342
1463
  recordBoundedAppendDrop(previousLength, appendedLength, nextLength) {
2343
1464
  return Math.max(0, previousLength + appendedLength - nextLength);
2344
1465
  }
2345
- buildCommittedMessagesActivitySignature() {
2346
- const last = this.committedMessages[this.committedMessages.length - 1];
2347
- return [
2348
- String(this.committedMessages.length),
2349
- String(last?.role || ""),
2350
- String(last?.kind || ""),
2351
- String(last?.senderName || ""),
2352
- String(last?.timestamp || ""),
2353
- String(last?.receivedAt || ""),
2354
- normalizeComparableMessageContent(last?.content || "").slice(-240)
2355
- ].join("|");
2356
- }
2357
- syncMessageViews() {
2358
- const signature = this.buildCommittedMessagesActivitySignature();
2359
- if (signature !== this.committedMessagesActivitySignature) {
2360
- this.committedMessagesActivitySignature = signature;
2361
- this.committedMessagesChangedAt = Date.now();
2362
- }
2363
- this.messages = [...this.committedMessages];
2364
- this.structuredMessages = [...this.committedMessages];
2365
- }
2366
- getLastCommittedMessageActivityAt() {
2367
- const last = this.committedMessages[this.committedMessages.length - 1];
2368
- const messageTime = Math.max(
2369
- typeof last?.receivedAt === "number" && Number.isFinite(last.receivedAt) ? last.receivedAt : 0,
2370
- typeof last?.timestamp === "number" && Number.isFinite(last.timestamp) ? last.timestamp : 0
2371
- );
2372
- return Math.max(messageTime, this.committedMessagesChangedAt || 0);
2373
- }
2374
1466
  readTerminalScreenText(now = Date.now()) {
2375
1467
  const screenText = this.terminalScreen.getText() || "";
2376
1468
  this.lastScreenText = screenText;
@@ -2390,7 +1482,7 @@ var init_provider_cli_adapter = __esm({
2390
1482
  }
2391
1483
  getFreshParsedStatusCache() {
2392
1484
  const cached = this.parsedStatusCache;
2393
- if (cached && cached.committedMessagesRef === this.committedMessages && cached.responseBuffer === this.responseBuffer && cached.currentTurnScope === this.currentTurnScope && cached.recentOutputBuffer === this.recentOutputBuffer && cached.accumulatedBuffer === this.accumulatedBuffer && cached.screenText === this.lastScreenText && cached.currentStatus === this.currentStatus && cached.activeModal === this.activeModal && cached.cliName === this.cliName) {
1485
+ if (cached && cached.responseBuffer === this.responseBuffer && cached.currentTurnScope === this.currentTurnScope && cached.recentOutputBuffer === this.recentOutputBuffer && cached.accumulatedBuffer === this.accumulatedBuffer && cached.screenText === this.lastScreenText && cached.currentStatus === this.currentStatus && cached.activeModal === this.activeModal && cached.cliName === this.cliName) {
2394
1486
  return cached.result;
2395
1487
  }
2396
1488
  return null;
@@ -2401,45 +1493,6 @@ var init_provider_cli_adapter = __esm({
2401
1493
  shouldUseFullProviderTranscriptContext() {
2402
1494
  return this.providerOwnsTranscript() && this.provider.transcriptContext === "full";
2403
1495
  }
2404
- selectParseBaseMessages(baseMessages) {
2405
- if (this.shouldUseFullProviderTranscriptContext()) return baseMessages;
2406
- if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
2407
- return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
2408
- }
2409
- messagesShareStableIdentity(left, right) {
2410
- if (left === right) return true;
2411
- if (!left || !right) return false;
2412
- if ((left.role || "") !== (right.role || "")) return false;
2413
- if (left.id && right.id && String(left.id) === String(right.id)) return true;
2414
- if (typeof left.index === "number" && typeof right.index === "number" && left.index === right.index) return true;
2415
- return false;
2416
- }
2417
- messagesComparable(left, right) {
2418
- if (this.messagesShareStableIdentity(left, right)) return true;
2419
- if (!left || !right) return false;
2420
- if ((left.role || "") !== (right.role || "")) return false;
2421
- const leftText = normalizeComparableTranscriptText(left.content);
2422
- const rightText = normalizeComparableTranscriptText(right.content);
2423
- return !!leftText && leftText === rightText;
2424
- }
2425
- stitchParsedMessagesWithCommittedBase(parsedMessages, fullBaseMessages, parseBaseMessages) {
2426
- if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
2427
- if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
2428
- const parsedFirst = parsedMessages[0];
2429
- const fullFirst = fullBaseMessages[0];
2430
- if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
2431
- return parsedMessages;
2432
- }
2433
- const tailFirst = parseBaseMessages[0];
2434
- if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
2435
- const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
2436
- const prefix = fullBaseMessages.slice(0, prefixLength);
2437
- const shouldSanitizePrefix = !!this.currentTurnScope || this.currentStatus !== "idle" || !!this.activeModal;
2438
- const nextPrefix = shouldSanitizePrefix ? prefix.map((message) => sanitizeCommittedMessageForDisplay(message)) : prefix;
2439
- return [...nextPrefix, ...parsedMessages];
2440
- }
2441
- return [...fullBaseMessages, ...parsedMessages];
2442
- }
2443
1496
  getIdleFinishConfirmMs() {
2444
1497
  return this.timeouts.idleFinishConfirm;
2445
1498
  }
@@ -2892,9 +1945,6 @@ var init_provider_cli_adapter = __esm({
2892
1945
  `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
2893
1946
  );
2894
1947
  }
2895
- trimLastAssistantEcho(messages, prompt) {
2896
- trimLastAssistantEchoForCliMessages(messages, prompt);
2897
- }
2898
1948
  clearAllTimers() {
2899
1949
  if (this.responseTimeout) {
2900
1950
  clearTimeout(this.responseTimeout);
@@ -2990,10 +2040,10 @@ var init_provider_cli_adapter = __esm({
2990
2040
  }
2991
2041
  const session = this.runParseSession();
2992
2042
  if (!session) return;
2993
- const { status, messages, modal, parsedStatus } = session;
2043
+ const { status, messages, parsedStatus } = session;
2044
+ const modal = session.activeModal ?? session.modal ?? null;
2994
2045
  const parsedMessages = normalizeCliParsedMessages(messages, {
2995
- committedMessages: this.committedMessages,
2996
- scope: this.currentTurnScope,
2046
+ scope: null,
2997
2047
  lastOutputAt: this.lastOutputAt
2998
2048
  });
2999
2049
  if (this.maybeCommitVisibleIdleTranscript(session, parsedMessages)) return;
@@ -3173,7 +2223,7 @@ var init_provider_cli_adapter = __esm({
3173
2223
  const effectiveScreenText = screenText || this.accumulatedBuffer;
3174
2224
  const noActiveTurn = !this.currentTurnScope;
3175
2225
  const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText);
3176
- const parsedShowsLiveAssistantProgress = parsedStatus === "generating" && !!lastParsedAssistant && parsedMessages.length > this.committedMessages.length;
2226
+ const parsedShowsLiveAssistantProgress = parsedStatus === "generating" && !!lastParsedAssistant;
3177
2227
  if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
3178
2228
  return;
3179
2229
  }
@@ -3330,10 +2380,7 @@ var init_provider_cli_adapter = __esm({
3330
2380
  }
3331
2381
  const visibleAssistant = [...parsedMessages].reverse().find((m) => m.role === "assistant" && m.content.trim());
3332
2382
  if (!visibleAssistant) return false;
3333
- this.committedMessages = parsedMessages;
3334
- this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
3335
2383
  this.clearAllTimers();
3336
- this.syncMessageViews();
3337
2384
  this.responseBuffer = "";
3338
2385
  this.isWaitingForResponse = false;
3339
2386
  this.responseSettleIgnoreUntil = 0;
@@ -3345,37 +2392,34 @@ var init_provider_cli_adapter = __esm({
3345
2392
  this.setStatus("idle", "script_idle_commit");
3346
2393
  this.onStatusChange?.();
3347
2394
  this.recordTrace("script_idle_commit", {
3348
- messageCount: this.committedMessages.length,
2395
+ messageCount: parsedMessages.length,
3349
2396
  lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320)
3350
2397
  });
3351
2398
  return true;
3352
2399
  }
3353
2400
  commitCurrentTranscript() {
3354
2401
  const parsed = this.parseCurrentTranscript(
3355
- this.committedMessages,
2402
+ [],
3356
2403
  this.responseBuffer,
3357
2404
  this.currentTurnScope
3358
2405
  );
3359
2406
  if (parsed && Array.isArray(parsed.messages)) {
3360
- this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
3361
- committedMessages: this.committedMessages,
3362
- scope: this.currentTurnScope,
2407
+ const parsedMessages = normalizeCliParsedMessages(parsed.messages, {
2408
+ scope: null,
3363
2409
  lastOutputAt: this.lastOutputAt
3364
2410
  });
3365
- this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
3366
- this.syncMessageViews();
3367
- const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
2411
+ const lastAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
3368
2412
  if (this.currentTurnScope) {
3369
2413
  LOG.info(
3370
2414
  "CLI",
3371
- `[${this.cliType}] commitCurrentTranscript committedMessages=${this.committedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
2415
+ `[${this.cliType}] commitCurrentTranscript parserMessages=${parsedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
3372
2416
  );
3373
2417
  }
3374
2418
  this.recordTrace("commit_transcript", {
3375
2419
  parsedStatus: parsed.status || null,
3376
- messageCount: this.committedMessages.length,
2420
+ messageCount: parsedMessages.length,
3377
2421
  lastAssistant: lastAssistant ? summarizeCliTraceText(lastAssistant.content, 320) : "",
3378
- messages: summarizeCliTraceMessages(this.committedMessages),
2422
+ messages: summarizeCliTraceMessages(parsedMessages),
3379
2423
  ...buildCliTraceParseSnapshot({
3380
2424
  accumulatedBuffer: this.accumulatedBuffer,
3381
2425
  accumulatedRawBuffer: this.accumulatedRawBuffer,
@@ -3409,63 +2453,31 @@ var init_provider_cli_adapter = __esm({
3409
2453
  }
3410
2454
  // ─── Script Execution ──────────────────────────
3411
2455
  runParseSession() {
3412
- if (typeof this.cliScripts?.parseSession === "function") {
3413
- try {
3414
- const screenText = this.terminalScreen.getText();
3415
- const tail = this.recentOutputBuffer.slice(-500);
3416
- const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
3417
- const input = buildCliParseInput({
3418
- accumulatedBuffer: this.accumulatedBuffer,
3419
- accumulatedRawBuffer: this.accumulatedRawBuffer,
3420
- recentOutputBuffer: this.recentOutputBuffer,
3421
- terminalScreenText: screenText,
3422
- baseMessages: parseBaseMessages,
3423
- partialResponse: this.responseBuffer,
3424
- isWaitingForResponse: this.isWaitingForResponse,
3425
- scope: this.currentTurnScope,
3426
- runtimeSettings: this.runtimeSettings
3427
- });
3428
- const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
3429
- if (session && typeof session === "object" && Array.isArray(session.messages)) {
3430
- session.messages = this.stitchParsedMessagesWithCommittedBase(
3431
- session.messages,
3432
- this.committedMessages,
3433
- parseBaseMessages
3434
- );
3435
- }
3436
- this.parseErrorMessage = null;
3437
- return session && typeof session === "object" ? session : null;
3438
- } catch (e) {
3439
- const message = e?.message || String(e);
3440
- this.parseErrorMessage = message;
3441
- LOG.warn("CLI", `[${this.cliType}] parseSession error: ${message}`);
3442
- return null;
3443
- }
2456
+ if (typeof this.cliScripts?.parseSession !== "function") {
2457
+ this.parseErrorMessage = `${this.cliType} parseSession unavailable`;
2458
+ return null;
3444
2459
  }
3445
- if (!this.cliScripts?.detectStatus && !this.cliScripts?.parseOutput) return null;
3446
2460
  try {
3447
- const tail = this.settledBuffer;
3448
- const parsedTranscript = this.parseCurrentTranscript(
3449
- this.committedMessages,
3450
- this.responseBuffer,
3451
- this.currentTurnScope
3452
- );
3453
- const parsedModal = parsedTranscript?.activeModal && Array.isArray(parsedTranscript.activeModal.buttons) && parsedTranscript.activeModal.buttons.some((b) => typeof b === "string" && b.trim()) ? parsedTranscript.activeModal : null;
3454
- const approval = this.runParseApproval(tail);
3455
- const modal = approval || parsedModal;
3456
- const rawStatus = this.runDetectStatus(tail);
3457
- const parsedStatus = typeof parsedTranscript?.status === "string" ? parsedTranscript.status : null;
3458
- const effectiveStatus = parsedStatus === "waiting_approval" && modal ? "waiting_approval" : rawStatus || parsedStatus || "idle";
3459
- return {
3460
- status: effectiveStatus,
3461
- messages: Array.isArray(parsedTranscript?.messages) ? parsedTranscript.messages : [],
3462
- modal,
3463
- parsedStatus
3464
- };
2461
+ const screenText = this.terminalScreen.getText();
2462
+ const tail = this.recentOutputBuffer.slice(-500);
2463
+ const input = buildCliParseInput({
2464
+ accumulatedBuffer: this.accumulatedBuffer,
2465
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2466
+ recentOutputBuffer: this.recentOutputBuffer,
2467
+ terminalScreenText: screenText,
2468
+ baseMessages: [],
2469
+ partialResponse: this.responseBuffer,
2470
+ isWaitingForResponse: this.isWaitingForResponse,
2471
+ scope: this.currentTurnScope,
2472
+ runtimeSettings: this.runtimeSettings
2473
+ });
2474
+ const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
2475
+ this.parseErrorMessage = null;
2476
+ return session && typeof session === "object" ? session : null;
3465
2477
  } catch (e) {
3466
2478
  const message = e?.message || String(e);
3467
2479
  this.parseErrorMessage = message;
3468
- LOG.warn("CLI", `[${this.cliType}] parseSession fallback error: ${message}`);
2480
+ LOG.warn("CLI", `[${this.cliType}] parseSession error: ${message}`);
3469
2481
  return null;
3470
2482
  }
3471
2483
  }
@@ -3515,45 +2527,14 @@ var init_provider_cli_adapter = __esm({
3515
2527
  if (this.isWaitingForResponse && this.currentTurnScope && this.currentStatus !== "stopped") return "generating";
3516
2528
  return this.currentStatus;
3517
2529
  }
3518
- suppressStaleParsedApproval(parsed, recentBuffer, screenText) {
3519
- const actionableParsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
3520
- if (!parsed || parsed?.status !== "waiting_approval" || !actionableParsedModal) {
3521
- return parsed;
3522
- }
3523
- const inApprovalCooldown = this.lastApprovalResolvedAt > 0 && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
3524
- if (!inApprovalCooldown) {
3525
- return parsed;
3526
- }
3527
- const visibleModal = this.runParseApproval(recentBuffer);
3528
- if (visibleModal) {
3529
- return parsed;
3530
- }
3531
- const detectedStatus = this.runDetectStatus(recentBuffer);
3532
- const resolvedStatus = detectedStatus && detectedStatus !== "waiting_approval" ? detectedStatus : this.isWaitingForResponse || this.currentTurnScope ? "generating" : this.currentStatus === "waiting_approval" ? "idle" : this.currentStatus;
3533
- return {
3534
- ...parsed,
3535
- status: resolvedStatus,
3536
- activeModal: null
3537
- };
3538
- }
3539
2530
  // ─── Public API (CliAdapter) ───────────────────
3540
2531
  getStatus(options = {}) {
3541
2532
  const allowParse = options.allowParse !== false;
3542
2533
  const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
3543
2534
  let effectiveStatus = this.projectEffectiveStatus(startupModal);
3544
2535
  let effectiveModal = startupModal || this.activeModal;
3545
- if (allowParse && !startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
3546
- let parsed = this.getFreshParsedStatusCache();
3547
- if (!parsed && effectiveStatus !== "idle") {
3548
- const now = Date.now();
3549
- if (now - this.lastStatusHotPathParseAt >= _ProviderCliAdapter.STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS) {
3550
- this.lastStatusHotPathParseAt = now;
3551
- try {
3552
- parsed = this.getScriptParsedStatus();
3553
- } catch {
3554
- }
3555
- }
3556
- }
2536
+ if (allowParse && !startupModal && !effectiveModal) {
2537
+ const parsed = this.getFreshParsedStatusCache();
3557
2538
  const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
3558
2539
  if (parsed?.status === "waiting_approval" && parsedModal) {
3559
2540
  effectiveStatus = "waiting_approval";
@@ -3563,7 +2544,7 @@ var init_provider_cli_adapter = __esm({
3563
2544
  const bufferState = this.getBufferState();
3564
2545
  return {
3565
2546
  status: effectiveStatus,
3566
- messages: [...this.committedMessages],
2547
+ messages: [],
3567
2548
  workingDir: this.workingDir,
3568
2549
  activeModal: effectiveModal,
3569
2550
  errorMessage: this.parseErrorMessage || void 0,
@@ -3571,98 +2552,6 @@ var init_provider_cli_adapter = __esm({
3571
2552
  ...bufferState ? { bufferState } : {}
3572
2553
  };
3573
2554
  }
3574
- seedCommittedMessages(messages) {
3575
- const normalized = (Array.isArray(messages) ? messages : []).filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
3576
- role: message.role,
3577
- content: typeof message.content === "string" ? message.content : String(message.content || ""),
3578
- timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0,
3579
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : void 0,
3580
- kind: typeof message.kind === "string" ? message.kind : void 0,
3581
- id: typeof message.id === "string" ? message.id : void 0,
3582
- index: typeof message.index === "number" ? message.index : void 0,
3583
- providerUnitKey: typeof message.providerUnitKey === "string" ? message.providerUnitKey : void 0,
3584
- bubbleId: typeof message.bubbleId === "string" ? message.bubbleId : void 0,
3585
- bubbleState: typeof message.bubbleState === "string" ? message.bubbleState : void 0,
3586
- _turnKey: typeof message._turnKey === "string" ? message._turnKey : void 0,
3587
- meta: message.meta && typeof message.meta === "object" ? { ...message.meta } : void 0,
3588
- senderName: typeof message.senderName === "string" ? message.senderName : void 0
3589
- }));
3590
- this.committedMessages = normalized;
3591
- this.syncMessageViews();
3592
- }
3593
- getSharedCommittedPrefixLength(parsedMessages) {
3594
- const committedMessages = this.committedMessages;
3595
- const max = Math.min(parsedMessages.length, committedMessages.length);
3596
- let index = 0;
3597
- while (index < max && this.messagesShareStableIdentity(parsedMessages[index], committedMessages[index])) {
3598
- index += 1;
3599
- }
3600
- return index;
3601
- }
3602
- hydrateCommittedPrefixForParsedStatus(parsedMessages) {
3603
- const sharedPrefixLength = this.getSharedCommittedPrefixLength(parsedMessages);
3604
- if (sharedPrefixLength !== this.committedMessages.length) return null;
3605
- const committedHydratedMessages = this.committedMessages.map((message, index) => {
3606
- const timestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : this.lastOutputAt || this.currentTurnScope?.startedAt || Date.now();
3607
- const contentValue = message.content;
3608
- return {
3609
- role: message.role,
3610
- content: typeof contentValue === "string" ? contentValue : String(contentValue || ""),
3611
- timestamp,
3612
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp,
3613
- kind: message.kind,
3614
- id: message.id || `msg_${index}`,
3615
- index: typeof message.index === "number" ? message.index : index,
3616
- providerUnitKey: message.providerUnitKey,
3617
- bubbleId: message.bubbleId,
3618
- bubbleState: message.bubbleState,
3619
- _turnKey: message._turnKey,
3620
- meta: message.meta,
3621
- senderName: message.senderName
3622
- };
3623
- });
3624
- const extraMessages = parsedMessages.slice(sharedPrefixLength);
3625
- if (extraMessages.length === 0) return committedHydratedMessages;
3626
- const extraHydratedMessages = hydrateCliParsedMessages(extraMessages, {
3627
- committedMessages: [],
3628
- scope: this.currentTurnScope,
3629
- lastOutputAt: this.lastOutputAt
3630
- }).map((message, offset) => ({
3631
- ...message,
3632
- id: message.id || `msg_${sharedPrefixLength + offset}`,
3633
- index: typeof message.index === "number" ? message.index : sharedPrefixLength + offset
3634
- }));
3635
- return [...committedHydratedMessages, ...extraHydratedMessages];
3636
- }
3637
- hydrateParsedMessagesForStatus(parsedMessages) {
3638
- return this.hydrateCommittedPrefixForParsedStatus(parsedMessages) || hydrateCliParsedMessages(parsedMessages, {
3639
- committedMessages: this.committedMessages,
3640
- scope: this.currentTurnScope,
3641
- lastOutputAt: this.lastOutputAt
3642
- });
3643
- }
3644
- buildCommittedChatMessages() {
3645
- return this.committedMessages.map((message, index) => {
3646
- const rawContentValue = message.content;
3647
- const rawContent = typeof rawContentValue === "string" ? rawContentValue : String(rawContentValue || "");
3648
- const content = message.role === "assistant" && (message.kind || "standard") === "standard" ? sanitizeCliStandardMessageContent(rawContent) : rawContent;
3649
- return buildChatMessage({
3650
- role: message.role,
3651
- content,
3652
- timestamp: message.timestamp,
3653
- kind: message.kind,
3654
- meta: message.meta,
3655
- senderName: message.senderName,
3656
- id: message.id || `msg_${index}`,
3657
- index: typeof message.index === "number" ? message.index : index,
3658
- providerUnitKey: message.providerUnitKey,
3659
- bubbleId: message.bubbleId,
3660
- bubbleState: message.bubbleState,
3661
- _turnKey: message._turnKey,
3662
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
3663
- });
3664
- });
3665
- }
3666
2555
  /**
3667
2556
  * Script-based full parse — returns ReadChatResult.
3668
2557
  * Called by command handler / dashboard for rich content rendering.
@@ -3670,125 +2559,30 @@ var init_provider_cli_adapter = __esm({
3670
2559
  getScriptParsedStatus() {
3671
2560
  const screenText = this.readTerminalScreenText();
3672
2561
  const cached = this.parsedStatusCache;
3673
- if (cached && cached.committedMessagesRef === this.committedMessages && cached.responseBuffer === this.responseBuffer && cached.currentTurnScope === this.currentTurnScope && cached.recentOutputBuffer === this.recentOutputBuffer && cached.accumulatedBuffer === this.accumulatedBuffer && cached.screenText === screenText && cached.currentStatus === this.currentStatus && cached.activeModal === this.activeModal && cached.cliName === this.cliName) {
2562
+ if (cached && cached.responseBuffer === this.responseBuffer && cached.currentTurnScope === this.currentTurnScope && cached.recentOutputBuffer === this.recentOutputBuffer && cached.accumulatedBuffer === this.accumulatedBuffer && cached.screenText === screenText && cached.currentStatus === this.currentStatus && cached.activeModal === this.activeModal && cached.cliName === this.cliName) {
3674
2563
  return cached.result;
3675
2564
  }
3676
- const parsed = this.parseCurrentTranscript(
3677
- this.committedMessages,
3678
- this.responseBuffer,
3679
- this.currentTurnScope,
3680
- screenText
3681
- );
3682
- const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
3683
- if (parsedModal && parsed?.status === "waiting_approval") {
3684
- this.activeModal = parsedModal;
3685
- this.isWaitingForResponse = true;
3686
- if (this.currentStatus !== "waiting_approval") {
3687
- this.setStatus("waiting_approval", "parsed_waiting_approval");
3688
- this.onStatusChange?.();
3689
- }
2565
+ const parsed = this.runParseSession();
2566
+ if (!parsed || !Array.isArray(parsed.messages)) {
2567
+ throw new Error(this.parseErrorMessage || `${this.cliType} parseSession did not return messages`);
3690
2568
  }
3691
- if (parsed && Array.isArray(parsed.messages) && this.provider.allowInputDuringGeneration === true) {
3692
- const hydratedForCommit = normalizeCliParsedMessages(parsed.messages, {
3693
- committedMessages: this.committedMessages,
3694
- scope: this.currentTurnScope,
2569
+ const activeModal = parsed.activeModal ?? parsed.modal ?? null;
2570
+ const bufferState = this.getBufferState();
2571
+ const result = {
2572
+ id: parsed.id || "cli_session",
2573
+ status: parsed.status || this.currentStatus,
2574
+ title: parsed.title || this.cliName,
2575
+ messages: normalizeCliParsedMessages(parsed.messages, {
2576
+ scope: null,
3695
2577
  lastOutputAt: this.lastOutputAt
3696
- });
3697
- const fakeSession = {
3698
- status: parsed.status || "idle",
3699
- messages: parsed.messages,
3700
- modal: parsedModal,
3701
- parsedStatus: parsed.status || null
3702
- };
3703
- if (this.maybeCommitVisibleIdleTranscript(fakeSession, hydratedForCommit)) {
3704
- return this.getScriptParsedStatus();
3705
- }
3706
- }
3707
- const shouldPreferCommittedMessages = !this.currentTurnScope && !this.activeModal && this.currentStatus === "idle";
3708
- let result;
3709
- if (parsed && Array.isArray(parsed.messages)) {
3710
- const parsedHydratedMessages = this.hydrateParsedMessagesForStatus(parsed.messages);
3711
- const parsedLastAssistant = [...parsedHydratedMessages].reverse().find((message) => message.role === "assistant" && typeof message.content === "string" && message.content.trim());
3712
- 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");
3713
- if (shouldAdoptParsedIdleReplay) {
3714
- this.committedMessages = this.getSharedCommittedPrefixLength(parsed.messages) === this.committedMessages.length ? parsedHydratedMessages.map((message) => ({
3715
- role: message.role,
3716
- content: typeof message.content === "string" ? message.content : String(message.content || ""),
3717
- timestamp: message.timestamp,
3718
- receivedAt: message.receivedAt,
3719
- kind: message.kind,
3720
- id: message.id,
3721
- index: message.index,
3722
- meta: message.meta,
3723
- senderName: message.senderName
3724
- })) : normalizeCliParsedMessages(parsed.messages, {
3725
- committedMessages: this.committedMessages,
3726
- scope: this.currentTurnScope,
3727
- lastOutputAt: this.lastOutputAt
3728
- });
3729
- this.syncMessageViews();
3730
- if (this.currentStatus !== "idle" || this.isWaitingForResponse) {
3731
- this.responseBuffer = "";
3732
- this.isWaitingForResponse = false;
3733
- this.responseSettleIgnoreUntil = 0;
3734
- this.submitRetryUsed = false;
3735
- this.submitRetryPromptSnippet = "";
3736
- this.finishRetryCount = 0;
3737
- this.currentTurnScope = null;
3738
- this.activeModal = null;
3739
- this.setStatus("idle", "parsed_idle_replay_commit");
3740
- this.onStatusChange?.();
3741
- }
3742
- }
3743
- const shouldPreferCommittedHistoryReplay = !this.currentTurnScope && !this.activeModal && this.committedMessages.length > parsedHydratedMessages.length;
3744
- const shouldPreferCommittedIdleReplay = shouldPreferCommittedMessages && !shouldAdoptParsedIdleReplay;
3745
- const hydratedMessages = shouldPreferCommittedIdleReplay || shouldPreferCommittedHistoryReplay ? this.buildCommittedChatMessages() : parsedHydratedMessages;
3746
- result = {
3747
- id: parsed.id || "cli_session",
3748
- status: parsed.status || this.currentStatus,
3749
- title: parsed.title || this.cliName,
3750
- messages: hydratedMessages,
3751
- activeModal: parsed.activeModal ?? this.activeModal,
3752
- providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
3753
- ...this.getBufferState() ? { bufferState: this.getBufferState() } : {},
3754
- ...this.providerOwnsTranscript() ? { transcriptAuthority: "provider", coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
3755
- };
3756
- } else {
3757
- const messages = [...this.committedMessages];
3758
- const bufferState = this.getBufferState();
3759
- result = {
3760
- id: "cli_session",
3761
- status: this.currentStatus,
3762
- title: this.cliName,
3763
- messages: messages.map((message, index) => buildChatMessage({
3764
- ...message,
3765
- id: message.id || `msg_${index}`,
3766
- index: typeof message.index === "number" ? message.index : index,
3767
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
3768
- })),
3769
- activeModal: this.activeModal,
3770
- ...bufferState ? { bufferState } : {}
3771
- };
3772
- }
3773
- const hasVisibleAssistantMessage = Array.isArray(result?.messages) && result.messages.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
3774
- const shouldClampStaleGeneratingToIdle = result?.status === "generating" && this.currentStatus === "idle" && !this.currentTurnScope && !result?.activeModal && hasVisibleAssistantMessage && !hasVisibleInterruptPrompt(screenText);
3775
- if (shouldClampStaleGeneratingToIdle) {
3776
- result = {
3777
- ...result,
3778
- status: "idle",
3779
- messages: Array.isArray(result.messages) ? result.messages.map((message) => {
3780
- if (message?.role !== "assistant" || !message?.meta?.streaming) return message;
3781
- const nextMeta = { ...message.meta || {} };
3782
- delete nextMeta.streaming;
3783
- return {
3784
- ...message,
3785
- ...Object.keys(nextMeta).length > 0 ? { meta: nextMeta } : { meta: void 0 }
3786
- };
3787
- }) : result.messages
3788
- };
3789
- }
2578
+ }),
2579
+ activeModal,
2580
+ providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
2581
+ ...bufferState ? { bufferState } : {},
2582
+ ...parsed.transcriptAuthority === "provider" || parsed.transcriptAuthority === "daemon" ? { transcriptAuthority: parsed.transcriptAuthority } : this.providerOwnsTranscript() ? { transcriptAuthority: "provider" } : {},
2583
+ ...parsed.coverage === "full" || parsed.coverage === "tail" || parsed.coverage === "current-turn" ? { coverage: parsed.coverage } : this.providerOwnsTranscript() ? { coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
2584
+ };
3790
2585
  this.parsedStatusCache = {
3791
- committedMessagesRef: this.committedMessages,
3792
2586
  responseBuffer: this.responseBuffer,
3793
2587
  currentTurnScope: this.currentTurnScope,
3794
2588
  recentOutputBuffer: this.recentOutputBuffer,
@@ -3811,7 +2605,7 @@ var init_provider_cli_adapter = __esm({
3811
2605
  accumulatedRawBuffer: this.accumulatedRawBuffer,
3812
2606
  recentOutputBuffer: this.recentOutputBuffer,
3813
2607
  terminalScreenText: this.terminalScreen.getText(),
3814
- baseMessages: this.committedMessages,
2608
+ baseMessages: [],
3815
2609
  partialResponse: this.responseBuffer,
3816
2610
  isWaitingForResponse: this.isWaitingForResponse,
3817
2611
  scope: this.currentTurnScope,
@@ -3822,46 +2616,8 @@ var init_provider_cli_adapter = __esm({
3822
2616
  args: args && typeof args === "object" ? { ...args } : {}
3823
2617
  }));
3824
2618
  }
3825
- parseCurrentTranscript(baseMessages, partialResponse, scope, screenTextOverride) {
3826
- if (!this.cliScripts?.parseOutput) {
3827
- this.parseErrorMessage = null;
3828
- return null;
3829
- }
3830
- try {
3831
- const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.terminalScreen.getText();
3832
- const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
3833
- const input = buildCliParseInput({
3834
- accumulatedBuffer: this.accumulatedBuffer,
3835
- accumulatedRawBuffer: this.accumulatedRawBuffer,
3836
- recentOutputBuffer: this.recentOutputBuffer,
3837
- terminalScreenText: screenText,
3838
- baseMessages: parseBaseMessages,
3839
- partialResponse,
3840
- isWaitingForResponse: this.isWaitingForResponse,
3841
- scope,
3842
- runtimeSettings: this.runtimeSettings
3843
- });
3844
- const parsed = this.cliScripts.parseOutput(input);
3845
- if (parsed && typeof parsed === "object") {
3846
- Object.assign(parsed, validateReadChatResultPayload(parsed, `${this.cliType} parseOutput`));
3847
- }
3848
- const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
3849
- if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
3850
- normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
3851
- normalizedParsed.messages,
3852
- baseMessages,
3853
- parseBaseMessages
3854
- );
3855
- this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
3856
- }
3857
- this.parseErrorMessage = null;
3858
- return normalizedParsed;
3859
- } catch (e) {
3860
- const message = e?.message || String(e);
3861
- this.parseErrorMessage = message;
3862
- LOG.warn("CLI", `[${this.cliType}] parseOutput error: ${message}`);
3863
- throw e;
3864
- }
2619
+ parseCurrentTranscript(_baseMessages, _partialResponse, _scope, _screenTextOverride) {
2620
+ return this.runParseSession();
3865
2621
  }
3866
2622
  /** Whether this adapter has CLI scripts loaded */
3867
2623
  hasCliScripts() {
@@ -3923,8 +2679,6 @@ var init_provider_cli_adapter = __esm({
3923
2679
  commitSendUserTurn(state) {
3924
2680
  if (state.didCommitUserTurn) return;
3925
2681
  state.didCommitUserTurn = true;
3926
- this.committedMessages.push({ role: "user", content: state.text, timestamp: Date.now() });
3927
- this.syncMessageViews();
3928
2682
  }
3929
2683
  armResponseTimeout() {
3930
2684
  if (this.responseTimeout) clearTimeout(this.responseTimeout);
@@ -4116,11 +2870,6 @@ var init_provider_cli_adapter = __esm({
4116
2870
  }
4117
2871
  })() : null;
4118
2872
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
4119
- const parsedMessagesBeforeSend = Array.isArray(parsedStatusBeforeSend?.messages) ? parsedStatusBeforeSend.messages.filter((message) => message && (message.role === "user" || message.role === "assistant")) : [];
4120
- const shouldCommitParsedIdleBeforeSend = !allowInputDuringGeneration && parsedSessionStatus === "idle" && parsedMessagesBeforeSend.length > this.committedMessages.length && parsedMessagesBeforeSend.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
4121
- if (shouldCommitParsedIdleBeforeSend) {
4122
- this.commitCurrentTranscript();
4123
- }
4124
2873
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
4125
2874
  throw new Error(`${this.cliName} is still processing the previous prompt`);
4126
2875
  }
@@ -4226,9 +2975,6 @@ var init_provider_cli_adapter = __esm({
4226
2975
  activeModal: this.activeModal,
4227
2976
  parseErrorMessage: this.parseErrorMessage,
4228
2977
  messageCounts: {
4229
- committed: this.committedMessages.length,
4230
- structured: this.structuredMessages.length,
4231
- visible: this.messages.length,
4232
2978
  parsedCache: Array.isArray(parsedResult?.messages) ? parsedResult.messages.length : void 0
4233
2979
  },
4234
2980
  buffers: {
@@ -4279,8 +3025,7 @@ var init_provider_cli_adapter = __esm({
4279
3025
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
4280
3026
  responseEpoch: this.responseEpoch,
4281
3027
  resizeSuppressUntil: this.resizeSuppressUntil,
4282
- lastApprovalResolvedAt: this.lastApprovalResolvedAt,
4283
- committedMessagesChangedAt: this.committedMessagesChangedAt
3028
+ lastApprovalResolvedAt: this.lastApprovalResolvedAt
4284
3029
  },
4285
3030
  finish: {
4286
3031
  idleFinishCandidate: this.idleFinishCandidate,
@@ -4405,8 +3150,6 @@ var init_provider_cli_adapter = __esm({
4405
3150
  }
4406
3151
  clearHistory() {
4407
3152
  this.clearIdleFinishCandidate("clear_history");
4408
- this.committedMessages = [];
4409
- this.syncMessageViews();
4410
3153
  this.accumulatedBuffer = "";
4411
3154
  this.accumulatedRawBuffer = "";
4412
3155
  this.currentTurnScope = null;
@@ -4447,7 +3190,7 @@ var init_provider_cli_adapter = __esm({
4447
3190
  }
4448
3191
  resolveModal(buttonIndex) {
4449
3192
  let modal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
4450
- if (!modal && typeof this.cliScripts?.parseOutput === "function") {
3193
+ if (!modal && typeof this.cliScripts?.parseSession === "function") {
4451
3194
  try {
4452
3195
  const parsed = this.getScriptParsedStatus();
4453
3196
  const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
@@ -4514,10 +3257,8 @@ var init_provider_cli_adapter = __esm({
4514
3257
  startupParseGate: this.startupParseGate,
4515
3258
  spawnAt: this.spawnAt,
4516
3259
  workingDir: this.workingDir,
4517
- messages: this.messages,
4518
- committedMessages: this.committedMessages,
4519
- structuredMessages: this.structuredMessages,
4520
- messageCount: this.committedMessages.length,
3260
+ messages: [],
3261
+ messageCount: 0,
4521
3262
  screenText: screenText.slice(-4e3),
4522
3263
  currentTurnScope: this.currentTurnScope,
4523
3264
  startupBuffer: this.startupBuffer.slice(-4e3),
@@ -4569,7 +3310,7 @@ var init_provider_cli_adapter = __esm({
4569
3310
  lifecycleStatus: this.isWaitingForResponse ? "awaiting_response" : "idle",
4570
3311
  activeModal: this.activeModal,
4571
3312
  currentTurnScope: this.currentTurnScope,
4572
- messages: summarizeCliTraceMessages(this.committedMessages, 5)
3313
+ messages: []
4573
3314
  };
4574
3315
  }
4575
3316
  getProviderResolutionMeta() {
@@ -8182,14 +6923,223 @@ var CdpDomHandlers = class {
8182
6923
  return { success: false, error: e.message };
8183
6924
  }
8184
6925
  }
8185
- };
8186
-
8187
- // src/providers/ide-provider-instance.ts
8188
- init_contracts();
8189
- import * as crypto2 from "crypto";
6926
+ };
6927
+
6928
+ // src/providers/ide-provider-instance.ts
6929
+ import * as crypto2 from "crypto";
6930
+
6931
+ // src/providers/io-contracts.ts
6932
+ function normalizeInputEnvelope(input) {
6933
+ const normalized = normalizeInputEnvelopePayload(input);
6934
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
6935
+ return {
6936
+ parts: normalized.parts,
6937
+ textFallback,
6938
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
6939
+ };
6940
+ }
6941
+ function normalizeMessageParts(content) {
6942
+ if (typeof content === "string") return [{ type: "text", text: content }];
6943
+ if (!Array.isArray(content)) {
6944
+ if (content && typeof content === "object" && typeof content.text === "string") {
6945
+ return [{ type: "text", text: String(content.text) }];
6946
+ }
6947
+ return [];
6948
+ }
6949
+ const parts = [];
6950
+ for (const raw of content) {
6951
+ if (typeof raw === "string") {
6952
+ parts.push({ type: "text", text: raw });
6953
+ continue;
6954
+ }
6955
+ if (!raw || typeof raw !== "object") continue;
6956
+ const part = normalizeMessagePartObject(raw);
6957
+ if (part) parts.push(part);
6958
+ }
6959
+ return parts;
6960
+ }
6961
+ function flattenMessageParts(parts) {
6962
+ return parts.map((part) => {
6963
+ if (part.type === "text") return part.text;
6964
+ if (part.type === "resource") return part.resource.text || "";
6965
+ return "";
6966
+ }).filter((value) => value.length > 0).join("\n");
6967
+ }
6968
+ function normalizeInputEnvelopePayload(input) {
6969
+ if (typeof input === "string") {
6970
+ return { parts: [{ type: "text", text: input }], textFallback: input };
6971
+ }
6972
+ if (!input || typeof input !== "object") {
6973
+ return { parts: [], textFallback: "" };
6974
+ }
6975
+ const record = input;
6976
+ const nestedInput = record.input;
6977
+ if (nestedInput && typeof nestedInput === "object") {
6978
+ const nested = nestedInput;
6979
+ return {
6980
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
6981
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
6982
+ metadata: normalizeInputMetadata(nested.metadata)
6983
+ };
6984
+ }
6985
+ const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
6986
+ if (directText !== void 0) {
6987
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
6988
+ }
6989
+ const directParts = normalizeInputParts(record.parts ?? record.prompt);
6990
+ return {
6991
+ parts: directParts,
6992
+ textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
6993
+ metadata: normalizeInputMetadata(record.metadata)
6994
+ };
6995
+ }
6996
+ function normalizeInputMetadata(value) {
6997
+ if (!value || typeof value !== "object") return void 0;
6998
+ const record = value;
6999
+ const metadata = {};
7000
+ if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
7001
+ metadata.source = record.source;
7002
+ }
7003
+ if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
7004
+ metadata.clientTimestamp = record.clientTimestamp;
7005
+ }
7006
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
7007
+ }
7008
+ function normalizeInputParts(value) {
7009
+ if (!Array.isArray(value)) return [];
7010
+ const parts = [];
7011
+ for (const raw of value) {
7012
+ if (typeof raw === "string") {
7013
+ parts.push({ type: "text", text: raw });
7014
+ continue;
7015
+ }
7016
+ if (!raw || typeof raw !== "object") continue;
7017
+ const part = normalizeInputPartObject(raw);
7018
+ if (part) parts.push(part);
7019
+ }
7020
+ return parts;
7021
+ }
7022
+ function normalizeInputPartObject(raw) {
7023
+ const type = raw.type;
7024
+ if (type === "text" && typeof raw.text === "string") {
7025
+ return { type, text: raw.text };
7026
+ }
7027
+ if (type === "image" && typeof raw.mimeType === "string") {
7028
+ return {
7029
+ type,
7030
+ mimeType: raw.mimeType,
7031
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7032
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7033
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
7034
+ };
7035
+ }
7036
+ if (type === "audio" && typeof raw.mimeType === "string") {
7037
+ return {
7038
+ type,
7039
+ mimeType: raw.mimeType,
7040
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7041
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7042
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7043
+ };
7044
+ }
7045
+ if (type === "video" && typeof raw.mimeType === "string") {
7046
+ return {
7047
+ type,
7048
+ mimeType: raw.mimeType,
7049
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7050
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7051
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7052
+ };
7053
+ }
7054
+ if (type === "resource" && typeof raw.uri === "string") {
7055
+ return {
7056
+ type,
7057
+ uri: raw.uri,
7058
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7059
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
7060
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
7061
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
7062
+ };
7063
+ }
7064
+ if (type === "resource_link" && typeof raw.uri === "string") {
7065
+ return {
7066
+ type: "resource",
7067
+ uri: raw.uri,
7068
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7069
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
7070
+ };
7071
+ }
7072
+ return null;
7073
+ }
7074
+ function normalizeMessagePartObject(raw) {
7075
+ const type = raw.type;
7076
+ if (type === "text" && typeof raw.text === "string") {
7077
+ return { type, text: raw.text };
7078
+ }
7079
+ if (type === "image" && typeof raw.mimeType === "string") {
7080
+ return {
7081
+ type,
7082
+ mimeType: raw.mimeType,
7083
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7084
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
7085
+ };
7086
+ }
7087
+ if (type === "audio" && typeof raw.mimeType === "string") {
7088
+ return {
7089
+ type,
7090
+ mimeType: raw.mimeType,
7091
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7092
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7093
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7094
+ };
7095
+ }
7096
+ if (type === "video" && typeof raw.mimeType === "string") {
7097
+ return {
7098
+ type,
7099
+ mimeType: raw.mimeType,
7100
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7101
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7102
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7103
+ };
7104
+ }
7105
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
7106
+ return {
7107
+ type,
7108
+ uri: raw.uri,
7109
+ name: raw.name,
7110
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7111
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
7112
+ };
7113
+ }
7114
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
7115
+ const resource = raw.resource;
7116
+ if (typeof resource.uri !== "string") return null;
7117
+ return {
7118
+ type,
7119
+ resource: {
7120
+ uri: resource.uri,
7121
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
7122
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
7123
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
7124
+ }
7125
+ };
7126
+ }
7127
+ return null;
7128
+ }
7129
+ function flattenInputParts(parts) {
7130
+ return parts.map((part) => {
7131
+ if (part.type === "text") return part.text;
7132
+ if (part.type === "audio") return part.transcript || "";
7133
+ if (part.type === "resource") return part.text || "";
7134
+ return "";
7135
+ }).filter((value) => value.length > 0).join("\n");
7136
+ }
8190
7137
 
8191
- // src/providers/extension-provider-instance.ts
8192
- init_contracts();
7138
+ // src/providers/contracts.ts
7139
+ function flattenContent(content) {
7140
+ if (typeof content === "string") return content;
7141
+ return flattenMessageParts(normalizeMessageParts(content));
7142
+ }
8193
7143
 
8194
7144
  // src/providers/status-monitor.ts
8195
7145
  var DEFAULT_MONITOR_CONFIG = {
@@ -8303,9 +7253,151 @@ var StatusMonitor = class {
8303
7253
  }
8304
7254
  };
8305
7255
 
7256
+ // src/providers/chat-message-normalization.ts
7257
+ var BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
7258
+ var KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
7259
+ var CHAT_MESSAGE_KIND_ALIASES = {
7260
+ text: "standard",
7261
+ message: "standard",
7262
+ assistant: "standard",
7263
+ thinking: "thought",
7264
+ think: "thought",
7265
+ reasoning: "thought",
7266
+ reason: "thought",
7267
+ toolcall: "tool",
7268
+ tool_call: "tool",
7269
+ tooluse: "tool",
7270
+ tool_use: "tool",
7271
+ action: "tool",
7272
+ command: "terminal",
7273
+ cmd: "terminal",
7274
+ shell: "terminal",
7275
+ console: "terminal"
7276
+ };
7277
+ function canonicalizeKindHint(value) {
7278
+ return value.trim().toLowerCase().replace(/[\s-]+/g, "_");
7279
+ }
7280
+ function resolveBuiltinOrAliasKind(kind) {
7281
+ if (typeof kind !== "string") return null;
7282
+ const normalizedKind = canonicalizeKindHint(kind);
7283
+ if (!normalizedKind) return null;
7284
+ if (KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
7285
+ return CHAT_MESSAGE_KIND_ALIASES[normalizedKind] || null;
7286
+ }
7287
+ function inferHintKind(value) {
7288
+ const direct = resolveBuiltinOrAliasKind(value);
7289
+ if (direct) return direct;
7290
+ if (typeof value !== "string") return null;
7291
+ const normalized = canonicalizeKindHint(value);
7292
+ if (!normalized) return null;
7293
+ if (/thought|thinking|reasoning/.test(normalized)) return "thought";
7294
+ if (/tool/.test(normalized)) return "tool";
7295
+ if (/terminal|command|shell|console/.test(normalized)) return "terminal";
7296
+ return null;
7297
+ }
7298
+ function inferKindFromToolCalls(message) {
7299
+ const toolCalls = Array.isArray(message?.toolCalls) ? message.toolCalls : [];
7300
+ if (toolCalls.length === 0) return null;
7301
+ if (toolCalls.some((toolCall) => toolCall?.kind === "think")) return "thought";
7302
+ if (toolCalls.some((toolCall) => toolCall?.kind === "execute")) return "terminal";
7303
+ if (toolCalls.some((toolCall) => Array.isArray(toolCall?.content) && toolCall.content.some((entry) => entry?.type === "terminal"))) {
7304
+ return "terminal";
7305
+ }
7306
+ return "tool";
7307
+ }
7308
+ function inferMissingChatMessageKind(message) {
7309
+ const role = typeof message?.role === "string" ? message.role.trim().toLowerCase() : "";
7310
+ if (role === "system") return "system";
7311
+ const meta = message?.meta && typeof message.meta === "object" ? message.meta : void 0;
7312
+ const hintCandidates = [
7313
+ message?._sub,
7314
+ message?._type,
7315
+ meta?.label,
7316
+ typeof message?.senderName === "string" ? message.senderName : void 0
7317
+ ];
7318
+ for (const candidate of hintCandidates) {
7319
+ const inferred = inferHintKind(candidate);
7320
+ if (inferred) return inferred;
7321
+ }
7322
+ const inferredFromToolCalls = inferKindFromToolCalls(message);
7323
+ if (inferredFromToolCalls) return inferredFromToolCalls;
7324
+ return null;
7325
+ }
7326
+ function isBuiltinChatMessageKind(kind) {
7327
+ return resolveBuiltinOrAliasKind(kind) !== null;
7328
+ }
7329
+ function normalizeChatMessageKind(kind, role) {
7330
+ const resolvedKind = resolveBuiltinOrAliasKind(kind);
7331
+ if (resolvedKind) return resolvedKind;
7332
+ const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
7333
+ return normalizedRole === "system" ? "system" : "standard";
7334
+ }
7335
+ function resolveChatMessageKind(message) {
7336
+ const explicitKind = resolveBuiltinOrAliasKind(message?.kind);
7337
+ if (explicitKind) return explicitKind;
7338
+ const inferredKind = inferMissingChatMessageKind(message);
7339
+ if (inferredKind) return inferredKind;
7340
+ return normalizeChatMessageKind(message?.kind, message?.role);
7341
+ }
7342
+ function buildChatMessage(message) {
7343
+ return {
7344
+ ...message,
7345
+ kind: resolveChatMessageKind(message)
7346
+ };
7347
+ }
7348
+ function buildSystemChatMessage(message) {
7349
+ return buildChatMessage({
7350
+ ...message,
7351
+ role: "system",
7352
+ kind: message?.kind || "system"
7353
+ });
7354
+ }
7355
+ function buildRuntimeSystemChatMessage(message) {
7356
+ return buildSystemChatMessage({
7357
+ ...message,
7358
+ senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
7359
+ });
7360
+ }
7361
+ function buildAssistantChatMessage(message) {
7362
+ return buildChatMessage({
7363
+ ...message,
7364
+ role: "assistant",
7365
+ kind: message?.kind || "standard"
7366
+ });
7367
+ }
7368
+ function buildThoughtChatMessage(message) {
7369
+ return buildAssistantChatMessage({
7370
+ ...message,
7371
+ kind: message?.kind || "thought"
7372
+ });
7373
+ }
7374
+ function buildToolChatMessage(message) {
7375
+ return buildAssistantChatMessage({
7376
+ ...message,
7377
+ kind: message?.kind || "tool"
7378
+ });
7379
+ }
7380
+ function buildTerminalChatMessage(message) {
7381
+ return buildAssistantChatMessage({
7382
+ ...message,
7383
+ kind: message?.kind || "terminal"
7384
+ });
7385
+ }
7386
+ function buildUserChatMessage(message) {
7387
+ return buildChatMessage({
7388
+ ...message,
7389
+ role: "user",
7390
+ kind: message?.kind || "standard"
7391
+ });
7392
+ }
7393
+ function normalizeChatMessage(message) {
7394
+ return buildChatMessage(message);
7395
+ }
7396
+ function normalizeChatMessages(messages) {
7397
+ return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
7398
+ }
7399
+
8306
7400
  // src/providers/control-effects.ts
8307
- init_contracts();
8308
- init_chat_message_normalization();
8309
7401
  function extractProviderControlValues(controls, data) {
8310
7402
  if (!data || typeof data !== "object") return void 0;
8311
7403
  const values = {};
@@ -8499,7 +7591,6 @@ ${cleanBody}`;
8499
7591
  }
8500
7592
 
8501
7593
  // src/config/chat-history.ts
8502
- init_chat_message_normalization();
8503
7594
  import * as fs3 from "fs";
8504
7595
  import * as path10 from "path";
8505
7596
  import * as os5 from "os";
@@ -9781,9 +8872,6 @@ function resolveProviderStateSurface(params) {
9781
8872
  };
9782
8873
  }
9783
8874
 
9784
- // src/providers/extension-provider-instance.ts
9785
- init_chat_message_normalization();
9786
-
9787
8875
  // src/providers/open-panel-support.ts
9788
8876
  var IDE_PROVIDER_SESSION_CAPABILITIES_BASE = [
9789
8877
  "read_chat",
@@ -10217,7 +9305,143 @@ ${effect.notification.body || ""}`.trim();
10217
9305
 
10218
9306
  // src/providers/ide-provider-instance.ts
10219
9307
  init_logger();
10220
- init_read_chat_contract();
9308
+
9309
+ // src/providers/read-chat-contract.ts
9310
+ var VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "streaming", "long_generating"];
9311
+ var VALID_ROLES = ["user", "assistant", "system", "human"];
9312
+ var VALID_BUBBLE_STATES = ["draft", "streaming", "final", "removed"];
9313
+ var VALID_TURN_STATUSES = ["open", "waiting_approval", "complete", "error"];
9314
+ function isPlainObject3(value) {
9315
+ return !!value && typeof value === "object" && !Array.isArray(value);
9316
+ }
9317
+ function isFiniteNumber(value) {
9318
+ return typeof value === "number" && Number.isFinite(value);
9319
+ }
9320
+ function validateStatus(status, source) {
9321
+ if (typeof status !== "string" || !VALID_STATUSES.includes(status)) {
9322
+ throw new Error(`${source}: status must be one of ${VALID_STATUSES.join(", ")}`);
9323
+ }
9324
+ return status;
9325
+ }
9326
+ function validateRole(role, source, index) {
9327
+ if (typeof role !== "string" || !VALID_ROLES.includes(role)) {
9328
+ throw new Error(`${source}: messages[${index}].role must be one of ${VALID_ROLES.join(", ")}`);
9329
+ }
9330
+ return role;
9331
+ }
9332
+ function validateBubbleState(state, source, index) {
9333
+ if (typeof state !== "string" || !VALID_BUBBLE_STATES.includes(state)) {
9334
+ throw new Error(`${source}: messages[${index}].bubbleState must be one of ${VALID_BUBBLE_STATES.join(", ")}`);
9335
+ }
9336
+ return state;
9337
+ }
9338
+ function validateTurnStatus(turnStatus, source) {
9339
+ if (typeof turnStatus !== "string" || !VALID_TURN_STATUSES.includes(turnStatus)) {
9340
+ throw new Error(`${source}: turnStatus must be one of ${VALID_TURN_STATUSES.join(", ")}`);
9341
+ }
9342
+ return turnStatus;
9343
+ }
9344
+ function validateMessageContent(content, source, index) {
9345
+ if (typeof content === "string") return content;
9346
+ if (Array.isArray(content)) return normalizeMessageParts(content);
9347
+ throw new Error(`${source}: messages[${index}].content must be a string or structured content array`);
9348
+ }
9349
+ function validateMessage(message, source, index) {
9350
+ if (!isPlainObject3(message)) {
9351
+ throw new Error(`${source}: messages[${index}] must be an object`);
9352
+ }
9353
+ const normalized = {
9354
+ role: validateRole(message.role, source, index),
9355
+ content: validateMessageContent(message.content, source, index)
9356
+ };
9357
+ if (typeof message.kind === "string") normalized.kind = message.kind;
9358
+ if (typeof message.id === "string") normalized.id = message.id;
9359
+ if (typeof message.bubbleId === "string") normalized.bubbleId = message.bubbleId;
9360
+ if (typeof message.providerUnitKey === "string") normalized.providerUnitKey = message.providerUnitKey;
9361
+ if (message.bubbleState !== void 0) normalized.bubbleState = validateBubbleState(message.bubbleState, source, index);
9362
+ if (isFiniteNumber(message.index)) normalized.index = message.index;
9363
+ if (isFiniteNumber(message.timestamp)) normalized.timestamp = message.timestamp;
9364
+ if (isFiniteNumber(message.receivedAt)) normalized.receivedAt = message.receivedAt;
9365
+ if (typeof message._turnKey === "string") normalized._turnKey = message._turnKey;
9366
+ if (Array.isArray(message.toolCalls)) normalized.toolCalls = message.toolCalls;
9367
+ if (isPlainObject3(message.meta)) normalized.meta = message.meta;
9368
+ if (typeof message.senderName === "string") normalized.senderName = message.senderName;
9369
+ if (typeof message._type === "string") normalized._type = message._type;
9370
+ if (typeof message._sub === "string") normalized._sub = message._sub;
9371
+ return normalized;
9372
+ }
9373
+ function validateModal(activeModal, status, source) {
9374
+ if (activeModal == null) {
9375
+ if (status === "waiting_approval") {
9376
+ throw new Error(`${source}: waiting_approval status requires activeModal with buttons`);
9377
+ }
9378
+ return activeModal === null ? null : void 0;
9379
+ }
9380
+ if (!isPlainObject3(activeModal)) {
9381
+ throw new Error(`${source}: activeModal must be an object when provided`);
9382
+ }
9383
+ if (typeof activeModal.message !== "string") {
9384
+ throw new Error(`${source}: activeModal.message must be a string`);
9385
+ }
9386
+ if (!Array.isArray(activeModal.buttons) || activeModal.buttons.some((button) => typeof button !== "string" || !button.trim())) {
9387
+ throw new Error(`${source}: activeModal.buttons must be a non-empty string array`);
9388
+ }
9389
+ const normalized = {
9390
+ message: activeModal.message,
9391
+ buttons: activeModal.buttons.map((button) => button.trim())
9392
+ };
9393
+ if (isFiniteNumber(activeModal.width)) normalized.width = activeModal.width;
9394
+ if (isFiniteNumber(activeModal.height)) normalized.height = activeModal.height;
9395
+ return normalized;
9396
+ }
9397
+ function validateControlValues(controlValues, source) {
9398
+ if (controlValues === void 0) return void 0;
9399
+ if (!isPlainObject3(controlValues)) {
9400
+ throw new Error(`${source}: controlValues must be an object when provided`);
9401
+ }
9402
+ const normalized = {};
9403
+ for (const [key, value] of Object.entries(controlValues)) {
9404
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
9405
+ throw new Error(`${source}: controlValues.${key} must be string, number, or boolean`);
9406
+ }
9407
+ normalized[key] = value;
9408
+ }
9409
+ return normalized;
9410
+ }
9411
+ function validateReadChatResultPayload(raw, source = "read_chat") {
9412
+ if (!isPlainObject3(raw)) {
9413
+ throw new Error(`${source}: payload must be an object`);
9414
+ }
9415
+ const status = validateStatus(raw.status, source);
9416
+ if (!Array.isArray(raw.messages)) {
9417
+ throw new Error(`${source}: messages must be an array`);
9418
+ }
9419
+ const messages = raw.messages.map((message, index) => validateMessage(message, source, index));
9420
+ const activeModal = validateModal(raw.activeModal, status, source);
9421
+ const controlValues = validateControlValues(raw.controlValues, source);
9422
+ const normalized = {
9423
+ status,
9424
+ messages
9425
+ };
9426
+ if (activeModal !== void 0) normalized.activeModal = activeModal;
9427
+ if (typeof raw.id === "string") normalized.id = raw.id;
9428
+ if (typeof raw.title === "string") normalized.title = raw.title;
9429
+ if (typeof raw.currentTurnId === "string") normalized.currentTurnId = raw.currentTurnId;
9430
+ if (raw.turnStatus !== void 0) normalized.turnStatus = validateTurnStatus(raw.turnStatus, source);
9431
+ if (typeof raw.agentType === "string") normalized.agentType = raw.agentType;
9432
+ if (typeof raw.agentName === "string") normalized.agentName = raw.agentName;
9433
+ if (typeof raw.extensionId === "string") normalized.extensionId = raw.extensionId;
9434
+ if (typeof raw.inputContent === "string") normalized.inputContent = raw.inputContent;
9435
+ if (typeof raw.isVisible === "boolean") normalized.isVisible = raw.isVisible;
9436
+ if (typeof raw.isWelcomeScreen === "boolean") normalized.isWelcomeScreen = raw.isWelcomeScreen;
9437
+ if (controlValues) normalized.controlValues = controlValues;
9438
+ if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
9439
+ if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
9440
+ if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
9441
+ if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
9442
+ if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
9443
+ return normalized;
9444
+ }
10221
9445
 
10222
9446
  // src/providers/approval-utils.ts
10223
9447
  var DEFAULT_APPROVAL_POSITIVE_HINTS = [
@@ -10267,7 +9491,6 @@ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
10267
9491
  }
10268
9492
 
10269
9493
  // src/providers/ide-provider-instance.ts
10270
- init_chat_message_normalization();
10271
9494
  var IdeProviderInstance = class {
10272
9495
  type;
10273
9496
  category = "ide";
@@ -11726,7 +10949,6 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
11726
10949
  }
11727
10950
 
11728
10951
  // src/commands/chat-commands.ts
11729
- init_contracts();
11730
10952
  import * as fs4 from "fs";
11731
10953
  import * as os6 from "os";
11732
10954
  import * as path11 from "path";
@@ -11788,7 +11010,6 @@ function assertProviderSupportsDeclaredInput(provider, input) {
11788
11010
  }
11789
11011
 
11790
11012
  // src/commands/chat-commands.ts
11791
- init_read_chat_contract();
11792
11013
  init_logger();
11793
11014
 
11794
11015
  // src/logging/debug-trace.ts
@@ -11916,10 +11137,6 @@ function buildChatTailDeliverySignature(payload) {
11916
11137
  payload.historySessionId || "",
11917
11138
  payload.status,
11918
11139
  payload.title || "",
11919
- payload.syncMode,
11920
- String(payload.replaceFrom),
11921
- String(payload.totalMessages),
11922
- payload.lastMessageSignature,
11923
11140
  payload.activeModal ? `${payload.activeModal.message}|${payload.activeModal.buttons.join("")}` : "",
11924
11141
  stringifySignatureMessages(payload.messages)
11925
11142
  ]);
@@ -11935,7 +11152,6 @@ function buildSessionModalDeliverySignature(payload) {
11935
11152
  }
11936
11153
 
11937
11154
  // src/commands/chat-commands.ts
11938
- init_chat_message_normalization();
11939
11155
  var RECENT_SEND_WINDOW_MS = 1200;
11940
11156
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
11941
11157
  var recentSendByTarget = /* @__PURE__ */ new Map();
@@ -12036,99 +11252,13 @@ function parseMaybeJson(value) {
12036
11252
  return value;
12037
11253
  }
12038
11254
  }
12039
- function getChatMessageSignature(message) {
12040
- return buildChatMessageSignature(message);
12041
- }
12042
- function normalizeReadChatCursor(args) {
12043
- const knownMessageCount = Math.max(0, Number(args?.knownMessageCount || 0));
12044
- const lastMessageSignature = typeof args?.lastMessageSignature === "string" ? args.lastMessageSignature : "";
12045
- const tailLimit = Math.max(0, Number(args?.tailLimit || 0));
12046
- return { knownMessageCount, lastMessageSignature, tailLimit };
11255
+ function normalizeReadChatTailLimit(args) {
11256
+ const value = Number(args?.tailLimit || 0);
11257
+ return Number.isFinite(value) ? Math.max(0, value) : 0;
12047
11258
  }
12048
11259
  function normalizeReadChatMessages(payload) {
12049
11260
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
12050
- return normalizeChatMessages(messages);
12051
- }
12052
- function normalizeReadChatReplayTextContent(content) {
12053
- return flattenContent(content || "").replace(/\s+/g, " ").trim();
12054
- }
12055
- function getReadChatReplayCollapseInfo(message) {
12056
- if (!message) return null;
12057
- const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
12058
- const kind = typeof message.kind === "string" ? message.kind.trim().toLowerCase() : "standard";
12059
- const senderName = typeof message.senderName === "string" ? message.senderName.trim().toLowerCase() : "";
12060
- const collapsible = role === "assistant" || role === "system";
12061
- if (!collapsible) return { role, kind, senderName, content: "", signature: "", collapsible };
12062
- const content = normalizeReadChatReplayTextContent(message.content);
12063
- return {
12064
- role,
12065
- kind,
12066
- senderName,
12067
- content,
12068
- signature: `${role}:${kind}:${senderName}:${content}`,
12069
- collapsible
12070
- };
12071
- }
12072
- function isStableReadChatAssistantAnswerInfo(info) {
12073
- if (!info) return false;
12074
- if (info.role !== "assistant") return false;
12075
- if (info.kind && info.kind !== "standard") return false;
12076
- if (info.content.length < 160) return false;
12077
- if (/^(bash|shell|terminal) command\b/i.test(info.content)) return false;
12078
- return true;
12079
- }
12080
- function isReplayedAssistantAnswerAfterStableAnswerInfo(info, stableContent) {
12081
- if (!info || !stableContent) return false;
12082
- if (info.role !== "assistant") return false;
12083
- if (info.kind && info.kind !== "standard") return false;
12084
- const content = info.content;
12085
- if (content.length < 80 || stableContent.length < 80) return false;
12086
- return content === stableContent || content.startsWith(stableContent) || stableContent.startsWith(content);
12087
- }
12088
- function collapseReplayDuplicatesFromReadChat(messages) {
12089
- const collapsed = [];
12090
- const replaySignaturesInCurrentTurn = /* @__PURE__ */ new Set();
12091
- let stableAssistantAnswerContentInCurrentTurn = "";
12092
- let stableAssistantAnswerCollapsedIndex = -1;
12093
- let stableAssistantAnswerHadInterveningActivity = false;
12094
- let previousReplaySignature = "";
12095
- for (const message of messages) {
12096
- const info = getReadChatReplayCollapseInfo(message);
12097
- if (info?.role === "user") {
12098
- replaySignaturesInCurrentTurn.clear();
12099
- stableAssistantAnswerContentInCurrentTurn = "";
12100
- stableAssistantAnswerCollapsedIndex = -1;
12101
- stableAssistantAnswerHadInterveningActivity = false;
12102
- previousReplaySignature = "";
12103
- }
12104
- if (info?.collapsible && info.signature) {
12105
- if (previousReplaySignature === info.signature) continue;
12106
- if (replaySignaturesInCurrentTurn.has(info.signature)) continue;
12107
- if (isReplayedAssistantAnswerAfterStableAnswerInfo(info, stableAssistantAnswerContentInCurrentTurn)) {
12108
- 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);
12109
- if (isAdjacentFullerAssistantAnswer) {
12110
- collapsed[stableAssistantAnswerCollapsedIndex] = message;
12111
- replaySignaturesInCurrentTurn.add(info.signature);
12112
- stableAssistantAnswerContentInCurrentTurn = info.content;
12113
- previousReplaySignature = info.signature;
12114
- }
12115
- continue;
12116
- }
12117
- }
12118
- collapsed.push(message);
12119
- previousReplaySignature = info?.collapsible ? info.signature : "";
12120
- if (info?.collapsible && info.signature) {
12121
- replaySignaturesInCurrentTurn.add(info.signature);
12122
- }
12123
- if (isStableReadChatAssistantAnswerInfo(info)) {
12124
- stableAssistantAnswerContentInCurrentTurn = info?.content || "";
12125
- stableAssistantAnswerCollapsedIndex = collapsed.length - 1;
12126
- stableAssistantAnswerHadInterveningActivity = false;
12127
- } else if (stableAssistantAnswerContentInCurrentTurn && info?.role === "assistant" && (!info.kind || info.kind !== "standard")) {
12128
- stableAssistantAnswerHadInterveningActivity = true;
12129
- }
12130
- }
12131
- return collapsed;
11261
+ return messages;
12132
11262
  }
12133
11263
  function deriveHistoryDedupKey(message) {
12134
11264
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -12153,102 +11283,12 @@ function toHistoryPersistedMessages(messages) {
12153
11283
  historyDedupKey: deriveHistoryDedupKey(message)
12154
11284
  }));
12155
11285
  }
12156
- function findLastMessageIndexBySignature(messages, signature) {
12157
- if (!signature) return -1;
12158
- for (let index = messages.length - 1; index >= 0; index -= 1) {
12159
- if (getChatMessageSignature(messages[index]) === signature) {
12160
- return index;
12161
- }
12162
- }
12163
- return -1;
12164
- }
12165
- function buildBoundedTailSync(messages, cursor) {
11286
+ function buildFullTail(messages, tailLimit) {
12166
11287
  const totalMessages = messages.length;
12167
- const tailMessages = cursor.tailLimit > 0 && totalMessages > cursor.tailLimit ? messages.slice(-cursor.tailLimit) : messages;
11288
+ const tailMessages = tailLimit > 0 ? messages.slice(-tailLimit) : messages;
12168
11289
  return {
12169
- syncMode: "full",
12170
- replaceFrom: 0,
12171
11290
  messages: tailMessages,
12172
- totalMessages,
12173
- lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1])
12174
- };
12175
- }
12176
- function computeReadChatSync(messages, cursor) {
12177
- const totalMessages = messages.length;
12178
- const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
12179
- const { knownMessageCount, lastMessageSignature: knownSignature } = cursor;
12180
- if (!knownMessageCount || !knownSignature) {
12181
- return {
12182
- syncMode: "full",
12183
- replaceFrom: 0,
12184
- messages,
12185
- totalMessages,
12186
- lastMessageSignature
12187
- };
12188
- }
12189
- if (knownMessageCount > totalMessages) {
12190
- return {
12191
- syncMode: "full",
12192
- replaceFrom: 0,
12193
- messages,
12194
- totalMessages,
12195
- lastMessageSignature
12196
- };
12197
- }
12198
- if (knownMessageCount === totalMessages && knownSignature === lastMessageSignature) {
12199
- return {
12200
- syncMode: "noop",
12201
- replaceFrom: totalMessages,
12202
- messages: [],
12203
- totalMessages,
12204
- lastMessageSignature
12205
- };
12206
- }
12207
- if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
12208
- const requestedTailCount = Math.min(totalMessages, cursor.tailLimit);
12209
- if (knownMessageCount >= requestedTailCount) {
12210
- return {
12211
- syncMode: "noop",
12212
- replaceFrom: totalMessages,
12213
- messages: [],
12214
- totalMessages,
12215
- lastMessageSignature
12216
- };
12217
- }
12218
- return buildBoundedTailSync(messages, cursor);
12219
- }
12220
- if (knownMessageCount < totalMessages) {
12221
- const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
12222
- if (anchorSignature === knownSignature) {
12223
- return {
12224
- syncMode: "append",
12225
- replaceFrom: knownMessageCount,
12226
- messages: messages.slice(knownMessageCount),
12227
- totalMessages,
12228
- lastMessageSignature
12229
- };
12230
- }
12231
- if (cursor.tailLimit > 0) {
12232
- const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
12233
- if (signatureIndex >= 0) {
12234
- return {
12235
- syncMode: "append",
12236
- replaceFrom: knownMessageCount,
12237
- messages: messages.slice(signatureIndex + 1),
12238
- totalMessages,
12239
- lastMessageSignature
12240
- };
12241
- }
12242
- return buildBoundedTailSync(messages, cursor);
12243
- }
12244
- }
12245
- const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
12246
- return {
12247
- syncMode: replaceFrom === 0 ? "full" : "replace_tail",
12248
- replaceFrom,
12249
- messages: replaceFrom === 0 ? messages : messages.slice(replaceFrom),
12250
- totalMessages,
12251
- lastMessageSignature
11291
+ totalMessages
12252
11292
  };
12253
11293
  }
12254
11294
  function hasNonEmptyModalButtons(activeModal) {
@@ -12283,31 +11323,13 @@ function buildReadChatCommandResult(payload, args) {
12283
11323
  } catch (error) {
12284
11324
  return { success: false, error: error?.message || String(error) };
12285
11325
  }
12286
- const messages = collapseReplayDuplicatesFromReadChat(normalizeReadChatMessages(validatedPayload));
12287
- const cursor = normalizeReadChatCursor(args);
12288
- if (!cursor.knownMessageCount && !cursor.lastMessageSignature && cursor.tailLimit > 0 && messages.length > cursor.tailLimit) {
12289
- const tailMessages = messages.slice(-cursor.tailLimit);
12290
- const lastMessageSignature = getChatMessageSignature(tailMessages[tailMessages.length - 1]);
12291
- return {
12292
- success: true,
12293
- ...validatedPayload,
12294
- messages: tailMessages,
12295
- syncMode: "full",
12296
- replaceFrom: 0,
12297
- totalMessages: messages.length,
12298
- lastMessageSignature,
12299
- ...debugReadChat ? { debugReadChat } : {}
12300
- };
12301
- }
12302
- const sync = computeReadChatSync(messages, cursor);
11326
+ const messages = normalizeReadChatMessages(validatedPayload);
11327
+ const sync = buildFullTail(messages, normalizeReadChatTailLimit(args));
12303
11328
  return {
12304
11329
  success: true,
12305
11330
  ...validatedPayload,
12306
11331
  messages: sync.messages,
12307
- syncMode: sync.syncMode,
12308
- replaceFrom: sync.replaceFrom,
12309
11332
  totalMessages: sync.totalMessages,
12310
- lastMessageSignature: sync.lastMessageSignature,
12311
11333
  ...debugReadChat ? { debugReadChat } : {}
12312
11334
  };
12313
11335
  }
@@ -12532,10 +11554,6 @@ async function handleGetChatDebugBundle(h, args) {
12532
11554
  status: readResult.status,
12533
11555
  title: readResult.title,
12534
11556
  totalMessages: readResult.totalMessages,
12535
- returnedMessages: Array.isArray(readResult.messages) ? readResult.messages.length : void 0,
12536
- syncMode: readResult.syncMode,
12537
- replaceFrom: readResult.replaceFrom,
12538
- lastMessageSignature: readResult.lastMessageSignature,
12539
11557
  providerSessionId: readResult.providerSessionId,
12540
11558
  transcriptAuthority: readResult.transcriptAuthority,
12541
11559
  coverage: readResult.coverage,
@@ -12645,22 +11663,13 @@ function toNonNegativeNumber(value) {
12645
11663
  return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
12646
11664
  }
12647
11665
  function getCliVisibleTranscriptCount(adapter) {
12648
- const adapterStatus = adapter?.getStatus?.() || {};
12649
- const adapterMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
12650
- let parsedRecord = null;
12651
- if (typeof adapter?.getScriptParsedStatus === "function") {
12652
- try {
12653
- const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
12654
- parsedRecord = parsed && typeof parsed === "object" ? parsed : null;
12655
- } catch {
12656
- parsedRecord = null;
12657
- }
11666
+ if (typeof adapter?.getScriptParsedStatus !== "function") return 0;
11667
+ try {
11668
+ const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
11669
+ return Array.isArray(parsed?.messages) ? parsed.messages.length : 0;
11670
+ } catch {
11671
+ return 0;
12658
11672
  }
12659
- const parsedMessages = Array.isArray(parsedRecord?.messages) ? parsedRecord.messages : [];
12660
- if (!parsedRecord) return adapterMessages.length;
12661
- const parsedIsProviderAuthoritative = parsedRecord.transcriptAuthority === "provider" || parsedRecord.coverage === "full";
12662
- const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && adapterMessages.length > 0 && adapterMessages.length > parsedMessages.length;
12663
- return shouldPreferAdapterMessages ? adapterMessages.length : parsedMessages.length;
12664
11673
  }
12665
11674
  async function getStableExtensionBaseline(h) {
12666
11675
  const first = await readExtensionChatState(h);
@@ -12722,52 +11731,46 @@ async function handleReadChat(h, args) {
12722
11731
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
12723
11732
  if (adapter) {
12724
11733
  _log(`${transport} adapter: ${adapter.cliType}`);
11734
+ if (typeof adapter.getScriptParsedStatus !== "function") {
11735
+ return { success: false, error: `${transport} adapter parseSession unavailable` };
11736
+ }
12725
11737
  let parsedStatus = null;
12726
- if (typeof adapter.getScriptParsedStatus === "function") {
12727
- try {
12728
- parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
12729
- } catch (error) {
12730
- return { success: false, error: error?.message || String(error) };
12731
- }
11738
+ try {
11739
+ parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
11740
+ } catch (error) {
11741
+ return { success: false, error: error?.message || String(error) };
12732
11742
  }
12733
11743
  const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
12734
- const adapterStatus = adapter.getStatus();
12735
- const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.coverage === "full";
12736
- const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
12737
- const parsedShowsApproval = hasNonEmptyModalButtons(parsedRecord?.activeModal) && parsedRecord?.status === "waiting_approval";
12738
- const status = parsedRecord ? {
12739
- ...parsedRecord,
12740
- messages: shouldPreferAdapterMessages ? adapterStatus.messages : parsedRecord.messages,
12741
- status: parsedShowsApproval ? parsedRecord.status : adapterStatus.status !== "idle" ? adapterStatus.status : parsedRecord.status || adapterStatus.status,
12742
- activeModal: parsedRecord.activeModal || adapterStatus.activeModal
12743
- } : adapterStatus;
12744
- const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
12745
- const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
12746
- const transcriptAuthority = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
12747
- const coverage = parsedRecord?.coverage === "full" || parsedRecord?.coverage === "tail" || parsedRecord?.coverage === "current-turn" ? parsedRecord.coverage : void 0;
12748
- if (status) {
12749
- LOG.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}`);
12750
- return buildReadChatCommandResult({
12751
- messages: status.messages || [],
12752
- status: status.status,
12753
- activeModal: status.activeModal,
12754
- debugReadChat: {
12755
- provider: adapter.cliType,
12756
- targetSessionId: String(args?.targetSessionId || ""),
12757
- adapterStatus: String(adapterStatus.status || ""),
12758
- parsedStatus: String(parsedRecord?.status || ""),
12759
- returnedStatus: String(status.status || ""),
12760
- shouldPreferAdapterMessages,
12761
- adapterMsgCount: Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0,
12762
- parsedMsgCount: Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0,
12763
- returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
12764
- },
12765
- ...title ? { title } : {},
12766
- ...providerSessionId ? { providerSessionId } : {},
12767
- ...transcriptAuthority ? { transcriptAuthority } : {},
12768
- ...coverage ? { coverage } : {}
12769
- }, args);
12770
- }
11744
+ if (!parsedRecord || !Array.isArray(parsedRecord.messages)) {
11745
+ return { success: false, error: `${transport} parser did not return messages` };
11746
+ }
11747
+ const adapterStatus = typeof adapter.getStatus === "function" ? adapter.getStatus() : {};
11748
+ const title = typeof parsedRecord.title === "string" ? parsedRecord.title : void 0;
11749
+ const providerSessionId = typeof parsedRecord.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
11750
+ const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
11751
+ const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
11752
+ const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
11753
+ const returnedStatus = parsedRecord.status || "idle";
11754
+ LOG.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}`);
11755
+ return buildReadChatCommandResult({
11756
+ messages: parsedRecord.messages,
11757
+ status: returnedStatus,
11758
+ activeModal,
11759
+ debugReadChat: {
11760
+ provider: adapter.cliType,
11761
+ targetSessionId: String(args?.targetSessionId || ""),
11762
+ adapterStatus: String(adapterStatus.status || ""),
11763
+ parsedStatus: String(parsedRecord.status || ""),
11764
+ returnedStatus: String(returnedStatus || ""),
11765
+ shouldPreferAdapterMessages: false,
11766
+ parsedMsgCount: parsedRecord.messages.length,
11767
+ returnedMsgCount: parsedRecord.messages.length
11768
+ },
11769
+ ...title ? { title } : {},
11770
+ ...providerSessionId ? { providerSessionId } : {},
11771
+ ...transcriptAuthority ? { transcriptAuthority } : {},
11772
+ ...coverage ? { coverage } : {}
11773
+ }, args);
12771
11774
  }
12772
11775
  return { success: false, error: `${transport} adapter not found` };
12773
11776
  }
@@ -15066,7 +14069,6 @@ import chalk from "chalk";
15066
14069
  init_config();
15067
14070
 
15068
14071
  // src/providers/cli-provider-instance.ts
15069
- init_contracts();
15070
14072
  import * as os12 from "os";
15071
14073
  import * as path15 from "path";
15072
14074
  import * as crypto3 from "crypto";
@@ -15093,7 +14095,6 @@ function normalizeProviderSessionId(provider, providerSessionId) {
15093
14095
  }
15094
14096
 
15095
14097
  // src/providers/cli-provider-instance.ts
15096
- init_chat_message_normalization();
15097
14098
  function normalizePersistableCliHistoryContent(content) {
15098
14099
  return flattenContent(content).replace(/\s+/g, " ").trim();
15099
14100
  }
@@ -15333,17 +14334,11 @@ var CliProviderInstance = class {
15333
14334
  }
15334
14335
  const runtime = this.adapter.getRuntimeMetadata();
15335
14336
  this.maybeAppendRuntimeRecoveryMessage(runtime);
15336
- let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : parseErrorMessage ? normalizeChatMessages(Array.isArray(adapterStatus.messages) ? adapterStatus.messages : []) : [];
14337
+ let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
15337
14338
  const historyMessageCount = Number.isFinite(parsedStatus?.historyMessageCount) ? Math.max(0, Number(parsedStatus.historyMessageCount)) : null;
15338
14339
  if (historyMessageCount !== null) {
15339
14340
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
15340
14341
  }
15341
- const committedMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
15342
- const isActiveNonIdle = adapterStatus.status !== "idle";
15343
- const shouldApplyCommittedFloor = parsedMessages.length < committedMessages.length && (adapterStatus.status === "waiting_approval" || isActiveNonIdle && historyMessageCount === null);
15344
- if (shouldApplyCommittedFloor) {
15345
- parsedMessages = normalizeChatMessages(committedMessages);
15346
- }
15347
14342
  const mergedMessages = this.mergeConversationMessages(parsedMessages);
15348
14343
  const canonicalBackedHistory = this.syncCanonicalSavedHistoryIfNeeded();
15349
14344
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
@@ -15436,11 +14431,9 @@ var CliProviderInstance = class {
15436
14431
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
15437
14432
  const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
15438
14433
  const runtime = this.adapter.getRuntimeMetadata();
15439
- const lastCommittedMessageActivityAt = typeof this.adapter.getLastCommittedMessageActivityAt === "function" ? this.adapter.getLastCommittedMessageActivityAt() : 0;
15440
14434
  return {
15441
14435
  id: this.instanceId,
15442
14436
  status: visibleStatus,
15443
- lastMessageAt: lastCommittedMessageActivityAt || void 0,
15444
14437
  runtimeLifecycle: runtime?.lifecycle ?? null,
15445
14438
  runtimeSurfaceKind: runtime?.surfaceKind,
15446
14439
  runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
@@ -15546,7 +14539,7 @@ var CliProviderInstance = class {
15546
14539
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
15547
14540
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
15548
14541
  const partial = this.adapter.getPartialResponse();
15549
- const progressFingerprint = newStatus === "generating" ? `${partial || ""}::${adapterStatus.messages.at(-1)?.content || ""}`.slice(-2e3) : void 0;
14542
+ const progressFingerprint = newStatus === "generating" ? `${partial || ""}`.slice(-2e3) : void 0;
15550
14543
  const previousStatus = this.lastStatus;
15551
14544
  if (newStatus !== this.lastStatus) {
15552
14545
  LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
@@ -15992,18 +14985,6 @@ ${effect.notification.body || ""}`.trim();
15992
14985
  receivedAt: message.receivedAt
15993
14986
  }));
15994
14987
  this.suppressIdleHistoryReplay = restoredHistory.messages.length > 0;
15995
- if (restoredHistory.messages.length > 0) {
15996
- this.adapter.seedCommittedMessages(
15997
- restoredHistory.messages.map((message) => ({
15998
- role: message.role,
15999
- content: message.content,
16000
- timestamp: message.receivedAt,
16001
- receivedAt: message.receivedAt,
16002
- kind: message.kind,
16003
- senderName: message.senderName
16004
- }))
16005
- );
16006
- }
16007
14988
  }
16008
14989
  getProbeDirectories() {
16009
14990
  const dirs = /* @__PURE__ */ new Set();
@@ -16050,7 +15031,6 @@ ${effect.notification.body || ""}`.trim();
16050
15031
  };
16051
15032
 
16052
15033
  // src/providers/acp-provider-instance.ts
16053
- init_contracts();
16054
15034
  import { Readable, Writable } from "stream";
16055
15035
  import { spawn } from "child_process";
16056
15036
  import {
@@ -16059,7 +15039,6 @@ import {
16059
15039
  RequestError,
16060
15040
  PROTOCOL_VERSION
16061
15041
  } from "@agentclientprotocol/sdk";
16062
- init_chat_message_normalization();
16063
15042
  init_logger();
16064
15043
  function getPromptCapabilityFlags(agentCapabilities) {
16065
15044
  const prompt = agentCapabilities?.promptCapabilities || {};
@@ -17203,7 +16182,6 @@ ${rawInput}` : rawInput;
17203
16182
  };
17204
16183
 
17205
16184
  // src/commands/cli-manager.ts
17206
- init_contracts();
17207
16185
  init_logger();
17208
16186
 
17209
16187
  // src/commands/hosted-runtime-restore.ts
@@ -20137,13 +19115,24 @@ async function launchWithCdp(options = {}) {
20137
19115
  break;
20138
19116
  }
20139
19117
  }
19118
+ if (!cdpReady) {
19119
+ return {
19120
+ success: false,
19121
+ ideId: targetIde.id,
19122
+ ideName: targetIde.displayName,
19123
+ port,
19124
+ action: "failed",
19125
+ message: "",
19126
+ error: `${targetIde.displayName} launched but CDP did not become available on port ${port}`
19127
+ };
19128
+ }
20140
19129
  return {
20141
19130
  success: true,
20142
19131
  ideId: targetIde.id,
20143
19132
  ideName: targetIde.displayName,
20144
19133
  port,
20145
19134
  action: alreadyRunning ? "restarted" : "started",
20146
- message: cdpReady ? `${targetIde.displayName} launched with CDP on port ${port}` : `${targetIde.displayName} launched (CDP may take a moment to initialize)`
19135
+ message: `${targetIde.displayName} launched with CDP on port ${port}`
20147
19136
  };
20148
19137
  } catch (e) {
20149
19138
  return {
@@ -22071,9 +21060,6 @@ var DEFAULT_DAEMON_PORT = 19222;
22071
21060
  var DAEMON_WS_PATH = "/ipc";
22072
21061
 
22073
21062
  // src/chat/subscription-updates.ts
22074
- function normalizeSyncMode(syncMode) {
22075
- return syncMode === "append" || syncMode === "replace_tail" || syncMode === "noop" || syncMode === "full" ? syncMode : "full";
22076
- }
22077
21063
  function normalizeModalButtons(value) {
22078
21064
  return Array.isArray(value) ? value.filter((button) => typeof button === "string") : [];
22079
21065
  }
@@ -22100,55 +21086,39 @@ function normalizeSessionModalFields(activeModal) {
22100
21086
  modalButtons: normalizeModalButtons(activeModal.buttons)
22101
21087
  };
22102
21088
  }
22103
- function buildNextChatCursor(cursor, result) {
22104
- return {
22105
- knownMessageCount: Math.max(0, Number(result.totalMessages || cursor.knownMessageCount)),
22106
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : cursor.lastMessageSignature,
22107
- tailLimit: cursor.tailLimit
22108
- };
22109
- }
22110
21089
  function prepareSessionChatTailUpdate(input) {
22111
21090
  const result = input.result;
22112
- if (!result?.success || result.syncMode === "noop") {
21091
+ if (!result?.success) {
22113
21092
  return {
22114
- cursor: result?.success ? buildNextChatCursor(input.cursor, result) : input.cursor,
21093
+ cursor: input.cursor,
22115
21094
  seq: input.seq,
22116
21095
  lastDeliveredSignature: input.lastDeliveredSignature,
22117
21096
  update: null
22118
21097
  };
22119
21098
  }
22120
- const syncMode = normalizeSyncMode(result.syncMode);
22121
- const cursor = {
22122
- knownMessageCount: Math.max(0, Number(result.totalMessages || 0)),
22123
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : "",
22124
- tailLimit: input.cursor.tailLimit
22125
- };
21099
+ const messages = Array.isArray(result.messages) ? result.messages : [];
22126
21100
  const title = typeof result.title === "string" ? result.title : void 0;
22127
21101
  const activeModal = normalizeChatTailActiveModal(result.activeModal);
22128
21102
  const status = typeof result.status === "string" ? result.status : "idle";
22129
21103
  const deliverySignature = buildChatTailDeliverySignature({
22130
21104
  sessionId: input.sessionId,
22131
21105
  ...input.historySessionId ? { historySessionId: input.historySessionId } : {},
22132
- messages: Array.isArray(result.messages) ? result.messages : [],
21106
+ messages,
22133
21107
  status,
22134
21108
  ...title ? { title } : {},
22135
- ...activeModal ? { activeModal } : {},
22136
- syncMode,
22137
- replaceFrom: Number(result.replaceFrom || 0),
22138
- totalMessages: Number(result.totalMessages || 0),
22139
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
21109
+ ...activeModal ? { activeModal } : {}
22140
21110
  });
22141
21111
  const seq = input.seq + 1;
22142
21112
  if (deliverySignature === input.lastDeliveredSignature) {
22143
21113
  return {
22144
- cursor,
21114
+ cursor: input.cursor,
22145
21115
  seq,
22146
21116
  lastDeliveredSignature: input.lastDeliveredSignature,
22147
21117
  update: null
22148
21118
  };
22149
21119
  }
22150
21120
  return {
22151
- cursor,
21121
+ cursor: input.cursor,
22152
21122
  seq,
22153
21123
  lastDeliveredSignature: deliverySignature,
22154
21124
  update: {
@@ -22159,14 +21129,10 @@ function prepareSessionChatTailUpdate(input) {
22159
21129
  ...input.interactionId ? { interactionId: input.interactionId } : {},
22160
21130
  seq,
22161
21131
  timestamp: input.timestamp,
22162
- messages: Array.isArray(result.messages) ? result.messages : [],
21132
+ messages,
22163
21133
  status,
22164
21134
  ...title ? { title } : {},
22165
- ...activeModal ? { activeModal } : {},
22166
- syncMode,
22167
- replaceFrom: Number(result.replaceFrom || 0),
22168
- totalMessages: Number(result.totalMessages || 0),
22169
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
21135
+ ...activeModal ? { activeModal } : {}
22170
21136
  }
22171
21137
  };
22172
21138
  }
@@ -22226,8 +21192,6 @@ async function runAsyncBatch(items, worker, options = {}) {
22226
21192
  }
22227
21193
 
22228
21194
  // src/agent-stream/provider-adapter.ts
22229
- init_read_chat_contract();
22230
- init_chat_message_normalization();
22231
21195
  var ProviderStreamAdapter = class {
22232
21196
  agentType;
22233
21197
  agentName;
@@ -22912,7 +21876,6 @@ var DaemonAgentStreamManager = class {
22912
21876
 
22913
21877
  // src/agent-stream/poller.ts
22914
21878
  init_logger();
22915
- init_chat_message_normalization();
22916
21879
  var AgentStreamPoller = class {
22917
21880
  deps;
22918
21881
  timer = null;
@@ -23391,10 +22354,6 @@ var ProviderInstanceManager = class {
23391
22354
  }
23392
22355
  };
23393
22356
 
23394
- // src/index.ts
23395
- init_io_contracts();
23396
- init_chat_message_normalization();
23397
-
23398
22357
  // src/providers/version-archive.ts
23399
22358
  import * as fs11 from "fs";
23400
22359
  import * as path21 from "path";
@@ -26832,7 +25791,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26832
25791
  lines.push("Provider category: `cli`");
26833
25792
  lines.push("");
26834
25793
  const funcToFile = {
26835
- parseOutput: "parse_output.js",
25794
+ parseSession: "parse_session.js",
26836
25795
  detectStatus: "detect_status.js",
26837
25796
  parseApproval: "parse_approval.js"
26838
25797
  };
@@ -26921,7 +25880,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26921
25880
  lines.push("");
26922
25881
  lines.push("| Function | Input | Return |");
26923
25882
  lines.push("|---|---|---|");
26924
- lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
25883
+ lines.push("| `parseSession` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
26925
25884
  lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
26926
25885
  lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
26927
25886
  lines.push("");
@@ -27141,7 +26100,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
27141
26100
  lines.push("");
27142
26101
  lines.push("## Required Validation");
27143
26102
  lines.push("1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.");
27144
- lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
26103
+ lines.push("2. Confirm `parseSession` produces a stable transcript without duplicating past turns when the PTY redraws.");
27145
26104
  lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
27146
26105
  lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
27147
26106
  lines.push("5. Confirm the Python file was actually created and executed, not just described in chat text.");
@@ -28411,7 +27370,7 @@ var DevServer = class _DevServer {
28411
27370
  lines.push("Provider category: `cli`");
28412
27371
  lines.push("");
28413
27372
  const funcToFile = {
28414
- parseOutput: "parse_output.js",
27373
+ parseSession: "parse_session.js",
28415
27374
  detectStatus: "detect_status.js",
28416
27375
  parseApproval: "parse_approval.js"
28417
27376
  };
@@ -28500,7 +27459,7 @@ var DevServer = class _DevServer {
28500
27459
  lines.push("");
28501
27460
  lines.push("| Function | Input | Return |");
28502
27461
  lines.push("|---|---|---|");
28503
- lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
27462
+ lines.push("| `parseSession` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
28504
27463
  lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
28505
27464
  lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
28506
27465
  lines.push("");
@@ -28595,7 +27554,7 @@ var DevServer = class _DevServer {
28595
27554
  lines.push("");
28596
27555
  lines.push("## Required Validation");
28597
27556
  lines.push("1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.");
28598
- lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
27557
+ lines.push("2. Confirm `parseSession` produces a stable transcript without duplicating past turns when the PTY redraws.");
28599
27558
  lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
28600
27559
  lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
28601
27560
  lines.push("5. Confirm the Python file was actually created and executed, not just described in chat text.");