@adhdev/daemon-core 0.9.64 → 0.9.66

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 -1712
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +646 -1712
  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 -366
  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.js CHANGED
@@ -482,525 +482,6 @@ var init_logger = __esm({
482
482
  }
483
483
  });
484
484
 
485
- // src/providers/io-contracts.ts
486
- function normalizeInputEnvelope(input) {
487
- const normalized = normalizeInputEnvelopePayload(input);
488
- const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
489
- return {
490
- parts: normalized.parts,
491
- textFallback,
492
- ...normalized.metadata ? { metadata: normalized.metadata } : {}
493
- };
494
- }
495
- function normalizeMessageParts(content) {
496
- if (typeof content === "string") return [{ type: "text", text: content }];
497
- if (!Array.isArray(content)) {
498
- if (content && typeof content === "object" && typeof content.text === "string") {
499
- return [{ type: "text", text: String(content.text) }];
500
- }
501
- return [];
502
- }
503
- const parts = [];
504
- for (const raw of content) {
505
- if (typeof raw === "string") {
506
- parts.push({ type: "text", text: raw });
507
- continue;
508
- }
509
- if (!raw || typeof raw !== "object") continue;
510
- const part = normalizeMessagePartObject(raw);
511
- if (part) parts.push(part);
512
- }
513
- return parts;
514
- }
515
- function flattenMessageParts(parts) {
516
- return parts.map((part) => {
517
- if (part.type === "text") return part.text;
518
- if (part.type === "resource") return part.resource.text || "";
519
- return "";
520
- }).filter((value) => value.length > 0).join("\n");
521
- }
522
- function normalizeInputEnvelopePayload(input) {
523
- if (typeof input === "string") {
524
- return { parts: [{ type: "text", text: input }], textFallback: input };
525
- }
526
- if (!input || typeof input !== "object") {
527
- return { parts: [], textFallback: "" };
528
- }
529
- const record = input;
530
- const nestedInput = record.input;
531
- if (nestedInput && typeof nestedInput === "object") {
532
- const nested = nestedInput;
533
- return {
534
- parts: normalizeInputParts(nested.parts ?? nested.prompt),
535
- textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
536
- metadata: normalizeInputMetadata(nested.metadata)
537
- };
538
- }
539
- const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
540
- if (directText !== void 0) {
541
- return { parts: [{ type: "text", text: directText }], textFallback: directText };
542
- }
543
- const directParts = normalizeInputParts(record.parts ?? record.prompt);
544
- return {
545
- parts: directParts,
546
- textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
547
- metadata: normalizeInputMetadata(record.metadata)
548
- };
549
- }
550
- function normalizeInputMetadata(value) {
551
- if (!value || typeof value !== "object") return void 0;
552
- const record = value;
553
- const metadata = {};
554
- if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
555
- metadata.source = record.source;
556
- }
557
- if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
558
- metadata.clientTimestamp = record.clientTimestamp;
559
- }
560
- return Object.keys(metadata).length > 0 ? metadata : void 0;
561
- }
562
- function normalizeInputParts(value) {
563
- if (!Array.isArray(value)) return [];
564
- const parts = [];
565
- for (const raw of value) {
566
- if (typeof raw === "string") {
567
- parts.push({ type: "text", text: raw });
568
- continue;
569
- }
570
- if (!raw || typeof raw !== "object") continue;
571
- const part = normalizeInputPartObject(raw);
572
- if (part) parts.push(part);
573
- }
574
- return parts;
575
- }
576
- function normalizeInputPartObject(raw) {
577
- const type = raw.type;
578
- if (type === "text" && typeof raw.text === "string") {
579
- return { type, text: raw.text };
580
- }
581
- if (type === "image" && typeof raw.mimeType === "string") {
582
- return {
583
- type,
584
- mimeType: raw.mimeType,
585
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
586
- ...typeof raw.data === "string" ? { data: raw.data } : {},
587
- ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
588
- };
589
- }
590
- if (type === "audio" && typeof raw.mimeType === "string") {
591
- return {
592
- type,
593
- mimeType: raw.mimeType,
594
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
595
- ...typeof raw.data === "string" ? { data: raw.data } : {},
596
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
597
- };
598
- }
599
- if (type === "video" && typeof raw.mimeType === "string") {
600
- return {
601
- type,
602
- mimeType: raw.mimeType,
603
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
604
- ...typeof raw.data === "string" ? { data: raw.data } : {},
605
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
606
- };
607
- }
608
- if (type === "resource" && typeof raw.uri === "string") {
609
- return {
610
- type,
611
- uri: raw.uri,
612
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
613
- ...typeof raw.name === "string" ? { name: raw.name } : {},
614
- ...typeof raw.text === "string" ? { text: raw.text } : {},
615
- ...typeof raw.data === "string" ? { data: raw.data } : {}
616
- };
617
- }
618
- if (type === "resource_link" && typeof raw.uri === "string") {
619
- return {
620
- type: "resource",
621
- uri: raw.uri,
622
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
623
- ...typeof raw.name === "string" ? { name: raw.name } : {}
624
- };
625
- }
626
- return null;
627
- }
628
- function normalizeMessagePartObject(raw) {
629
- const type = raw.type;
630
- if (type === "text" && typeof raw.text === "string") {
631
- return { type, text: raw.text };
632
- }
633
- if (type === "image" && typeof raw.mimeType === "string") {
634
- return {
635
- type,
636
- mimeType: raw.mimeType,
637
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
638
- ...typeof raw.data === "string" ? { data: raw.data } : {}
639
- };
640
- }
641
- if (type === "audio" && typeof raw.mimeType === "string") {
642
- return {
643
- type,
644
- mimeType: raw.mimeType,
645
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
646
- ...typeof raw.data === "string" ? { data: raw.data } : {},
647
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
648
- };
649
- }
650
- if (type === "video" && typeof raw.mimeType === "string") {
651
- return {
652
- type,
653
- mimeType: raw.mimeType,
654
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
655
- ...typeof raw.data === "string" ? { data: raw.data } : {},
656
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
657
- };
658
- }
659
- if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
660
- return {
661
- type,
662
- uri: raw.uri,
663
- name: raw.name,
664
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
665
- ...typeof raw.size === "number" ? { size: raw.size } : {}
666
- };
667
- }
668
- if (type === "resource" && raw.resource && typeof raw.resource === "object") {
669
- const resource = raw.resource;
670
- if (typeof resource.uri !== "string") return null;
671
- return {
672
- type,
673
- resource: {
674
- uri: resource.uri,
675
- ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
676
- ...typeof resource.text === "string" ? { text: resource.text } : {},
677
- ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
678
- }
679
- };
680
- }
681
- return null;
682
- }
683
- function flattenInputParts(parts) {
684
- return parts.map((part) => {
685
- if (part.type === "text") return part.text;
686
- if (part.type === "audio") return part.transcript || "";
687
- if (part.type === "resource") return part.text || "";
688
- return "";
689
- }).filter((value) => value.length > 0).join("\n");
690
- }
691
- var init_io_contracts = __esm({
692
- "src/providers/io-contracts.ts"() {
693
- "use strict";
694
- }
695
- });
696
-
697
- // src/providers/contracts.ts
698
- function flattenContent(content) {
699
- if (typeof content === "string") return content;
700
- return flattenMessageParts(normalizeMessageParts(content));
701
- }
702
- var init_contracts = __esm({
703
- "src/providers/contracts.ts"() {
704
- "use strict";
705
- init_io_contracts();
706
- init_io_contracts();
707
- }
708
- });
709
-
710
- // src/providers/chat-message-normalization.ts
711
- function canonicalizeKindHint(value) {
712
- return value.trim().toLowerCase().replace(/[\s-]+/g, "_");
713
- }
714
- function resolveBuiltinOrAliasKind(kind) {
715
- if (typeof kind !== "string") return null;
716
- const normalizedKind = canonicalizeKindHint(kind);
717
- if (!normalizedKind) return null;
718
- if (KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
719
- return CHAT_MESSAGE_KIND_ALIASES[normalizedKind] || null;
720
- }
721
- function inferHintKind(value) {
722
- const direct = resolveBuiltinOrAliasKind(value);
723
- if (direct) return direct;
724
- if (typeof value !== "string") return null;
725
- const normalized = canonicalizeKindHint(value);
726
- if (!normalized) return null;
727
- if (/thought|thinking|reasoning/.test(normalized)) return "thought";
728
- if (/tool/.test(normalized)) return "tool";
729
- if (/terminal|command|shell|console/.test(normalized)) return "terminal";
730
- return null;
731
- }
732
- function inferKindFromToolCalls(message) {
733
- const toolCalls = Array.isArray(message?.toolCalls) ? message.toolCalls : [];
734
- if (toolCalls.length === 0) return null;
735
- if (toolCalls.some((toolCall) => toolCall?.kind === "think")) return "thought";
736
- if (toolCalls.some((toolCall) => toolCall?.kind === "execute")) return "terminal";
737
- if (toolCalls.some((toolCall) => Array.isArray(toolCall?.content) && toolCall.content.some((entry) => entry?.type === "terminal"))) {
738
- return "terminal";
739
- }
740
- return "tool";
741
- }
742
- function inferMissingChatMessageKind(message) {
743
- const role = typeof message?.role === "string" ? message.role.trim().toLowerCase() : "";
744
- if (role === "system") return "system";
745
- const meta = message?.meta && typeof message.meta === "object" ? message.meta : void 0;
746
- const hintCandidates = [
747
- message?._sub,
748
- message?._type,
749
- meta?.label,
750
- typeof message?.senderName === "string" ? message.senderName : void 0
751
- ];
752
- for (const candidate of hintCandidates) {
753
- const inferred = inferHintKind(candidate);
754
- if (inferred) return inferred;
755
- }
756
- const inferredFromToolCalls = inferKindFromToolCalls(message);
757
- if (inferredFromToolCalls) return inferredFromToolCalls;
758
- return null;
759
- }
760
- function isBuiltinChatMessageKind(kind) {
761
- return resolveBuiltinOrAliasKind(kind) !== null;
762
- }
763
- function normalizeChatMessageKind(kind, role) {
764
- const resolvedKind = resolveBuiltinOrAliasKind(kind);
765
- if (resolvedKind) return resolvedKind;
766
- const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
767
- return normalizedRole === "system" ? "system" : "standard";
768
- }
769
- function resolveChatMessageKind(message) {
770
- const explicitKind = resolveBuiltinOrAliasKind(message?.kind);
771
- if (explicitKind) return explicitKind;
772
- const inferredKind = inferMissingChatMessageKind(message);
773
- if (inferredKind) return inferredKind;
774
- return normalizeChatMessageKind(message?.kind, message?.role);
775
- }
776
- function buildChatMessage(message) {
777
- return {
778
- ...message,
779
- kind: resolveChatMessageKind(message)
780
- };
781
- }
782
- function buildSystemChatMessage(message) {
783
- return buildChatMessage({
784
- ...message,
785
- role: "system",
786
- kind: message?.kind || "system"
787
- });
788
- }
789
- function buildRuntimeSystemChatMessage(message) {
790
- return buildSystemChatMessage({
791
- ...message,
792
- senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
793
- });
794
- }
795
- function buildAssistantChatMessage(message) {
796
- return buildChatMessage({
797
- ...message,
798
- role: "assistant",
799
- kind: message?.kind || "standard"
800
- });
801
- }
802
- function buildThoughtChatMessage(message) {
803
- return buildAssistantChatMessage({
804
- ...message,
805
- kind: message?.kind || "thought"
806
- });
807
- }
808
- function buildToolChatMessage(message) {
809
- return buildAssistantChatMessage({
810
- ...message,
811
- kind: message?.kind || "tool"
812
- });
813
- }
814
- function buildTerminalChatMessage(message) {
815
- return buildAssistantChatMessage({
816
- ...message,
817
- kind: message?.kind || "terminal"
818
- });
819
- }
820
- function buildUserChatMessage(message) {
821
- return buildChatMessage({
822
- ...message,
823
- role: "user",
824
- kind: message?.kind || "standard"
825
- });
826
- }
827
- function normalizeChatMessage(message) {
828
- return buildChatMessage(message);
829
- }
830
- function normalizeChatMessages(messages) {
831
- return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
832
- }
833
- var BUILTIN_CHAT_MESSAGE_KINDS, KNOWN_CHAT_MESSAGE_KINDS, CHAT_MESSAGE_KIND_ALIASES;
834
- var init_chat_message_normalization = __esm({
835
- "src/providers/chat-message-normalization.ts"() {
836
- "use strict";
837
- BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
838
- KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
839
- CHAT_MESSAGE_KIND_ALIASES = {
840
- text: "standard",
841
- message: "standard",
842
- assistant: "standard",
843
- thinking: "thought",
844
- think: "thought",
845
- reasoning: "thought",
846
- reason: "thought",
847
- toolcall: "tool",
848
- tool_call: "tool",
849
- tooluse: "tool",
850
- tool_use: "tool",
851
- action: "tool",
852
- command: "terminal",
853
- cmd: "terminal",
854
- shell: "terminal",
855
- console: "terminal"
856
- };
857
- }
858
- });
859
-
860
- // src/providers/read-chat-contract.ts
861
- function isPlainObject3(value) {
862
- return !!value && typeof value === "object" && !Array.isArray(value);
863
- }
864
- function isFiniteNumber(value) {
865
- return typeof value === "number" && Number.isFinite(value);
866
- }
867
- function validateStatus(status, source) {
868
- if (typeof status !== "string" || !VALID_STATUSES.includes(status)) {
869
- throw new Error(`${source}: status must be one of ${VALID_STATUSES.join(", ")}`);
870
- }
871
- return status;
872
- }
873
- function validateRole(role, source, index) {
874
- if (typeof role !== "string" || !VALID_ROLES.includes(role)) {
875
- throw new Error(`${source}: messages[${index}].role must be one of ${VALID_ROLES.join(", ")}`);
876
- }
877
- return role;
878
- }
879
- function validateBubbleState(state, source, index) {
880
- if (typeof state !== "string" || !VALID_BUBBLE_STATES.includes(state)) {
881
- throw new Error(`${source}: messages[${index}].bubbleState must be one of ${VALID_BUBBLE_STATES.join(", ")}`);
882
- }
883
- return state;
884
- }
885
- function validateTurnStatus(turnStatus, source) {
886
- if (typeof turnStatus !== "string" || !VALID_TURN_STATUSES.includes(turnStatus)) {
887
- throw new Error(`${source}: turnStatus must be one of ${VALID_TURN_STATUSES.join(", ")}`);
888
- }
889
- return turnStatus;
890
- }
891
- function validateMessageContent(content, source, index) {
892
- if (typeof content === "string") return content;
893
- if (Array.isArray(content)) return normalizeMessageParts(content);
894
- throw new Error(`${source}: messages[${index}].content must be a string or structured content array`);
895
- }
896
- function validateMessage(message, source, index) {
897
- if (!isPlainObject3(message)) {
898
- throw new Error(`${source}: messages[${index}] must be an object`);
899
- }
900
- const normalized = {
901
- role: validateRole(message.role, source, index),
902
- content: validateMessageContent(message.content, source, index)
903
- };
904
- if (typeof message.kind === "string") normalized.kind = message.kind;
905
- if (typeof message.id === "string") normalized.id = message.id;
906
- if (typeof message.bubbleId === "string") normalized.bubbleId = message.bubbleId;
907
- if (typeof message.providerUnitKey === "string") normalized.providerUnitKey = message.providerUnitKey;
908
- if (message.bubbleState !== void 0) normalized.bubbleState = validateBubbleState(message.bubbleState, source, index);
909
- if (isFiniteNumber(message.index)) normalized.index = message.index;
910
- if (isFiniteNumber(message.timestamp)) normalized.timestamp = message.timestamp;
911
- if (isFiniteNumber(message.receivedAt)) normalized.receivedAt = message.receivedAt;
912
- if (typeof message._turnKey === "string") normalized._turnKey = message._turnKey;
913
- if (Array.isArray(message.toolCalls)) normalized.toolCalls = message.toolCalls;
914
- if (isPlainObject3(message.meta)) normalized.meta = message.meta;
915
- if (typeof message.senderName === "string") normalized.senderName = message.senderName;
916
- if (typeof message._type === "string") normalized._type = message._type;
917
- if (typeof message._sub === "string") normalized._sub = message._sub;
918
- return normalized;
919
- }
920
- function validateModal(activeModal, status, source) {
921
- if (activeModal == null) {
922
- if (status === "waiting_approval") {
923
- throw new Error(`${source}: waiting_approval status requires activeModal with buttons`);
924
- }
925
- return activeModal === null ? null : void 0;
926
- }
927
- if (!isPlainObject3(activeModal)) {
928
- throw new Error(`${source}: activeModal must be an object when provided`);
929
- }
930
- if (typeof activeModal.message !== "string") {
931
- throw new Error(`${source}: activeModal.message must be a string`);
932
- }
933
- if (!Array.isArray(activeModal.buttons) || activeModal.buttons.some((button) => typeof button !== "string" || !button.trim())) {
934
- throw new Error(`${source}: activeModal.buttons must be a non-empty string array`);
935
- }
936
- const normalized = {
937
- message: activeModal.message,
938
- buttons: activeModal.buttons.map((button) => button.trim())
939
- };
940
- if (isFiniteNumber(activeModal.width)) normalized.width = activeModal.width;
941
- if (isFiniteNumber(activeModal.height)) normalized.height = activeModal.height;
942
- return normalized;
943
- }
944
- function validateControlValues(controlValues, source) {
945
- if (controlValues === void 0) return void 0;
946
- if (!isPlainObject3(controlValues)) {
947
- throw new Error(`${source}: controlValues must be an object when provided`);
948
- }
949
- const normalized = {};
950
- for (const [key, value] of Object.entries(controlValues)) {
951
- if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
952
- throw new Error(`${source}: controlValues.${key} must be string, number, or boolean`);
953
- }
954
- normalized[key] = value;
955
- }
956
- return normalized;
957
- }
958
- function validateReadChatResultPayload(raw, source = "read_chat") {
959
- if (!isPlainObject3(raw)) {
960
- throw new Error(`${source}: payload must be an object`);
961
- }
962
- const status = validateStatus(raw.status, source);
963
- if (!Array.isArray(raw.messages)) {
964
- throw new Error(`${source}: messages must be an array`);
965
- }
966
- const messages = raw.messages.map((message, index) => validateMessage(message, source, index));
967
- const activeModal = validateModal(raw.activeModal, status, source);
968
- const controlValues = validateControlValues(raw.controlValues, source);
969
- const normalized = {
970
- status,
971
- messages
972
- };
973
- if (activeModal !== void 0) normalized.activeModal = activeModal;
974
- if (typeof raw.id === "string") normalized.id = raw.id;
975
- if (typeof raw.title === "string") normalized.title = raw.title;
976
- if (typeof raw.currentTurnId === "string") normalized.currentTurnId = raw.currentTurnId;
977
- if (raw.turnStatus !== void 0) normalized.turnStatus = validateTurnStatus(raw.turnStatus, source);
978
- if (typeof raw.agentType === "string") normalized.agentType = raw.agentType;
979
- if (typeof raw.agentName === "string") normalized.agentName = raw.agentName;
980
- if (typeof raw.extensionId === "string") normalized.extensionId = raw.extensionId;
981
- if (typeof raw.inputContent === "string") normalized.inputContent = raw.inputContent;
982
- if (typeof raw.isVisible === "boolean") normalized.isVisible = raw.isVisible;
983
- if (typeof raw.isWelcomeScreen === "boolean") normalized.isWelcomeScreen = raw.isWelcomeScreen;
984
- if (controlValues) normalized.controlValues = controlValues;
985
- if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
986
- if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
987
- if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
988
- if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
989
- if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
990
- return normalized;
991
- }
992
- var VALID_STATUSES, VALID_ROLES, VALID_BUBBLE_STATES, VALID_TURN_STATUSES;
993
- var init_read_chat_contract = __esm({
994
- "src/providers/read-chat-contract.ts"() {
995
- "use strict";
996
- init_contracts();
997
- VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "streaming", "long_generating"];
998
- VALID_ROLES = ["user", "assistant", "system", "human"];
999
- VALID_BUBBLE_STATES = ["draft", "streaming", "final", "removed"];
1000
- VALID_TURN_STATUSES = ["open", "waiting_approval", "complete", "error"];
1001
- }
1002
- });
1003
-
1004
485
  // src/logging/debug-config.ts
1005
486
  function normalizeCategories(categories) {
1006
487
  if (!Array.isArray(categories)) return [];
@@ -1562,67 +1043,6 @@ function promptLikelyVisible(screenText, promptSnippet) {
1562
1043
  function normalizeScreenSnapshot(text) {
1563
1044
  return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
1564
1045
  }
1565
- function shouldReflowComparableMessageLines(lines) {
1566
- 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));
1567
- }
1568
- function joinComparableMessageLines(lines) {
1569
- return lines.reduce((acc, line) => {
1570
- const next = String(line || "").trim();
1571
- if (!next) return acc;
1572
- if (!acc) return next;
1573
- if (/[,\d]$/.test(acc) && /^\d/.test(next)) {
1574
- return `${acc}${next}`;
1575
- }
1576
- if (/[A-Za-z]$/.test(acc) && /^\d/.test(next)) {
1577
- return `${acc}${next}`;
1578
- }
1579
- const fragmentMatch = acc.match(/([A-Za-z]{1,4})$/);
1580
- const fragment = fragmentMatch ? fragmentMatch[1].toLowerCase() : "";
1581
- if (/^[a-z]/.test(next) && fragment && !COMMON_COMPARABLE_WRAP_WORDS.has(fragment)) {
1582
- return `${acc}${next}`;
1583
- }
1584
- return `${acc} ${next}`;
1585
- }, "").replace(/\s+([,.;:!?])/g, "$1").replace(/(\d)\s+,/g, "$1,").replace(/\s+/g, " ").trim();
1586
- }
1587
- function normalizeComparableMessageContent(text) {
1588
- const lines = String(text || "").split(/\r\n|\n|\r/g).map((line) => line.trim()).filter(Boolean);
1589
- if (lines.length === 0) return "";
1590
- if (shouldReflowComparableMessageLines(lines)) {
1591
- return joinComparableMessageLines(lines);
1592
- }
1593
- return lines.join(" ").replace(/\s+/g, " ").trim();
1594
- }
1595
- function trimPromptEchoPrefix(text, promptText) {
1596
- const prompt = normalizeComparableMessageContent(String(promptText || ""));
1597
- if (!prompt) return String(text || "");
1598
- const lines = String(text || "").split(/\r\n|\n|\r/g);
1599
- let dropCount = 0;
1600
- for (let index = 0; index < Math.min(lines.length, 6); index += 1) {
1601
- const fragment = normalizeComparableMessageContent(lines[index].replace(/^[.…]+\s*/, ""));
1602
- if (!fragment) {
1603
- if (dropCount === index) dropCount = index + 1;
1604
- continue;
1605
- }
1606
- const fragmentWordCount = fragment ? fragment.split(/\s+/).filter(Boolean).length : 0;
1607
- const canBePromptEcho = fragment.length >= 16 || fragmentWordCount >= 4;
1608
- if (canBePromptEcho && prompt.includes(fragment)) {
1609
- dropCount = index + 1;
1610
- continue;
1611
- }
1612
- break;
1613
- }
1614
- return lines.slice(dropCount).join("\n").trim();
1615
- }
1616
- function getLastUserPromptText(messages) {
1617
- const items = Array.isArray(messages) ? messages : [];
1618
- for (let index = items.length - 1; index >= 0; index -= 1) {
1619
- const message = items[index];
1620
- if (message?.role === "user" && typeof message.content === "string" && message.content.trim()) {
1621
- return message.content;
1622
- }
1623
- }
1624
- return "";
1625
- }
1626
1046
  function parsePatternEntry(x) {
1627
1047
  if (x instanceof RegExp) return x;
1628
1048
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -1649,7 +1069,7 @@ function normalizeCliProviderForRuntime(raw) {
1649
1069
  }
1650
1070
  };
1651
1071
  }
1652
- var os9, path13, import_child_process4, buildCliSpawnEnv, COMMON_COMPARABLE_WRAP_WORDS;
1072
+ var os9, path13, import_child_process4, buildCliSpawnEnv;
1653
1073
  var init_provider_cli_shared = __esm({
1654
1074
  "src/cli-adapters/provider-cli-shared.ts"() {
1655
1075
  "use strict";
@@ -1658,32 +1078,6 @@ var init_provider_cli_shared = __esm({
1658
1078
  import_child_process4 = require("child_process");
1659
1079
  init_spawn_env();
1660
1080
  buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
1661
- COMMON_COMPARABLE_WRAP_WORDS = /* @__PURE__ */ new Set([
1662
- "a",
1663
- "an",
1664
- "and",
1665
- "as",
1666
- "at",
1667
- "but",
1668
- "by",
1669
- "for",
1670
- "from",
1671
- "in",
1672
- "into",
1673
- "is",
1674
- "it",
1675
- "of",
1676
- "on",
1677
- "or",
1678
- "that",
1679
- "the",
1680
- "their",
1681
- "then",
1682
- "this",
1683
- "to",
1684
- "was",
1685
- "with"
1686
- ]);
1687
1081
  }
1688
1082
  });
1689
1083
 
@@ -1694,169 +1088,8 @@ function sliceFromOffset(text, start) {
1694
1088
  if (start >= text.length) return "";
1695
1089
  return text.slice(start);
1696
1090
  }
1697
- function hydrateCliParsedMessages(parsedMessages, options) {
1698
- const { committedMessages, scope, lastOutputAt } = options;
1699
- const referenceMessages = [...committedMessages];
1700
- const referenceComparables = new Array(referenceMessages.length);
1701
- const usedReferenceIndexes = /* @__PURE__ */ new Set();
1702
- const now = options.now ?? Date.now();
1703
- let exactReferenceIndexesByKey = null;
1704
- const exactReferenceCursorByKey = /* @__PURE__ */ new Map();
1705
- const hasFiniteTimestamp = (message) => typeof message?.timestamp === "number" && Number.isFinite(message.timestamp);
1706
- const getReferenceComparable = (index) => {
1707
- if (typeof referenceComparables[index] === "string") return referenceComparables[index] || "";
1708
- const comparable = normalizeComparableMessageContent(referenceMessages[index]?.content || "");
1709
- referenceComparables[index] = comparable;
1710
- return comparable;
1711
- };
1712
- const messagesShareStableIdentity = (parsed, reference) => {
1713
- if (!parsed || !reference) return false;
1714
- const parsedId = typeof parsed.id === "string" ? parsed.id.trim() : "";
1715
- const referenceId = typeof reference.id === "string" ? reference.id.trim() : "";
1716
- if (parsedId && referenceId && parsedId === referenceId) return true;
1717
- return typeof parsed.index === "number" && Number.isFinite(parsed.index) && typeof reference.index === "number" && Number.isFinite(reference.index) && parsed.index === reference.index;
1718
- };
1719
- const exactReferenceKey = (role, comparable) => `${role}\0${comparable}`;
1720
- const ensureExactReferenceIndex = () => {
1721
- if (exactReferenceIndexesByKey) return exactReferenceIndexesByKey;
1722
- const byKey = /* @__PURE__ */ new Map();
1723
- for (let i = 0; i < referenceMessages.length; i++) {
1724
- const candidate = referenceMessages[i];
1725
- if (!candidate || candidate.role !== "user" && candidate.role !== "assistant" || !hasFiniteTimestamp(candidate)) continue;
1726
- const comparable = getReferenceComparable(i);
1727
- if (!comparable) continue;
1728
- const key = exactReferenceKey(candidate.role, comparable);
1729
- const indexes = byKey.get(key);
1730
- if (indexes) {
1731
- indexes.push(i);
1732
- } else {
1733
- byKey.set(key, [i]);
1734
- }
1735
- }
1736
- exactReferenceIndexesByKey = byKey;
1737
- return byKey;
1738
- };
1739
- const takeExactReferenceTimestamp = (role, normalizedContent) => {
1740
- const key = exactReferenceKey(role, normalizedContent);
1741
- const indexes = ensureExactReferenceIndex().get(key);
1742
- if (!indexes) return void 0;
1743
- let cursor = exactReferenceCursorByKey.get(key) || 0;
1744
- while (cursor < indexes.length) {
1745
- const candidateIndex = indexes[cursor];
1746
- cursor += 1;
1747
- if (usedReferenceIndexes.has(candidateIndex)) continue;
1748
- const candidate = referenceMessages[candidateIndex];
1749
- if (!candidate || candidate.role !== role || !hasFiniteTimestamp(candidate)) continue;
1750
- usedReferenceIndexes.add(candidateIndex);
1751
- exactReferenceCursorByKey.set(key, cursor);
1752
- return candidate.timestamp;
1753
- }
1754
- exactReferenceCursorByKey.set(key, cursor);
1755
- return void 0;
1756
- };
1757
- const findReferenceTimestamp = (message, role, content, parsedIndex) => {
1758
- const sameIndex = referenceMessages[parsedIndex];
1759
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && hasFiniteTimestamp(sameIndex) && messagesShareStableIdentity(message, sameIndex)) {
1760
- usedReferenceIndexes.add(parsedIndex);
1761
- return sameIndex.timestamp;
1762
- }
1763
- const normalizedContent = normalizeComparableMessageContent(content);
1764
- if (!normalizedContent) return void 0;
1765
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && getReferenceComparable(parsedIndex) === normalizedContent && hasFiniteTimestamp(sameIndex)) {
1766
- usedReferenceIndexes.add(parsedIndex);
1767
- return sameIndex.timestamp;
1768
- }
1769
- const exactTimestamp = takeExactReferenceTimestamp(role, normalizedContent);
1770
- if (typeof exactTimestamp === "number") return exactTimestamp;
1771
- for (let i = 0; i < referenceMessages.length; i++) {
1772
- if (usedReferenceIndexes.has(i)) continue;
1773
- const candidate = referenceMessages[i];
1774
- if (!candidate || candidate.role !== role) continue;
1775
- const candidateContent = getReferenceComparable(i);
1776
- if (!candidateContent) continue;
1777
- const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1778
- if (!fuzzyMatch) continue;
1779
- if (hasFiniteTimestamp(candidate)) {
1780
- usedReferenceIndexes.add(i);
1781
- return candidate.timestamp;
1782
- }
1783
- }
1784
- return void 0;
1785
- };
1786
- return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1787
- const role = message.role;
1788
- const content = typeof message.content === "string" ? message.content : String(message.content || "");
1789
- const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1790
- const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(message, role, content, index);
1791
- const fallbackTimestamp = role === "user" ? scope?.startedAt || now : lastOutputAt || scope?.startedAt || now;
1792
- const timestamp = referenceTimestamp ?? fallbackTimestamp;
1793
- return {
1794
- ...message,
1795
- role,
1796
- content,
1797
- timestamp,
1798
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
1799
- };
1800
- });
1801
- }
1802
- function chooseMoreComparableCliMessage(left, right, leftComparable = normalizeComparableMessageContent(left.content || ""), rightComparable = normalizeComparableMessageContent(right.content || "")) {
1803
- if (leftComparable && leftComparable === rightComparable) {
1804
- const leftNewlines = String(left.content || "").split(/\r\n|\n|\r/g).length - 1;
1805
- const rightNewlines = String(right.content || "").split(/\r\n|\n|\r/g).length - 1;
1806
- return rightNewlines < leftNewlines ? right : left;
1807
- }
1808
- return rightComparable.length > leftComparable.length ? right : left;
1809
- }
1810
- function dedupeConsecutiveComparableCliMessages(messages) {
1811
- const deduped = [];
1812
- for (const message of messages) {
1813
- const current = {
1814
- ...message,
1815
- content: typeof message.content === "string" ? message.content : String(message.content || "")
1816
- };
1817
- const currentComparable = normalizeComparableMessageContent(current.content || "");
1818
- const previous = deduped[deduped.length - 1];
1819
- if (!previous) {
1820
- deduped.push({ message: current, comparable: currentComparable });
1821
- continue;
1822
- }
1823
- const sameRole = previous.message.role === current.role;
1824
- const sameKind = (previous.message.kind || "standard") === (current.kind || "standard");
1825
- const sameSender = (previous.message.senderName || "") === (current.senderName || "");
1826
- const comparableMatch = previous.comparable && previous.comparable === currentComparable;
1827
- if (sameRole && sameKind && sameSender && comparableMatch) {
1828
- const selected = chooseMoreComparableCliMessage(
1829
- previous.message,
1830
- current,
1831
- previous.comparable,
1832
- currentComparable
1833
- );
1834
- deduped[deduped.length - 1] = {
1835
- message: selected,
1836
- comparable: selected === current ? currentComparable : previous.comparable
1837
- };
1838
- continue;
1839
- }
1840
- deduped.push({ message: current, comparable: currentComparable });
1841
- }
1842
- return deduped.map((entry) => entry.message);
1843
- }
1844
- function normalizeCliParsedMessages(parsedMessages, options) {
1845
- return dedupeConsecutiveComparableCliMessages(hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
1846
- role: message.role,
1847
- content: message.content,
1848
- timestamp: message.timestamp,
1849
- receivedAt: message.receivedAt,
1850
- kind: message.kind,
1851
- id: message.id,
1852
- index: message.index,
1853
- providerUnitKey: message.providerUnitKey,
1854
- bubbleId: message.bubbleId,
1855
- bubbleState: message.bubbleState,
1856
- _turnKey: message._turnKey,
1857
- meta: message.meta,
1858
- senderName: message.senderName
1859
- })));
1091
+ function normalizeCliParsedMessages(parsedMessages, _options) {
1092
+ return Array.isArray(parsedMessages) ? parsedMessages : [];
1860
1093
  }
1861
1094
  function buildCliParseInput(options) {
1862
1095
  const {
@@ -2066,40 +1299,8 @@ var provider_cli_adapter_exports = {};
2066
1299
  __export(provider_cli_adapter_exports, {
2067
1300
  ProviderCliAdapter: () => ProviderCliAdapter,
2068
1301
  appendBoundedText: () => appendBoundedText,
2069
- normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime,
2070
- sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent,
2071
- trimLastAssistantEchoForCliMessages: () => trimLastAssistantEchoForCliMessages
1302
+ normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
2072
1303
  });
2073
- function normalizeComparableTranscriptText(value) {
2074
- return sanitizeTerminalText(String(value || "")).replace(/\s+/g, " ").trim();
2075
- }
2076
- function hasVisibleInterruptPrompt(text) {
2077
- const interruptCopyPattern = /\bEnter\s+to\s+interrupt\b(?:\s*,?\s*Ctrl\s*(?:\+|-)?\s*C\s+to\s+cancel)?/i;
2078
- return sanitizeTerminalText(text || "").split(/\r?\n/g).some((line) => {
2079
- const trimmed = line.trim();
2080
- if (!interruptCopyPattern.test(trimmed)) return false;
2081
- return /^(?:[^A-Za-z0-9\s]{1,8}\s+)?[❯›>]\s+/.test(trimmed);
2082
- });
2083
- }
2084
- function parsedTranscriptIsRicherThanCommitted(parsedMessages, committedMessages) {
2085
- if (!Array.isArray(parsedMessages) || !Array.isArray(committedMessages)) return false;
2086
- if (parsedMessages.length > committedMessages.length) return true;
2087
- if (parsedMessages.length !== committedMessages.length) return false;
2088
- for (let index = 0; index < parsedMessages.length; index += 1) {
2089
- const parsed = parsedMessages[index];
2090
- const committed = committedMessages[index];
2091
- if (!parsed || !committed) return false;
2092
- if ((parsed.role || "") !== (committed.role || "")) return false;
2093
- if (parsed.id && committed.id && String(parsed.id) !== String(committed.id)) return false;
2094
- if (typeof parsed.index === "number" && typeof committed.index === "number" && parsed.index !== committed.index) return false;
2095
- const parsedText = normalizeComparableTranscriptText(parsed.content);
2096
- const committedText = normalizeComparableTranscriptText(committed.content);
2097
- if (!parsedText || !committedText || parsedText === committedText) continue;
2098
- if (parsedText.length > committedText.length && parsedText.startsWith(committedText)) return true;
2099
- return false;
2100
- }
2101
- return false;
2102
- }
2103
1304
  function appendBoundedText(current, chunk, maxChars) {
2104
1305
  if (!chunk) return current.length <= maxChars ? current : current.slice(-maxChars);
2105
1306
  if (maxChars <= 0) return "";
@@ -2108,76 +1309,7 @@ function appendBoundedText(current, chunk, maxChars) {
2108
1309
  if (current.length <= keepFromCurrent) return current + chunk;
2109
1310
  return current.slice(-keepFromCurrent) + chunk;
2110
1311
  }
2111
- function isLikelyCommittedActivityPrefixContinuation(line) {
2112
- const trimmed = String(line || "").trim();
2113
- if (!trimmed) return false;
2114
- if (COMMITTED_ACTIVITY_PREFIX_BLOCK_RE.test(trimmed)) return false;
2115
- if (/\s/.test(trimmed)) return false;
2116
- if (/[가-힣]/.test(trimmed)) return false;
2117
- if (trimmed.length > 96) return false;
2118
- return /^[A-Za-z0-9_./:@+%=-]+$/.test(trimmed);
2119
- }
2120
- function parseCommittedActivityPrefixBlock(lines, index) {
2121
- const first = String(lines[index] || "").trim();
2122
- if (!COMMITTED_ACTIVITY_PREFIX_BLOCK_RE.test(first)) return null;
2123
- const parts = [first];
2124
- let nextIndex = index + 1;
2125
- while (nextIndex < lines.length && isLikelyCommittedActivityPrefixContinuation(lines[nextIndex])) {
2126
- parts.push(String(lines[nextIndex] || "").trim());
2127
- nextIndex += 1;
2128
- }
2129
- return { label: parts.join(""), nextIndex };
2130
- }
2131
- function sanitizeCliStandardMessageContent(content) {
2132
- const source = String(content || "").trim();
2133
- if (!source) return "";
2134
- const lines = source.split(/\r?\n/);
2135
- if (lines.length < 4) return source;
2136
- const counts = /* @__PURE__ */ new Map();
2137
- for (let index = 0; index < lines.length; index += 1) {
2138
- const block = parseCommittedActivityPrefixBlock(lines, index);
2139
- if (!block) continue;
2140
- counts.set(block.label, (counts.get(block.label) || 0) + 1);
2141
- index = block.nextIndex - 1;
2142
- }
2143
- const repeatedLabels = new Set(
2144
- Array.from(counts.entries()).filter(([, count]) => count >= 3).map(([label]) => label)
2145
- );
2146
- if (repeatedLabels.size === 0) return source;
2147
- const stripped = [];
2148
- let removed = 0;
2149
- for (let index = 0; index < lines.length; index += 1) {
2150
- const block = parseCommittedActivityPrefixBlock(lines, index);
2151
- if (block && repeatedLabels.has(block.label)) {
2152
- removed += 1;
2153
- index = block.nextIndex - 1;
2154
- continue;
2155
- }
2156
- stripped.push(lines[index]);
2157
- }
2158
- const next = stripped.join("\n").replace(/\n{3,}/g, "\n\n").trim();
2159
- return removed >= 3 && next.length >= 80 ? next : source;
2160
- }
2161
- function sanitizeCommittedMessageForDisplay(message) {
2162
- if (!message || message.role !== "assistant" || (message.kind || "standard") !== "standard") return message;
2163
- const content = sanitizeCliStandardMessageContent(message.content);
2164
- if (content === message.content) return message;
2165
- return { ...message, content };
2166
- }
2167
- function trimLastAssistantEchoForCliMessages(messages, prompt) {
2168
- if (!prompt) return;
2169
- for (let index = messages.length - 1; index >= 0; index -= 1) {
2170
- const message = messages[index];
2171
- if (!message || message.role !== "assistant" || typeof message.content !== "string") continue;
2172
- if ((message.kind || "standard") !== "standard") continue;
2173
- message.content = trimPromptEchoPrefix(message.content, prompt);
2174
- if (!message.content.trim()) {
2175
- messages.splice(index, 1);
2176
- }
2177
- return;
2178
- }
2179
- }
2180
- var os11, COMMITTED_ACTIVITY_PREFIX_BLOCK_RE, ProviderCliAdapter;
1312
+ var os11, ProviderCliAdapter;
2181
1313
  var init_provider_cli_adapter = __esm({
2182
1314
  "src/cli-adapters/provider-cli-adapter.ts"() {
2183
1315
  "use strict";
@@ -2187,13 +1319,10 @@ var init_provider_cli_adapter = __esm({
2187
1319
  init_terminal_screen();
2188
1320
  init_pty_transport();
2189
1321
  init_provider_cli_shared();
2190
- init_chat_message_normalization();
2191
- init_read_chat_contract();
2192
1322
  init_provider_cli_parse();
2193
1323
  init_provider_cli_config();
2194
1324
  init_provider_cli_runtime();
2195
1325
  init_provider_cli_shared();
2196
- COMMITTED_ACTIVITY_PREFIX_BLOCK_RE = /^(?:📖|💻|🔎|📚|📋|✏️|📝|🔧|🛠️|⚙️)\s+(.+)$/;
2197
1326
  ProviderCliAdapter = class _ProviderCliAdapter {
2198
1327
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
2199
1328
  this.extraArgs = extraArgs;
@@ -2236,11 +1365,6 @@ var init_provider_cli_adapter = __esm({
2236
1365
  provider;
2237
1366
  ptyProcess = null;
2238
1367
  transportFactory;
2239
- messages = [];
2240
- committedMessages = [];
2241
- structuredMessages = [];
2242
- committedMessagesActivitySignature = "";
2243
- committedMessagesChangedAt = 0;
2244
1368
  currentStatus = "starting";
2245
1369
  onStatusChange = null;
2246
1370
  responseBuffer = "";
@@ -2320,11 +1444,8 @@ var init_provider_cli_adapter = __esm({
2320
1444
  traceSeq = 0;
2321
1445
  traceSessionId = "";
2322
1446
  parsedStatusCache = null;
2323
- lastStatusHotPathParseAt = Number.NEGATIVE_INFINITY;
2324
- static STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1e3;
2325
1447
  static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
2326
1448
  static MAX_TRACE_ENTRIES = 250;
2327
- static PARSE_MESSAGE_TAIL_LIMIT = 100;
2328
1449
  providerResolutionMeta;
2329
1450
  static FINISH_RETRY_DELAY_MS = 300;
2330
1451
  static MAX_FINISH_RETRIES = 2;
@@ -2345,35 +1466,6 @@ var init_provider_cli_adapter = __esm({
2345
1466
  recordBoundedAppendDrop(previousLength, appendedLength, nextLength) {
2346
1467
  return Math.max(0, previousLength + appendedLength - nextLength);
2347
1468
  }
2348
- buildCommittedMessagesActivitySignature() {
2349
- const last = this.committedMessages[this.committedMessages.length - 1];
2350
- return [
2351
- String(this.committedMessages.length),
2352
- String(last?.role || ""),
2353
- String(last?.kind || ""),
2354
- String(last?.senderName || ""),
2355
- String(last?.timestamp || ""),
2356
- String(last?.receivedAt || ""),
2357
- normalizeComparableMessageContent(last?.content || "").slice(-240)
2358
- ].join("|");
2359
- }
2360
- syncMessageViews() {
2361
- const signature = this.buildCommittedMessagesActivitySignature();
2362
- if (signature !== this.committedMessagesActivitySignature) {
2363
- this.committedMessagesActivitySignature = signature;
2364
- this.committedMessagesChangedAt = Date.now();
2365
- }
2366
- this.messages = [...this.committedMessages];
2367
- this.structuredMessages = [...this.committedMessages];
2368
- }
2369
- getLastCommittedMessageActivityAt() {
2370
- const last = this.committedMessages[this.committedMessages.length - 1];
2371
- const messageTime = Math.max(
2372
- typeof last?.receivedAt === "number" && Number.isFinite(last.receivedAt) ? last.receivedAt : 0,
2373
- typeof last?.timestamp === "number" && Number.isFinite(last.timestamp) ? last.timestamp : 0
2374
- );
2375
- return Math.max(messageTime, this.committedMessagesChangedAt || 0);
2376
- }
2377
1469
  readTerminalScreenText(now = Date.now()) {
2378
1470
  const screenText = this.terminalScreen.getText() || "";
2379
1471
  this.lastScreenText = screenText;
@@ -2393,7 +1485,7 @@ var init_provider_cli_adapter = __esm({
2393
1485
  }
2394
1486
  getFreshParsedStatusCache() {
2395
1487
  const cached = this.parsedStatusCache;
2396
- 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) {
1488
+ 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) {
2397
1489
  return cached.result;
2398
1490
  }
2399
1491
  return null;
@@ -2404,45 +1496,6 @@ var init_provider_cli_adapter = __esm({
2404
1496
  shouldUseFullProviderTranscriptContext() {
2405
1497
  return this.providerOwnsTranscript() && this.provider.transcriptContext === "full";
2406
1498
  }
2407
- selectParseBaseMessages(baseMessages) {
2408
- if (this.shouldUseFullProviderTranscriptContext()) return baseMessages;
2409
- if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
2410
- return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
2411
- }
2412
- messagesShareStableIdentity(left, right) {
2413
- if (left === right) return true;
2414
- if (!left || !right) return false;
2415
- if ((left.role || "") !== (right.role || "")) return false;
2416
- if (left.id && right.id && String(left.id) === String(right.id)) return true;
2417
- if (typeof left.index === "number" && typeof right.index === "number" && left.index === right.index) return true;
2418
- return false;
2419
- }
2420
- messagesComparable(left, right) {
2421
- if (this.messagesShareStableIdentity(left, right)) return true;
2422
- if (!left || !right) return false;
2423
- if ((left.role || "") !== (right.role || "")) return false;
2424
- const leftText = normalizeComparableTranscriptText(left.content);
2425
- const rightText = normalizeComparableTranscriptText(right.content);
2426
- return !!leftText && leftText === rightText;
2427
- }
2428
- stitchParsedMessagesWithCommittedBase(parsedMessages, fullBaseMessages, parseBaseMessages) {
2429
- if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
2430
- if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
2431
- const parsedFirst = parsedMessages[0];
2432
- const fullFirst = fullBaseMessages[0];
2433
- if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
2434
- return parsedMessages;
2435
- }
2436
- const tailFirst = parseBaseMessages[0];
2437
- if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
2438
- const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
2439
- const prefix = fullBaseMessages.slice(0, prefixLength);
2440
- const shouldSanitizePrefix = !!this.currentTurnScope || this.currentStatus !== "idle" || !!this.activeModal;
2441
- const nextPrefix = shouldSanitizePrefix ? prefix.map((message) => sanitizeCommittedMessageForDisplay(message)) : prefix;
2442
- return [...nextPrefix, ...parsedMessages];
2443
- }
2444
- return [...fullBaseMessages, ...parsedMessages];
2445
- }
2446
1499
  getIdleFinishConfirmMs() {
2447
1500
  return this.timeouts.idleFinishConfirm;
2448
1501
  }
@@ -2895,9 +1948,6 @@ var init_provider_cli_adapter = __esm({
2895
1948
  `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
2896
1949
  );
2897
1950
  }
2898
- trimLastAssistantEcho(messages, prompt) {
2899
- trimLastAssistantEchoForCliMessages(messages, prompt);
2900
- }
2901
1951
  clearAllTimers() {
2902
1952
  if (this.responseTimeout) {
2903
1953
  clearTimeout(this.responseTimeout);
@@ -2993,10 +2043,10 @@ var init_provider_cli_adapter = __esm({
2993
2043
  }
2994
2044
  const session = this.runParseSession();
2995
2045
  if (!session) return;
2996
- const { status, messages, modal, parsedStatus } = session;
2046
+ const { status, messages, parsedStatus } = session;
2047
+ const modal = session.activeModal ?? session.modal ?? null;
2997
2048
  const parsedMessages = normalizeCliParsedMessages(messages, {
2998
- committedMessages: this.committedMessages,
2999
- scope: this.currentTurnScope,
2049
+ scope: null,
3000
2050
  lastOutputAt: this.lastOutputAt
3001
2051
  });
3002
2052
  if (this.maybeCommitVisibleIdleTranscript(session, parsedMessages)) return;
@@ -3176,7 +2226,7 @@ var init_provider_cli_adapter = __esm({
3176
2226
  const effectiveScreenText = screenText || this.accumulatedBuffer;
3177
2227
  const noActiveTurn = !this.currentTurnScope;
3178
2228
  const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText);
3179
- const parsedShowsLiveAssistantProgress = parsedStatus === "generating" && !!lastParsedAssistant && parsedMessages.length > this.committedMessages.length;
2229
+ const parsedShowsLiveAssistantProgress = parsedStatus === "generating" && !!lastParsedAssistant;
3180
2230
  if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
3181
2231
  return;
3182
2232
  }
@@ -3333,10 +2383,7 @@ var init_provider_cli_adapter = __esm({
3333
2383
  }
3334
2384
  const visibleAssistant = [...parsedMessages].reverse().find((m) => m.role === "assistant" && m.content.trim());
3335
2385
  if (!visibleAssistant) return false;
3336
- this.committedMessages = parsedMessages;
3337
- this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
3338
2386
  this.clearAllTimers();
3339
- this.syncMessageViews();
3340
2387
  this.responseBuffer = "";
3341
2388
  this.isWaitingForResponse = false;
3342
2389
  this.responseSettleIgnoreUntil = 0;
@@ -3348,37 +2395,34 @@ var init_provider_cli_adapter = __esm({
3348
2395
  this.setStatus("idle", "script_idle_commit");
3349
2396
  this.onStatusChange?.();
3350
2397
  this.recordTrace("script_idle_commit", {
3351
- messageCount: this.committedMessages.length,
2398
+ messageCount: parsedMessages.length,
3352
2399
  lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320)
3353
2400
  });
3354
2401
  return true;
3355
2402
  }
3356
2403
  commitCurrentTranscript() {
3357
2404
  const parsed = this.parseCurrentTranscript(
3358
- this.committedMessages,
2405
+ [],
3359
2406
  this.responseBuffer,
3360
2407
  this.currentTurnScope
3361
2408
  );
3362
2409
  if (parsed && Array.isArray(parsed.messages)) {
3363
- this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
3364
- committedMessages: this.committedMessages,
3365
- scope: this.currentTurnScope,
2410
+ const parsedMessages = normalizeCliParsedMessages(parsed.messages, {
2411
+ scope: null,
3366
2412
  lastOutputAt: this.lastOutputAt
3367
2413
  });
3368
- this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
3369
- this.syncMessageViews();
3370
- const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
2414
+ const lastAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
3371
2415
  if (this.currentTurnScope) {
3372
2416
  LOG.info(
3373
2417
  "CLI",
3374
- `[${this.cliType}] commitCurrentTranscript committedMessages=${this.committedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
2418
+ `[${this.cliType}] commitCurrentTranscript parserMessages=${parsedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
3375
2419
  );
3376
2420
  }
3377
2421
  this.recordTrace("commit_transcript", {
3378
2422
  parsedStatus: parsed.status || null,
3379
- messageCount: this.committedMessages.length,
2423
+ messageCount: parsedMessages.length,
3380
2424
  lastAssistant: lastAssistant ? summarizeCliTraceText(lastAssistant.content, 320) : "",
3381
- messages: summarizeCliTraceMessages(this.committedMessages),
2425
+ messages: summarizeCliTraceMessages(parsedMessages),
3382
2426
  ...buildCliTraceParseSnapshot({
3383
2427
  accumulatedBuffer: this.accumulatedBuffer,
3384
2428
  accumulatedRawBuffer: this.accumulatedRawBuffer,
@@ -3412,63 +2456,31 @@ var init_provider_cli_adapter = __esm({
3412
2456
  }
3413
2457
  // ─── Script Execution ──────────────────────────
3414
2458
  runParseSession() {
3415
- if (typeof this.cliScripts?.parseSession === "function") {
3416
- try {
3417
- const screenText = this.terminalScreen.getText();
3418
- const tail = this.recentOutputBuffer.slice(-500);
3419
- const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
3420
- const input = buildCliParseInput({
3421
- accumulatedBuffer: this.accumulatedBuffer,
3422
- accumulatedRawBuffer: this.accumulatedRawBuffer,
3423
- recentOutputBuffer: this.recentOutputBuffer,
3424
- terminalScreenText: screenText,
3425
- baseMessages: parseBaseMessages,
3426
- partialResponse: this.responseBuffer,
3427
- isWaitingForResponse: this.isWaitingForResponse,
3428
- scope: this.currentTurnScope,
3429
- runtimeSettings: this.runtimeSettings
3430
- });
3431
- const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
3432
- if (session && typeof session === "object" && Array.isArray(session.messages)) {
3433
- session.messages = this.stitchParsedMessagesWithCommittedBase(
3434
- session.messages,
3435
- this.committedMessages,
3436
- parseBaseMessages
3437
- );
3438
- }
3439
- this.parseErrorMessage = null;
3440
- return session && typeof session === "object" ? session : null;
3441
- } catch (e) {
3442
- const message = e?.message || String(e);
3443
- this.parseErrorMessage = message;
3444
- LOG.warn("CLI", `[${this.cliType}] parseSession error: ${message}`);
3445
- return null;
3446
- }
2459
+ if (typeof this.cliScripts?.parseSession !== "function") {
2460
+ this.parseErrorMessage = `${this.cliType} parseSession unavailable`;
2461
+ return null;
3447
2462
  }
3448
- if (!this.cliScripts?.detectStatus && !this.cliScripts?.parseOutput) return null;
3449
2463
  try {
3450
- const tail = this.settledBuffer;
3451
- const parsedTranscript = this.parseCurrentTranscript(
3452
- this.committedMessages,
3453
- this.responseBuffer,
3454
- this.currentTurnScope
3455
- );
3456
- const parsedModal = parsedTranscript?.activeModal && Array.isArray(parsedTranscript.activeModal.buttons) && parsedTranscript.activeModal.buttons.some((b) => typeof b === "string" && b.trim()) ? parsedTranscript.activeModal : null;
3457
- const approval = this.runParseApproval(tail);
3458
- const modal = approval || parsedModal;
3459
- const rawStatus = this.runDetectStatus(tail);
3460
- const parsedStatus = typeof parsedTranscript?.status === "string" ? parsedTranscript.status : null;
3461
- const effectiveStatus = parsedStatus === "waiting_approval" && modal ? "waiting_approval" : rawStatus || parsedStatus || "idle";
3462
- return {
3463
- status: effectiveStatus,
3464
- messages: Array.isArray(parsedTranscript?.messages) ? parsedTranscript.messages : [],
3465
- modal,
3466
- parsedStatus
3467
- };
2464
+ const screenText = this.terminalScreen.getText();
2465
+ const tail = this.recentOutputBuffer.slice(-500);
2466
+ const input = buildCliParseInput({
2467
+ accumulatedBuffer: this.accumulatedBuffer,
2468
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2469
+ recentOutputBuffer: this.recentOutputBuffer,
2470
+ terminalScreenText: screenText,
2471
+ baseMessages: [],
2472
+ partialResponse: this.responseBuffer,
2473
+ isWaitingForResponse: this.isWaitingForResponse,
2474
+ scope: this.currentTurnScope,
2475
+ runtimeSettings: this.runtimeSettings
2476
+ });
2477
+ const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
2478
+ this.parseErrorMessage = null;
2479
+ return session && typeof session === "object" ? session : null;
3468
2480
  } catch (e) {
3469
2481
  const message = e?.message || String(e);
3470
2482
  this.parseErrorMessage = message;
3471
- LOG.warn("CLI", `[${this.cliType}] parseSession fallback error: ${message}`);
2483
+ LOG.warn("CLI", `[${this.cliType}] parseSession error: ${message}`);
3472
2484
  return null;
3473
2485
  }
3474
2486
  }
@@ -3518,45 +2530,14 @@ var init_provider_cli_adapter = __esm({
3518
2530
  if (this.isWaitingForResponse && this.currentTurnScope && this.currentStatus !== "stopped") return "generating";
3519
2531
  return this.currentStatus;
3520
2532
  }
3521
- suppressStaleParsedApproval(parsed, recentBuffer, screenText) {
3522
- const actionableParsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
3523
- if (!parsed || parsed?.status !== "waiting_approval" || !actionableParsedModal) {
3524
- return parsed;
3525
- }
3526
- const inApprovalCooldown = this.lastApprovalResolvedAt > 0 && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
3527
- if (!inApprovalCooldown) {
3528
- return parsed;
3529
- }
3530
- const visibleModal = this.runParseApproval(recentBuffer);
3531
- if (visibleModal) {
3532
- return parsed;
3533
- }
3534
- const detectedStatus = this.runDetectStatus(recentBuffer);
3535
- const resolvedStatus = detectedStatus && detectedStatus !== "waiting_approval" ? detectedStatus : this.isWaitingForResponse || this.currentTurnScope ? "generating" : this.currentStatus === "waiting_approval" ? "idle" : this.currentStatus;
3536
- return {
3537
- ...parsed,
3538
- status: resolvedStatus,
3539
- activeModal: null
3540
- };
3541
- }
3542
2533
  // ─── Public API (CliAdapter) ───────────────────
3543
2534
  getStatus(options = {}) {
3544
2535
  const allowParse = options.allowParse !== false;
3545
2536
  const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
3546
2537
  let effectiveStatus = this.projectEffectiveStatus(startupModal);
3547
2538
  let effectiveModal = startupModal || this.activeModal;
3548
- if (allowParse && !startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
3549
- let parsed = this.getFreshParsedStatusCache();
3550
- if (!parsed && effectiveStatus !== "idle") {
3551
- const now = Date.now();
3552
- if (now - this.lastStatusHotPathParseAt >= _ProviderCliAdapter.STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS) {
3553
- this.lastStatusHotPathParseAt = now;
3554
- try {
3555
- parsed = this.getScriptParsedStatus();
3556
- } catch {
3557
- }
3558
- }
3559
- }
2539
+ if (allowParse && !startupModal && !effectiveModal) {
2540
+ const parsed = this.getFreshParsedStatusCache();
3560
2541
  const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
3561
2542
  if (parsed?.status === "waiting_approval" && parsedModal) {
3562
2543
  effectiveStatus = "waiting_approval";
@@ -3566,7 +2547,7 @@ var init_provider_cli_adapter = __esm({
3566
2547
  const bufferState = this.getBufferState();
3567
2548
  return {
3568
2549
  status: effectiveStatus,
3569
- messages: [...this.committedMessages],
2550
+ messages: [],
3570
2551
  workingDir: this.workingDir,
3571
2552
  activeModal: effectiveModal,
3572
2553
  errorMessage: this.parseErrorMessage || void 0,
@@ -3574,98 +2555,6 @@ var init_provider_cli_adapter = __esm({
3574
2555
  ...bufferState ? { bufferState } : {}
3575
2556
  };
3576
2557
  }
3577
- seedCommittedMessages(messages) {
3578
- const normalized = (Array.isArray(messages) ? messages : []).filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
3579
- role: message.role,
3580
- content: typeof message.content === "string" ? message.content : String(message.content || ""),
3581
- timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0,
3582
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : void 0,
3583
- kind: typeof message.kind === "string" ? message.kind : void 0,
3584
- id: typeof message.id === "string" ? message.id : void 0,
3585
- index: typeof message.index === "number" ? message.index : void 0,
3586
- providerUnitKey: typeof message.providerUnitKey === "string" ? message.providerUnitKey : void 0,
3587
- bubbleId: typeof message.bubbleId === "string" ? message.bubbleId : void 0,
3588
- bubbleState: typeof message.bubbleState === "string" ? message.bubbleState : void 0,
3589
- _turnKey: typeof message._turnKey === "string" ? message._turnKey : void 0,
3590
- meta: message.meta && typeof message.meta === "object" ? { ...message.meta } : void 0,
3591
- senderName: typeof message.senderName === "string" ? message.senderName : void 0
3592
- }));
3593
- this.committedMessages = normalized;
3594
- this.syncMessageViews();
3595
- }
3596
- getSharedCommittedPrefixLength(parsedMessages) {
3597
- const committedMessages = this.committedMessages;
3598
- const max = Math.min(parsedMessages.length, committedMessages.length);
3599
- let index = 0;
3600
- while (index < max && this.messagesShareStableIdentity(parsedMessages[index], committedMessages[index])) {
3601
- index += 1;
3602
- }
3603
- return index;
3604
- }
3605
- hydrateCommittedPrefixForParsedStatus(parsedMessages) {
3606
- const sharedPrefixLength = this.getSharedCommittedPrefixLength(parsedMessages);
3607
- if (sharedPrefixLength !== this.committedMessages.length) return null;
3608
- const committedHydratedMessages = this.committedMessages.map((message, index) => {
3609
- const timestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : this.lastOutputAt || this.currentTurnScope?.startedAt || Date.now();
3610
- const contentValue = message.content;
3611
- return {
3612
- role: message.role,
3613
- content: typeof contentValue === "string" ? contentValue : String(contentValue || ""),
3614
- timestamp,
3615
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp,
3616
- kind: message.kind,
3617
- id: message.id || `msg_${index}`,
3618
- index: typeof message.index === "number" ? message.index : index,
3619
- providerUnitKey: message.providerUnitKey,
3620
- bubbleId: message.bubbleId,
3621
- bubbleState: message.bubbleState,
3622
- _turnKey: message._turnKey,
3623
- meta: message.meta,
3624
- senderName: message.senderName
3625
- };
3626
- });
3627
- const extraMessages = parsedMessages.slice(sharedPrefixLength);
3628
- if (extraMessages.length === 0) return committedHydratedMessages;
3629
- const extraHydratedMessages = hydrateCliParsedMessages(extraMessages, {
3630
- committedMessages: [],
3631
- scope: this.currentTurnScope,
3632
- lastOutputAt: this.lastOutputAt
3633
- }).map((message, offset) => ({
3634
- ...message,
3635
- id: message.id || `msg_${sharedPrefixLength + offset}`,
3636
- index: typeof message.index === "number" ? message.index : sharedPrefixLength + offset
3637
- }));
3638
- return [...committedHydratedMessages, ...extraHydratedMessages];
3639
- }
3640
- hydrateParsedMessagesForStatus(parsedMessages) {
3641
- return this.hydrateCommittedPrefixForParsedStatus(parsedMessages) || hydrateCliParsedMessages(parsedMessages, {
3642
- committedMessages: this.committedMessages,
3643
- scope: this.currentTurnScope,
3644
- lastOutputAt: this.lastOutputAt
3645
- });
3646
- }
3647
- buildCommittedChatMessages() {
3648
- return this.committedMessages.map((message, index) => {
3649
- const rawContentValue = message.content;
3650
- const rawContent = typeof rawContentValue === "string" ? rawContentValue : String(rawContentValue || "");
3651
- const content = message.role === "assistant" && (message.kind || "standard") === "standard" ? sanitizeCliStandardMessageContent(rawContent) : rawContent;
3652
- return buildChatMessage({
3653
- role: message.role,
3654
- content,
3655
- timestamp: message.timestamp,
3656
- kind: message.kind,
3657
- meta: message.meta,
3658
- senderName: message.senderName,
3659
- id: message.id || `msg_${index}`,
3660
- index: typeof message.index === "number" ? message.index : index,
3661
- providerUnitKey: message.providerUnitKey,
3662
- bubbleId: message.bubbleId,
3663
- bubbleState: message.bubbleState,
3664
- _turnKey: message._turnKey,
3665
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
3666
- });
3667
- });
3668
- }
3669
2558
  /**
3670
2559
  * Script-based full parse — returns ReadChatResult.
3671
2560
  * Called by command handler / dashboard for rich content rendering.
@@ -3673,125 +2562,30 @@ var init_provider_cli_adapter = __esm({
3673
2562
  getScriptParsedStatus() {
3674
2563
  const screenText = this.readTerminalScreenText();
3675
2564
  const cached = this.parsedStatusCache;
3676
- 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) {
2565
+ 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) {
3677
2566
  return cached.result;
3678
2567
  }
3679
- const parsed = this.parseCurrentTranscript(
3680
- this.committedMessages,
3681
- this.responseBuffer,
3682
- this.currentTurnScope,
3683
- screenText
3684
- );
3685
- const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
3686
- if (parsedModal && parsed?.status === "waiting_approval") {
3687
- this.activeModal = parsedModal;
3688
- this.isWaitingForResponse = true;
3689
- if (this.currentStatus !== "waiting_approval") {
3690
- this.setStatus("waiting_approval", "parsed_waiting_approval");
3691
- this.onStatusChange?.();
3692
- }
2568
+ const parsed = this.runParseSession();
2569
+ if (!parsed || !Array.isArray(parsed.messages)) {
2570
+ throw new Error(this.parseErrorMessage || `${this.cliType} parseSession did not return messages`);
3693
2571
  }
3694
- if (parsed && Array.isArray(parsed.messages) && this.provider.allowInputDuringGeneration === true) {
3695
- const hydratedForCommit = normalizeCliParsedMessages(parsed.messages, {
3696
- committedMessages: this.committedMessages,
3697
- scope: this.currentTurnScope,
2572
+ const activeModal = parsed.activeModal ?? parsed.modal ?? null;
2573
+ const bufferState = this.getBufferState();
2574
+ const result = {
2575
+ id: parsed.id || "cli_session",
2576
+ status: parsed.status || this.currentStatus,
2577
+ title: parsed.title || this.cliName,
2578
+ messages: normalizeCliParsedMessages(parsed.messages, {
2579
+ scope: null,
3698
2580
  lastOutputAt: this.lastOutputAt
3699
- });
3700
- const fakeSession = {
3701
- status: parsed.status || "idle",
3702
- messages: parsed.messages,
3703
- modal: parsedModal,
3704
- parsedStatus: parsed.status || null
3705
- };
3706
- if (this.maybeCommitVisibleIdleTranscript(fakeSession, hydratedForCommit)) {
3707
- return this.getScriptParsedStatus();
3708
- }
3709
- }
3710
- const shouldPreferCommittedMessages = !this.currentTurnScope && !this.activeModal && this.currentStatus === "idle";
3711
- let result;
3712
- if (parsed && Array.isArray(parsed.messages)) {
3713
- const parsedHydratedMessages = this.hydrateParsedMessagesForStatus(parsed.messages);
3714
- const parsedLastAssistant = [...parsedHydratedMessages].reverse().find((message) => message.role === "assistant" && typeof message.content === "string" && message.content.trim());
3715
- 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");
3716
- if (shouldAdoptParsedIdleReplay) {
3717
- this.committedMessages = this.getSharedCommittedPrefixLength(parsed.messages) === this.committedMessages.length ? parsedHydratedMessages.map((message) => ({
3718
- role: message.role,
3719
- content: typeof message.content === "string" ? message.content : String(message.content || ""),
3720
- timestamp: message.timestamp,
3721
- receivedAt: message.receivedAt,
3722
- kind: message.kind,
3723
- id: message.id,
3724
- index: message.index,
3725
- meta: message.meta,
3726
- senderName: message.senderName
3727
- })) : normalizeCliParsedMessages(parsed.messages, {
3728
- committedMessages: this.committedMessages,
3729
- scope: this.currentTurnScope,
3730
- lastOutputAt: this.lastOutputAt
3731
- });
3732
- this.syncMessageViews();
3733
- if (this.currentStatus !== "idle" || this.isWaitingForResponse) {
3734
- this.responseBuffer = "";
3735
- this.isWaitingForResponse = false;
3736
- this.responseSettleIgnoreUntil = 0;
3737
- this.submitRetryUsed = false;
3738
- this.submitRetryPromptSnippet = "";
3739
- this.finishRetryCount = 0;
3740
- this.currentTurnScope = null;
3741
- this.activeModal = null;
3742
- this.setStatus("idle", "parsed_idle_replay_commit");
3743
- this.onStatusChange?.();
3744
- }
3745
- }
3746
- const shouldPreferCommittedHistoryReplay = !this.currentTurnScope && !this.activeModal && this.committedMessages.length > parsedHydratedMessages.length;
3747
- const shouldPreferCommittedIdleReplay = shouldPreferCommittedMessages && !shouldAdoptParsedIdleReplay;
3748
- const hydratedMessages = shouldPreferCommittedIdleReplay || shouldPreferCommittedHistoryReplay ? this.buildCommittedChatMessages() : parsedHydratedMessages;
3749
- result = {
3750
- id: parsed.id || "cli_session",
3751
- status: parsed.status || this.currentStatus,
3752
- title: parsed.title || this.cliName,
3753
- messages: hydratedMessages,
3754
- activeModal: parsed.activeModal ?? this.activeModal,
3755
- providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
3756
- ...this.getBufferState() ? { bufferState: this.getBufferState() } : {},
3757
- ...this.providerOwnsTranscript() ? { transcriptAuthority: "provider", coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
3758
- };
3759
- } else {
3760
- const messages = [...this.committedMessages];
3761
- const bufferState = this.getBufferState();
3762
- result = {
3763
- id: "cli_session",
3764
- status: this.currentStatus,
3765
- title: this.cliName,
3766
- messages: messages.map((message, index) => buildChatMessage({
3767
- ...message,
3768
- id: message.id || `msg_${index}`,
3769
- index: typeof message.index === "number" ? message.index : index,
3770
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
3771
- })),
3772
- activeModal: this.activeModal,
3773
- ...bufferState ? { bufferState } : {}
3774
- };
3775
- }
3776
- const hasVisibleAssistantMessage = Array.isArray(result?.messages) && result.messages.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
3777
- const shouldClampStaleGeneratingToIdle = result?.status === "generating" && this.currentStatus === "idle" && !this.currentTurnScope && !result?.activeModal && hasVisibleAssistantMessage && !hasVisibleInterruptPrompt(screenText);
3778
- if (shouldClampStaleGeneratingToIdle) {
3779
- result = {
3780
- ...result,
3781
- status: "idle",
3782
- messages: Array.isArray(result.messages) ? result.messages.map((message) => {
3783
- if (message?.role !== "assistant" || !message?.meta?.streaming) return message;
3784
- const nextMeta = { ...message.meta || {} };
3785
- delete nextMeta.streaming;
3786
- return {
3787
- ...message,
3788
- ...Object.keys(nextMeta).length > 0 ? { meta: nextMeta } : { meta: void 0 }
3789
- };
3790
- }) : result.messages
3791
- };
3792
- }
2581
+ }),
2582
+ activeModal,
2583
+ providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
2584
+ ...bufferState ? { bufferState } : {},
2585
+ ...parsed.transcriptAuthority === "provider" || parsed.transcriptAuthority === "daemon" ? { transcriptAuthority: parsed.transcriptAuthority } : this.providerOwnsTranscript() ? { transcriptAuthority: "provider" } : {},
2586
+ ...parsed.coverage === "full" || parsed.coverage === "tail" || parsed.coverage === "current-turn" ? { coverage: parsed.coverage } : this.providerOwnsTranscript() ? { coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
2587
+ };
3793
2588
  this.parsedStatusCache = {
3794
- committedMessagesRef: this.committedMessages,
3795
2589
  responseBuffer: this.responseBuffer,
3796
2590
  currentTurnScope: this.currentTurnScope,
3797
2591
  recentOutputBuffer: this.recentOutputBuffer,
@@ -3814,7 +2608,7 @@ var init_provider_cli_adapter = __esm({
3814
2608
  accumulatedRawBuffer: this.accumulatedRawBuffer,
3815
2609
  recentOutputBuffer: this.recentOutputBuffer,
3816
2610
  terminalScreenText: this.terminalScreen.getText(),
3817
- baseMessages: this.committedMessages,
2611
+ baseMessages: [],
3818
2612
  partialResponse: this.responseBuffer,
3819
2613
  isWaitingForResponse: this.isWaitingForResponse,
3820
2614
  scope: this.currentTurnScope,
@@ -3825,46 +2619,8 @@ var init_provider_cli_adapter = __esm({
3825
2619
  args: args && typeof args === "object" ? { ...args } : {}
3826
2620
  }));
3827
2621
  }
3828
- parseCurrentTranscript(baseMessages, partialResponse, scope, screenTextOverride) {
3829
- if (!this.cliScripts?.parseOutput) {
3830
- this.parseErrorMessage = null;
3831
- return null;
3832
- }
3833
- try {
3834
- const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.terminalScreen.getText();
3835
- const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
3836
- const input = buildCliParseInput({
3837
- accumulatedBuffer: this.accumulatedBuffer,
3838
- accumulatedRawBuffer: this.accumulatedRawBuffer,
3839
- recentOutputBuffer: this.recentOutputBuffer,
3840
- terminalScreenText: screenText,
3841
- baseMessages: parseBaseMessages,
3842
- partialResponse,
3843
- isWaitingForResponse: this.isWaitingForResponse,
3844
- scope,
3845
- runtimeSettings: this.runtimeSettings
3846
- });
3847
- const parsed = this.cliScripts.parseOutput(input);
3848
- if (parsed && typeof parsed === "object") {
3849
- Object.assign(parsed, validateReadChatResultPayload(parsed, `${this.cliType} parseOutput`));
3850
- }
3851
- const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
3852
- if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
3853
- normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
3854
- normalizedParsed.messages,
3855
- baseMessages,
3856
- parseBaseMessages
3857
- );
3858
- this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
3859
- }
3860
- this.parseErrorMessage = null;
3861
- return normalizedParsed;
3862
- } catch (e) {
3863
- const message = e?.message || String(e);
3864
- this.parseErrorMessage = message;
3865
- LOG.warn("CLI", `[${this.cliType}] parseOutput error: ${message}`);
3866
- throw e;
3867
- }
2622
+ parseCurrentTranscript(_baseMessages, _partialResponse, _scope, _screenTextOverride) {
2623
+ return this.runParseSession();
3868
2624
  }
3869
2625
  /** Whether this adapter has CLI scripts loaded */
3870
2626
  hasCliScripts() {
@@ -3926,8 +2682,6 @@ var init_provider_cli_adapter = __esm({
3926
2682
  commitSendUserTurn(state) {
3927
2683
  if (state.didCommitUserTurn) return;
3928
2684
  state.didCommitUserTurn = true;
3929
- this.committedMessages.push({ role: "user", content: state.text, timestamp: Date.now() });
3930
- this.syncMessageViews();
3931
2685
  }
3932
2686
  armResponseTimeout() {
3933
2687
  if (this.responseTimeout) clearTimeout(this.responseTimeout);
@@ -4119,11 +2873,6 @@ var init_provider_cli_adapter = __esm({
4119
2873
  }
4120
2874
  })() : null;
4121
2875
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
4122
- const parsedMessagesBeforeSend = Array.isArray(parsedStatusBeforeSend?.messages) ? parsedStatusBeforeSend.messages.filter((message) => message && (message.role === "user" || message.role === "assistant")) : [];
4123
- const shouldCommitParsedIdleBeforeSend = !allowInputDuringGeneration && parsedSessionStatus === "idle" && parsedMessagesBeforeSend.length > this.committedMessages.length && parsedMessagesBeforeSend.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
4124
- if (shouldCommitParsedIdleBeforeSend) {
4125
- this.commitCurrentTranscript();
4126
- }
4127
2876
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
4128
2877
  throw new Error(`${this.cliName} is still processing the previous prompt`);
4129
2878
  }
@@ -4229,9 +2978,6 @@ var init_provider_cli_adapter = __esm({
4229
2978
  activeModal: this.activeModal,
4230
2979
  parseErrorMessage: this.parseErrorMessage,
4231
2980
  messageCounts: {
4232
- committed: this.committedMessages.length,
4233
- structured: this.structuredMessages.length,
4234
- visible: this.messages.length,
4235
2981
  parsedCache: Array.isArray(parsedResult?.messages) ? parsedResult.messages.length : void 0
4236
2982
  },
4237
2983
  buffers: {
@@ -4282,8 +3028,7 @@ var init_provider_cli_adapter = __esm({
4282
3028
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
4283
3029
  responseEpoch: this.responseEpoch,
4284
3030
  resizeSuppressUntil: this.resizeSuppressUntil,
4285
- lastApprovalResolvedAt: this.lastApprovalResolvedAt,
4286
- committedMessagesChangedAt: this.committedMessagesChangedAt
3031
+ lastApprovalResolvedAt: this.lastApprovalResolvedAt
4287
3032
  },
4288
3033
  finish: {
4289
3034
  idleFinishCandidate: this.idleFinishCandidate,
@@ -4408,8 +3153,6 @@ var init_provider_cli_adapter = __esm({
4408
3153
  }
4409
3154
  clearHistory() {
4410
3155
  this.clearIdleFinishCandidate("clear_history");
4411
- this.committedMessages = [];
4412
- this.syncMessageViews();
4413
3156
  this.accumulatedBuffer = "";
4414
3157
  this.accumulatedRawBuffer = "";
4415
3158
  this.currentTurnScope = null;
@@ -4450,7 +3193,7 @@ var init_provider_cli_adapter = __esm({
4450
3193
  }
4451
3194
  resolveModal(buttonIndex) {
4452
3195
  let modal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
4453
- if (!modal && typeof this.cliScripts?.parseOutput === "function") {
3196
+ if (!modal && typeof this.cliScripts?.parseSession === "function") {
4454
3197
  try {
4455
3198
  const parsed = this.getScriptParsedStatus();
4456
3199
  const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
@@ -4517,10 +3260,8 @@ var init_provider_cli_adapter = __esm({
4517
3260
  startupParseGate: this.startupParseGate,
4518
3261
  spawnAt: this.spawnAt,
4519
3262
  workingDir: this.workingDir,
4520
- messages: this.messages,
4521
- committedMessages: this.committedMessages,
4522
- structuredMessages: this.structuredMessages,
4523
- messageCount: this.committedMessages.length,
3263
+ messages: [],
3264
+ messageCount: 0,
4524
3265
  screenText: screenText.slice(-4e3),
4525
3266
  currentTurnScope: this.currentTurnScope,
4526
3267
  startupBuffer: this.startupBuffer.slice(-4e3),
@@ -4572,7 +3313,7 @@ var init_provider_cli_adapter = __esm({
4572
3313
  lifecycleStatus: this.isWaitingForResponse ? "awaiting_response" : "idle",
4573
3314
  activeModal: this.activeModal,
4574
3315
  currentTurnScope: this.currentTurnScope,
4575
- messages: summarizeCliTraceMessages(this.committedMessages, 5)
3316
+ messages: []
4576
3317
  };
4577
3318
  }
4578
3319
  getProviderResolutionMeta() {
@@ -8362,14 +7103,223 @@ var CdpDomHandlers = class {
8362
7103
  return { success: false, error: e.message };
8363
7104
  }
8364
7105
  }
8365
- };
8366
-
8367
- // src/providers/ide-provider-instance.ts
8368
- var crypto2 = __toESM(require("crypto"));
8369
- init_contracts();
7106
+ };
7107
+
7108
+ // src/providers/ide-provider-instance.ts
7109
+ var crypto2 = __toESM(require("crypto"));
7110
+
7111
+ // src/providers/io-contracts.ts
7112
+ function normalizeInputEnvelope(input) {
7113
+ const normalized = normalizeInputEnvelopePayload(input);
7114
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
7115
+ return {
7116
+ parts: normalized.parts,
7117
+ textFallback,
7118
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
7119
+ };
7120
+ }
7121
+ function normalizeMessageParts(content) {
7122
+ if (typeof content === "string") return [{ type: "text", text: content }];
7123
+ if (!Array.isArray(content)) {
7124
+ if (content && typeof content === "object" && typeof content.text === "string") {
7125
+ return [{ type: "text", text: String(content.text) }];
7126
+ }
7127
+ return [];
7128
+ }
7129
+ const parts = [];
7130
+ for (const raw of content) {
7131
+ if (typeof raw === "string") {
7132
+ parts.push({ type: "text", text: raw });
7133
+ continue;
7134
+ }
7135
+ if (!raw || typeof raw !== "object") continue;
7136
+ const part = normalizeMessagePartObject(raw);
7137
+ if (part) parts.push(part);
7138
+ }
7139
+ return parts;
7140
+ }
7141
+ function flattenMessageParts(parts) {
7142
+ return parts.map((part) => {
7143
+ if (part.type === "text") return part.text;
7144
+ if (part.type === "resource") return part.resource.text || "";
7145
+ return "";
7146
+ }).filter((value) => value.length > 0).join("\n");
7147
+ }
7148
+ function normalizeInputEnvelopePayload(input) {
7149
+ if (typeof input === "string") {
7150
+ return { parts: [{ type: "text", text: input }], textFallback: input };
7151
+ }
7152
+ if (!input || typeof input !== "object") {
7153
+ return { parts: [], textFallback: "" };
7154
+ }
7155
+ const record = input;
7156
+ const nestedInput = record.input;
7157
+ if (nestedInput && typeof nestedInput === "object") {
7158
+ const nested = nestedInput;
7159
+ return {
7160
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
7161
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
7162
+ metadata: normalizeInputMetadata(nested.metadata)
7163
+ };
7164
+ }
7165
+ const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
7166
+ if (directText !== void 0) {
7167
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
7168
+ }
7169
+ const directParts = normalizeInputParts(record.parts ?? record.prompt);
7170
+ return {
7171
+ parts: directParts,
7172
+ textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
7173
+ metadata: normalizeInputMetadata(record.metadata)
7174
+ };
7175
+ }
7176
+ function normalizeInputMetadata(value) {
7177
+ if (!value || typeof value !== "object") return void 0;
7178
+ const record = value;
7179
+ const metadata = {};
7180
+ if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
7181
+ metadata.source = record.source;
7182
+ }
7183
+ if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
7184
+ metadata.clientTimestamp = record.clientTimestamp;
7185
+ }
7186
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
7187
+ }
7188
+ function normalizeInputParts(value) {
7189
+ if (!Array.isArray(value)) return [];
7190
+ const parts = [];
7191
+ for (const raw of value) {
7192
+ if (typeof raw === "string") {
7193
+ parts.push({ type: "text", text: raw });
7194
+ continue;
7195
+ }
7196
+ if (!raw || typeof raw !== "object") continue;
7197
+ const part = normalizeInputPartObject(raw);
7198
+ if (part) parts.push(part);
7199
+ }
7200
+ return parts;
7201
+ }
7202
+ function normalizeInputPartObject(raw) {
7203
+ const type = raw.type;
7204
+ if (type === "text" && typeof raw.text === "string") {
7205
+ return { type, text: raw.text };
7206
+ }
7207
+ if (type === "image" && typeof raw.mimeType === "string") {
7208
+ return {
7209
+ type,
7210
+ mimeType: raw.mimeType,
7211
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7212
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7213
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
7214
+ };
7215
+ }
7216
+ if (type === "audio" && typeof raw.mimeType === "string") {
7217
+ return {
7218
+ type,
7219
+ mimeType: raw.mimeType,
7220
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7221
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7222
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7223
+ };
7224
+ }
7225
+ if (type === "video" && typeof raw.mimeType === "string") {
7226
+ return {
7227
+ type,
7228
+ mimeType: raw.mimeType,
7229
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7230
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7231
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7232
+ };
7233
+ }
7234
+ if (type === "resource" && typeof raw.uri === "string") {
7235
+ return {
7236
+ type,
7237
+ uri: raw.uri,
7238
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7239
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
7240
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
7241
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
7242
+ };
7243
+ }
7244
+ if (type === "resource_link" && typeof raw.uri === "string") {
7245
+ return {
7246
+ type: "resource",
7247
+ uri: raw.uri,
7248
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7249
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
7250
+ };
7251
+ }
7252
+ return null;
7253
+ }
7254
+ function normalizeMessagePartObject(raw) {
7255
+ const type = raw.type;
7256
+ if (type === "text" && typeof raw.text === "string") {
7257
+ return { type, text: raw.text };
7258
+ }
7259
+ if (type === "image" && typeof raw.mimeType === "string") {
7260
+ return {
7261
+ type,
7262
+ mimeType: raw.mimeType,
7263
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7264
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
7265
+ };
7266
+ }
7267
+ if (type === "audio" && typeof raw.mimeType === "string") {
7268
+ return {
7269
+ type,
7270
+ mimeType: raw.mimeType,
7271
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7272
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7273
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7274
+ };
7275
+ }
7276
+ if (type === "video" && typeof raw.mimeType === "string") {
7277
+ return {
7278
+ type,
7279
+ mimeType: raw.mimeType,
7280
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7281
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7282
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7283
+ };
7284
+ }
7285
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
7286
+ return {
7287
+ type,
7288
+ uri: raw.uri,
7289
+ name: raw.name,
7290
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7291
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
7292
+ };
7293
+ }
7294
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
7295
+ const resource = raw.resource;
7296
+ if (typeof resource.uri !== "string") return null;
7297
+ return {
7298
+ type,
7299
+ resource: {
7300
+ uri: resource.uri,
7301
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
7302
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
7303
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
7304
+ }
7305
+ };
7306
+ }
7307
+ return null;
7308
+ }
7309
+ function flattenInputParts(parts) {
7310
+ return parts.map((part) => {
7311
+ if (part.type === "text") return part.text;
7312
+ if (part.type === "audio") return part.transcript || "";
7313
+ if (part.type === "resource") return part.text || "";
7314
+ return "";
7315
+ }).filter((value) => value.length > 0).join("\n");
7316
+ }
8370
7317
 
8371
- // src/providers/extension-provider-instance.ts
8372
- init_contracts();
7318
+ // src/providers/contracts.ts
7319
+ function flattenContent(content) {
7320
+ if (typeof content === "string") return content;
7321
+ return flattenMessageParts(normalizeMessageParts(content));
7322
+ }
8373
7323
 
8374
7324
  // src/providers/status-monitor.ts
8375
7325
  var DEFAULT_MONITOR_CONFIG = {
@@ -8483,9 +7433,151 @@ var StatusMonitor = class {
8483
7433
  }
8484
7434
  };
8485
7435
 
7436
+ // src/providers/chat-message-normalization.ts
7437
+ var BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
7438
+ var KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
7439
+ var CHAT_MESSAGE_KIND_ALIASES = {
7440
+ text: "standard",
7441
+ message: "standard",
7442
+ assistant: "standard",
7443
+ thinking: "thought",
7444
+ think: "thought",
7445
+ reasoning: "thought",
7446
+ reason: "thought",
7447
+ toolcall: "tool",
7448
+ tool_call: "tool",
7449
+ tooluse: "tool",
7450
+ tool_use: "tool",
7451
+ action: "tool",
7452
+ command: "terminal",
7453
+ cmd: "terminal",
7454
+ shell: "terminal",
7455
+ console: "terminal"
7456
+ };
7457
+ function canonicalizeKindHint(value) {
7458
+ return value.trim().toLowerCase().replace(/[\s-]+/g, "_");
7459
+ }
7460
+ function resolveBuiltinOrAliasKind(kind) {
7461
+ if (typeof kind !== "string") return null;
7462
+ const normalizedKind = canonicalizeKindHint(kind);
7463
+ if (!normalizedKind) return null;
7464
+ if (KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
7465
+ return CHAT_MESSAGE_KIND_ALIASES[normalizedKind] || null;
7466
+ }
7467
+ function inferHintKind(value) {
7468
+ const direct = resolveBuiltinOrAliasKind(value);
7469
+ if (direct) return direct;
7470
+ if (typeof value !== "string") return null;
7471
+ const normalized = canonicalizeKindHint(value);
7472
+ if (!normalized) return null;
7473
+ if (/thought|thinking|reasoning/.test(normalized)) return "thought";
7474
+ if (/tool/.test(normalized)) return "tool";
7475
+ if (/terminal|command|shell|console/.test(normalized)) return "terminal";
7476
+ return null;
7477
+ }
7478
+ function inferKindFromToolCalls(message) {
7479
+ const toolCalls = Array.isArray(message?.toolCalls) ? message.toolCalls : [];
7480
+ if (toolCalls.length === 0) return null;
7481
+ if (toolCalls.some((toolCall) => toolCall?.kind === "think")) return "thought";
7482
+ if (toolCalls.some((toolCall) => toolCall?.kind === "execute")) return "terminal";
7483
+ if (toolCalls.some((toolCall) => Array.isArray(toolCall?.content) && toolCall.content.some((entry) => entry?.type === "terminal"))) {
7484
+ return "terminal";
7485
+ }
7486
+ return "tool";
7487
+ }
7488
+ function inferMissingChatMessageKind(message) {
7489
+ const role = typeof message?.role === "string" ? message.role.trim().toLowerCase() : "";
7490
+ if (role === "system") return "system";
7491
+ const meta = message?.meta && typeof message.meta === "object" ? message.meta : void 0;
7492
+ const hintCandidates = [
7493
+ message?._sub,
7494
+ message?._type,
7495
+ meta?.label,
7496
+ typeof message?.senderName === "string" ? message.senderName : void 0
7497
+ ];
7498
+ for (const candidate of hintCandidates) {
7499
+ const inferred = inferHintKind(candidate);
7500
+ if (inferred) return inferred;
7501
+ }
7502
+ const inferredFromToolCalls = inferKindFromToolCalls(message);
7503
+ if (inferredFromToolCalls) return inferredFromToolCalls;
7504
+ return null;
7505
+ }
7506
+ function isBuiltinChatMessageKind(kind) {
7507
+ return resolveBuiltinOrAliasKind(kind) !== null;
7508
+ }
7509
+ function normalizeChatMessageKind(kind, role) {
7510
+ const resolvedKind = resolveBuiltinOrAliasKind(kind);
7511
+ if (resolvedKind) return resolvedKind;
7512
+ const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
7513
+ return normalizedRole === "system" ? "system" : "standard";
7514
+ }
7515
+ function resolveChatMessageKind(message) {
7516
+ const explicitKind = resolveBuiltinOrAliasKind(message?.kind);
7517
+ if (explicitKind) return explicitKind;
7518
+ const inferredKind = inferMissingChatMessageKind(message);
7519
+ if (inferredKind) return inferredKind;
7520
+ return normalizeChatMessageKind(message?.kind, message?.role);
7521
+ }
7522
+ function buildChatMessage(message) {
7523
+ return {
7524
+ ...message,
7525
+ kind: resolveChatMessageKind(message)
7526
+ };
7527
+ }
7528
+ function buildSystemChatMessage(message) {
7529
+ return buildChatMessage({
7530
+ ...message,
7531
+ role: "system",
7532
+ kind: message?.kind || "system"
7533
+ });
7534
+ }
7535
+ function buildRuntimeSystemChatMessage(message) {
7536
+ return buildSystemChatMessage({
7537
+ ...message,
7538
+ senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
7539
+ });
7540
+ }
7541
+ function buildAssistantChatMessage(message) {
7542
+ return buildChatMessage({
7543
+ ...message,
7544
+ role: "assistant",
7545
+ kind: message?.kind || "standard"
7546
+ });
7547
+ }
7548
+ function buildThoughtChatMessage(message) {
7549
+ return buildAssistantChatMessage({
7550
+ ...message,
7551
+ kind: message?.kind || "thought"
7552
+ });
7553
+ }
7554
+ function buildToolChatMessage(message) {
7555
+ return buildAssistantChatMessage({
7556
+ ...message,
7557
+ kind: message?.kind || "tool"
7558
+ });
7559
+ }
7560
+ function buildTerminalChatMessage(message) {
7561
+ return buildAssistantChatMessage({
7562
+ ...message,
7563
+ kind: message?.kind || "terminal"
7564
+ });
7565
+ }
7566
+ function buildUserChatMessage(message) {
7567
+ return buildChatMessage({
7568
+ ...message,
7569
+ role: "user",
7570
+ kind: message?.kind || "standard"
7571
+ });
7572
+ }
7573
+ function normalizeChatMessage(message) {
7574
+ return buildChatMessage(message);
7575
+ }
7576
+ function normalizeChatMessages(messages) {
7577
+ return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
7578
+ }
7579
+
8486
7580
  // src/providers/control-effects.ts
8487
- init_contracts();
8488
- init_chat_message_normalization();
8489
7581
  function extractProviderControlValues(controls, data) {
8490
7582
  if (!data || typeof data !== "object") return void 0;
8491
7583
  const values = {};
@@ -8682,7 +7774,6 @@ ${cleanBody}`;
8682
7774
  var fs3 = __toESM(require("fs"));
8683
7775
  var path10 = __toESM(require("path"));
8684
7776
  var os5 = __toESM(require("os"));
8685
- init_chat_message_normalization();
8686
7777
  var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
8687
7778
  var RETAIN_DAYS = 30;
8688
7779
  var SAVED_HISTORY_INDEX_VERSION = 1;
@@ -9961,9 +9052,6 @@ function resolveProviderStateSurface(params) {
9961
9052
  };
9962
9053
  }
9963
9054
 
9964
- // src/providers/extension-provider-instance.ts
9965
- init_chat_message_normalization();
9966
-
9967
9055
  // src/providers/open-panel-support.ts
9968
9056
  var IDE_PROVIDER_SESSION_CAPABILITIES_BASE = [
9969
9057
  "read_chat",
@@ -10397,7 +9485,143 @@ ${effect.notification.body || ""}`.trim();
10397
9485
 
10398
9486
  // src/providers/ide-provider-instance.ts
10399
9487
  init_logger();
10400
- init_read_chat_contract();
9488
+
9489
+ // src/providers/read-chat-contract.ts
9490
+ var VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "streaming", "long_generating"];
9491
+ var VALID_ROLES = ["user", "assistant", "system", "human"];
9492
+ var VALID_BUBBLE_STATES = ["draft", "streaming", "final", "removed"];
9493
+ var VALID_TURN_STATUSES = ["open", "waiting_approval", "complete", "error"];
9494
+ function isPlainObject3(value) {
9495
+ return !!value && typeof value === "object" && !Array.isArray(value);
9496
+ }
9497
+ function isFiniteNumber(value) {
9498
+ return typeof value === "number" && Number.isFinite(value);
9499
+ }
9500
+ function validateStatus(status, source) {
9501
+ if (typeof status !== "string" || !VALID_STATUSES.includes(status)) {
9502
+ throw new Error(`${source}: status must be one of ${VALID_STATUSES.join(", ")}`);
9503
+ }
9504
+ return status;
9505
+ }
9506
+ function validateRole(role, source, index) {
9507
+ if (typeof role !== "string" || !VALID_ROLES.includes(role)) {
9508
+ throw new Error(`${source}: messages[${index}].role must be one of ${VALID_ROLES.join(", ")}`);
9509
+ }
9510
+ return role;
9511
+ }
9512
+ function validateBubbleState(state, source, index) {
9513
+ if (typeof state !== "string" || !VALID_BUBBLE_STATES.includes(state)) {
9514
+ throw new Error(`${source}: messages[${index}].bubbleState must be one of ${VALID_BUBBLE_STATES.join(", ")}`);
9515
+ }
9516
+ return state;
9517
+ }
9518
+ function validateTurnStatus(turnStatus, source) {
9519
+ if (typeof turnStatus !== "string" || !VALID_TURN_STATUSES.includes(turnStatus)) {
9520
+ throw new Error(`${source}: turnStatus must be one of ${VALID_TURN_STATUSES.join(", ")}`);
9521
+ }
9522
+ return turnStatus;
9523
+ }
9524
+ function validateMessageContent(content, source, index) {
9525
+ if (typeof content === "string") return content;
9526
+ if (Array.isArray(content)) return normalizeMessageParts(content);
9527
+ throw new Error(`${source}: messages[${index}].content must be a string or structured content array`);
9528
+ }
9529
+ function validateMessage(message, source, index) {
9530
+ if (!isPlainObject3(message)) {
9531
+ throw new Error(`${source}: messages[${index}] must be an object`);
9532
+ }
9533
+ const normalized = {
9534
+ role: validateRole(message.role, source, index),
9535
+ content: validateMessageContent(message.content, source, index)
9536
+ };
9537
+ if (typeof message.kind === "string") normalized.kind = message.kind;
9538
+ if (typeof message.id === "string") normalized.id = message.id;
9539
+ if (typeof message.bubbleId === "string") normalized.bubbleId = message.bubbleId;
9540
+ if (typeof message.providerUnitKey === "string") normalized.providerUnitKey = message.providerUnitKey;
9541
+ if (message.bubbleState !== void 0) normalized.bubbleState = validateBubbleState(message.bubbleState, source, index);
9542
+ if (isFiniteNumber(message.index)) normalized.index = message.index;
9543
+ if (isFiniteNumber(message.timestamp)) normalized.timestamp = message.timestamp;
9544
+ if (isFiniteNumber(message.receivedAt)) normalized.receivedAt = message.receivedAt;
9545
+ if (typeof message._turnKey === "string") normalized._turnKey = message._turnKey;
9546
+ if (Array.isArray(message.toolCalls)) normalized.toolCalls = message.toolCalls;
9547
+ if (isPlainObject3(message.meta)) normalized.meta = message.meta;
9548
+ if (typeof message.senderName === "string") normalized.senderName = message.senderName;
9549
+ if (typeof message._type === "string") normalized._type = message._type;
9550
+ if (typeof message._sub === "string") normalized._sub = message._sub;
9551
+ return normalized;
9552
+ }
9553
+ function validateModal(activeModal, status, source) {
9554
+ if (activeModal == null) {
9555
+ if (status === "waiting_approval") {
9556
+ throw new Error(`${source}: waiting_approval status requires activeModal with buttons`);
9557
+ }
9558
+ return activeModal === null ? null : void 0;
9559
+ }
9560
+ if (!isPlainObject3(activeModal)) {
9561
+ throw new Error(`${source}: activeModal must be an object when provided`);
9562
+ }
9563
+ if (typeof activeModal.message !== "string") {
9564
+ throw new Error(`${source}: activeModal.message must be a string`);
9565
+ }
9566
+ if (!Array.isArray(activeModal.buttons) || activeModal.buttons.some((button) => typeof button !== "string" || !button.trim())) {
9567
+ throw new Error(`${source}: activeModal.buttons must be a non-empty string array`);
9568
+ }
9569
+ const normalized = {
9570
+ message: activeModal.message,
9571
+ buttons: activeModal.buttons.map((button) => button.trim())
9572
+ };
9573
+ if (isFiniteNumber(activeModal.width)) normalized.width = activeModal.width;
9574
+ if (isFiniteNumber(activeModal.height)) normalized.height = activeModal.height;
9575
+ return normalized;
9576
+ }
9577
+ function validateControlValues(controlValues, source) {
9578
+ if (controlValues === void 0) return void 0;
9579
+ if (!isPlainObject3(controlValues)) {
9580
+ throw new Error(`${source}: controlValues must be an object when provided`);
9581
+ }
9582
+ const normalized = {};
9583
+ for (const [key, value] of Object.entries(controlValues)) {
9584
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
9585
+ throw new Error(`${source}: controlValues.${key} must be string, number, or boolean`);
9586
+ }
9587
+ normalized[key] = value;
9588
+ }
9589
+ return normalized;
9590
+ }
9591
+ function validateReadChatResultPayload(raw, source = "read_chat") {
9592
+ if (!isPlainObject3(raw)) {
9593
+ throw new Error(`${source}: payload must be an object`);
9594
+ }
9595
+ const status = validateStatus(raw.status, source);
9596
+ if (!Array.isArray(raw.messages)) {
9597
+ throw new Error(`${source}: messages must be an array`);
9598
+ }
9599
+ const messages = raw.messages.map((message, index) => validateMessage(message, source, index));
9600
+ const activeModal = validateModal(raw.activeModal, status, source);
9601
+ const controlValues = validateControlValues(raw.controlValues, source);
9602
+ const normalized = {
9603
+ status,
9604
+ messages
9605
+ };
9606
+ if (activeModal !== void 0) normalized.activeModal = activeModal;
9607
+ if (typeof raw.id === "string") normalized.id = raw.id;
9608
+ if (typeof raw.title === "string") normalized.title = raw.title;
9609
+ if (typeof raw.currentTurnId === "string") normalized.currentTurnId = raw.currentTurnId;
9610
+ if (raw.turnStatus !== void 0) normalized.turnStatus = validateTurnStatus(raw.turnStatus, source);
9611
+ if (typeof raw.agentType === "string") normalized.agentType = raw.agentType;
9612
+ if (typeof raw.agentName === "string") normalized.agentName = raw.agentName;
9613
+ if (typeof raw.extensionId === "string") normalized.extensionId = raw.extensionId;
9614
+ if (typeof raw.inputContent === "string") normalized.inputContent = raw.inputContent;
9615
+ if (typeof raw.isVisible === "boolean") normalized.isVisible = raw.isVisible;
9616
+ if (typeof raw.isWelcomeScreen === "boolean") normalized.isWelcomeScreen = raw.isWelcomeScreen;
9617
+ if (controlValues) normalized.controlValues = controlValues;
9618
+ if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
9619
+ if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
9620
+ if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
9621
+ if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
9622
+ if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
9623
+ return normalized;
9624
+ }
10401
9625
 
10402
9626
  // src/providers/approval-utils.ts
10403
9627
  var DEFAULT_APPROVAL_POSITIVE_HINTS = [
@@ -10447,7 +9671,6 @@ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
10447
9671
  }
10448
9672
 
10449
9673
  // src/providers/ide-provider-instance.ts
10450
- init_chat_message_normalization();
10451
9674
  var IdeProviderInstance = class {
10452
9675
  type;
10453
9676
  category = "ide";
@@ -11910,7 +11133,6 @@ var fs4 = __toESM(require("fs"));
11910
11133
  var os6 = __toESM(require("os"));
11911
11134
  var path11 = __toESM(require("path"));
11912
11135
  var import_node_crypto = require("crypto");
11913
- init_contracts();
11914
11136
 
11915
11137
  // src/providers/provider-input-support.ts
11916
11138
  var VALID_INPUT_MEDIA_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "resource"]);
@@ -11968,7 +11190,6 @@ function assertProviderSupportsDeclaredInput(provider, input) {
11968
11190
  }
11969
11191
 
11970
11192
  // src/commands/chat-commands.ts
11971
- init_read_chat_contract();
11972
11193
  init_logger();
11973
11194
 
11974
11195
  // src/logging/debug-trace.ts
@@ -12096,10 +11317,6 @@ function buildChatTailDeliverySignature(payload) {
12096
11317
  payload.historySessionId || "",
12097
11318
  payload.status,
12098
11319
  payload.title || "",
12099
- payload.syncMode,
12100
- String(payload.replaceFrom),
12101
- String(payload.totalMessages),
12102
- payload.lastMessageSignature,
12103
11320
  payload.activeModal ? `${payload.activeModal.message}|${payload.activeModal.buttons.join("")}` : "",
12104
11321
  stringifySignatureMessages(payload.messages)
12105
11322
  ]);
@@ -12115,7 +11332,6 @@ function buildSessionModalDeliverySignature(payload) {
12115
11332
  }
12116
11333
 
12117
11334
  // src/commands/chat-commands.ts
12118
- init_chat_message_normalization();
12119
11335
  var RECENT_SEND_WINDOW_MS = 1200;
12120
11336
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
12121
11337
  var recentSendByTarget = /* @__PURE__ */ new Map();
@@ -12216,99 +11432,13 @@ function parseMaybeJson(value) {
12216
11432
  return value;
12217
11433
  }
12218
11434
  }
12219
- function getChatMessageSignature(message) {
12220
- return buildChatMessageSignature(message);
12221
- }
12222
- function normalizeReadChatCursor(args) {
12223
- const knownMessageCount = Math.max(0, Number(args?.knownMessageCount || 0));
12224
- const lastMessageSignature = typeof args?.lastMessageSignature === "string" ? args.lastMessageSignature : "";
12225
- const tailLimit = Math.max(0, Number(args?.tailLimit || 0));
12226
- return { knownMessageCount, lastMessageSignature, tailLimit };
11435
+ function normalizeReadChatTailLimit(args) {
11436
+ const value = Number(args?.tailLimit || 0);
11437
+ return Number.isFinite(value) ? Math.max(0, value) : 0;
12227
11438
  }
12228
11439
  function normalizeReadChatMessages(payload) {
12229
11440
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
12230
- return normalizeChatMessages(messages);
12231
- }
12232
- function normalizeReadChatReplayTextContent(content) {
12233
- return flattenContent(content || "").replace(/\s+/g, " ").trim();
12234
- }
12235
- function getReadChatReplayCollapseInfo(message) {
12236
- if (!message) return null;
12237
- const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
12238
- const kind = typeof message.kind === "string" ? message.kind.trim().toLowerCase() : "standard";
12239
- const senderName = typeof message.senderName === "string" ? message.senderName.trim().toLowerCase() : "";
12240
- const collapsible = role === "assistant" || role === "system";
12241
- if (!collapsible) return { role, kind, senderName, content: "", signature: "", collapsible };
12242
- const content = normalizeReadChatReplayTextContent(message.content);
12243
- return {
12244
- role,
12245
- kind,
12246
- senderName,
12247
- content,
12248
- signature: `${role}:${kind}:${senderName}:${content}`,
12249
- collapsible
12250
- };
12251
- }
12252
- function isStableReadChatAssistantAnswerInfo(info) {
12253
- if (!info) return false;
12254
- if (info.role !== "assistant") return false;
12255
- if (info.kind && info.kind !== "standard") return false;
12256
- if (info.content.length < 160) return false;
12257
- if (/^(bash|shell|terminal) command\b/i.test(info.content)) return false;
12258
- return true;
12259
- }
12260
- function isReplayedAssistantAnswerAfterStableAnswerInfo(info, stableContent) {
12261
- if (!info || !stableContent) return false;
12262
- if (info.role !== "assistant") return false;
12263
- if (info.kind && info.kind !== "standard") return false;
12264
- const content = info.content;
12265
- if (content.length < 80 || stableContent.length < 80) return false;
12266
- return content === stableContent || content.startsWith(stableContent) || stableContent.startsWith(content);
12267
- }
12268
- function collapseReplayDuplicatesFromReadChat(messages) {
12269
- const collapsed = [];
12270
- const replaySignaturesInCurrentTurn = /* @__PURE__ */ new Set();
12271
- let stableAssistantAnswerContentInCurrentTurn = "";
12272
- let stableAssistantAnswerCollapsedIndex = -1;
12273
- let stableAssistantAnswerHadInterveningActivity = false;
12274
- let previousReplaySignature = "";
12275
- for (const message of messages) {
12276
- const info = getReadChatReplayCollapseInfo(message);
12277
- if (info?.role === "user") {
12278
- replaySignaturesInCurrentTurn.clear();
12279
- stableAssistantAnswerContentInCurrentTurn = "";
12280
- stableAssistantAnswerCollapsedIndex = -1;
12281
- stableAssistantAnswerHadInterveningActivity = false;
12282
- previousReplaySignature = "";
12283
- }
12284
- if (info?.collapsible && info.signature) {
12285
- if (previousReplaySignature === info.signature) continue;
12286
- if (replaySignaturesInCurrentTurn.has(info.signature)) continue;
12287
- if (isReplayedAssistantAnswerAfterStableAnswerInfo(info, stableAssistantAnswerContentInCurrentTurn)) {
12288
- 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);
12289
- if (isAdjacentFullerAssistantAnswer) {
12290
- collapsed[stableAssistantAnswerCollapsedIndex] = message;
12291
- replaySignaturesInCurrentTurn.add(info.signature);
12292
- stableAssistantAnswerContentInCurrentTurn = info.content;
12293
- previousReplaySignature = info.signature;
12294
- }
12295
- continue;
12296
- }
12297
- }
12298
- collapsed.push(message);
12299
- previousReplaySignature = info?.collapsible ? info.signature : "";
12300
- if (info?.collapsible && info.signature) {
12301
- replaySignaturesInCurrentTurn.add(info.signature);
12302
- }
12303
- if (isStableReadChatAssistantAnswerInfo(info)) {
12304
- stableAssistantAnswerContentInCurrentTurn = info?.content || "";
12305
- stableAssistantAnswerCollapsedIndex = collapsed.length - 1;
12306
- stableAssistantAnswerHadInterveningActivity = false;
12307
- } else if (stableAssistantAnswerContentInCurrentTurn && info?.role === "assistant" && (!info.kind || info.kind !== "standard")) {
12308
- stableAssistantAnswerHadInterveningActivity = true;
12309
- }
12310
- }
12311
- return collapsed;
11441
+ return messages;
12312
11442
  }
12313
11443
  function deriveHistoryDedupKey(message) {
12314
11444
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -12333,127 +11463,12 @@ function toHistoryPersistedMessages(messages) {
12333
11463
  historyDedupKey: deriveHistoryDedupKey(message)
12334
11464
  }));
12335
11465
  }
12336
- function findLastMessageIndexBySignature(messages, signature) {
12337
- if (!signature) return -1;
12338
- for (let index = messages.length - 1; index >= 0; index -= 1) {
12339
- if (getChatMessageSignature(messages[index]) === signature) {
12340
- return index;
12341
- }
12342
- }
12343
- return -1;
12344
- }
12345
- function isReadChatConversationAnchorMessage(message) {
12346
- if (!message) return false;
12347
- const role = String(message.role || "").trim().toLowerCase();
12348
- if (role !== "user" && role !== "assistant") return false;
12349
- const kind = String(message.kind || "standard").trim().toLowerCase();
12350
- return !kind || kind === "standard";
12351
- }
12352
- function buildVisibleReadChatTailMessages(messages, tailLimit) {
11466
+ function buildFullTail(messages, tailLimit) {
12353
11467
  const totalMessages = messages.length;
12354
- if (tailLimit <= 0 || totalMessages <= tailLimit) return messages;
12355
- const tailMessages = messages.slice(-tailLimit);
12356
- if (tailMessages.some(isReadChatConversationAnchorMessage)) return tailMessages;
12357
- const hiddenMessages = messages.slice(0, totalMessages - tailLimit);
12358
- const anchors = [];
12359
- const seenRoles = /* @__PURE__ */ new Set();
12360
- for (let index = hiddenMessages.length - 1; index >= 0 && anchors.length < 2; index -= 1) {
12361
- const message = hiddenMessages[index];
12362
- if (!isReadChatConversationAnchorMessage(message)) continue;
12363
- const role = String(message.role || "").trim().toLowerCase();
12364
- if (seenRoles.has(role)) continue;
12365
- seenRoles.add(role);
12366
- anchors.unshift(message);
12367
- }
12368
- return anchors.length > 0 ? [...anchors, ...tailMessages] : tailMessages;
12369
- }
12370
- function buildBoundedTailSync(messages, cursor) {
12371
- const totalMessages = messages.length;
12372
- const tailMessages = buildVisibleReadChatTailMessages(messages, cursor.tailLimit);
11468
+ const tailMessages = tailLimit > 0 ? messages.slice(-tailLimit) : messages;
12373
11469
  return {
12374
- syncMode: "full",
12375
- replaceFrom: 0,
12376
11470
  messages: tailMessages,
12377
- totalMessages,
12378
- lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1])
12379
- };
12380
- }
12381
- function computeReadChatSync(messages, cursor) {
12382
- const totalMessages = messages.length;
12383
- const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
12384
- const { knownMessageCount, lastMessageSignature: knownSignature } = cursor;
12385
- if (!knownMessageCount || !knownSignature) {
12386
- return {
12387
- syncMode: "full",
12388
- replaceFrom: 0,
12389
- messages,
12390
- totalMessages,
12391
- lastMessageSignature
12392
- };
12393
- }
12394
- if (knownMessageCount > totalMessages) {
12395
- return {
12396
- syncMode: "full",
12397
- replaceFrom: 0,
12398
- messages,
12399
- totalMessages,
12400
- lastMessageSignature
12401
- };
12402
- }
12403
- if (knownMessageCount === totalMessages && knownSignature === lastMessageSignature) {
12404
- return {
12405
- syncMode: "noop",
12406
- replaceFrom: totalMessages,
12407
- messages: [],
12408
- totalMessages,
12409
- lastMessageSignature
12410
- };
12411
- }
12412
- if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
12413
- const requestedTailCount = Math.min(totalMessages, cursor.tailLimit);
12414
- if (knownMessageCount >= requestedTailCount) {
12415
- return {
12416
- syncMode: "noop",
12417
- replaceFrom: totalMessages,
12418
- messages: [],
12419
- totalMessages,
12420
- lastMessageSignature
12421
- };
12422
- }
12423
- return buildBoundedTailSync(messages, cursor);
12424
- }
12425
- if (knownMessageCount < totalMessages) {
12426
- const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
12427
- if (anchorSignature === knownSignature) {
12428
- return {
12429
- syncMode: "append",
12430
- replaceFrom: knownMessageCount,
12431
- messages: messages.slice(knownMessageCount),
12432
- totalMessages,
12433
- lastMessageSignature
12434
- };
12435
- }
12436
- if (cursor.tailLimit > 0) {
12437
- const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
12438
- if (signatureIndex >= 0) {
12439
- return {
12440
- syncMode: "append",
12441
- replaceFrom: knownMessageCount,
12442
- messages: messages.slice(signatureIndex + 1),
12443
- totalMessages,
12444
- lastMessageSignature
12445
- };
12446
- }
12447
- return buildBoundedTailSync(messages, cursor);
12448
- }
12449
- }
12450
- const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
12451
- return {
12452
- syncMode: replaceFrom === 0 ? "full" : "replace_tail",
12453
- replaceFrom,
12454
- messages: replaceFrom === 0 ? messages : messages.slice(replaceFrom),
12455
- totalMessages,
12456
- lastMessageSignature
11471
+ totalMessages
12457
11472
  };
12458
11473
  }
12459
11474
  function hasNonEmptyModalButtons(activeModal) {
@@ -12488,31 +11503,13 @@ function buildReadChatCommandResult(payload, args) {
12488
11503
  } catch (error) {
12489
11504
  return { success: false, error: error?.message || String(error) };
12490
11505
  }
12491
- const messages = collapseReplayDuplicatesFromReadChat(normalizeReadChatMessages(validatedPayload));
12492
- const cursor = normalizeReadChatCursor(args);
12493
- if (!cursor.knownMessageCount && !cursor.lastMessageSignature && cursor.tailLimit > 0 && messages.length > cursor.tailLimit) {
12494
- const tailMessages = buildVisibleReadChatTailMessages(messages, cursor.tailLimit);
12495
- const lastMessageSignature = getChatMessageSignature(messages[messages.length - 1]);
12496
- return {
12497
- success: true,
12498
- ...validatedPayload,
12499
- messages: tailMessages,
12500
- syncMode: "full",
12501
- replaceFrom: 0,
12502
- totalMessages: messages.length,
12503
- lastMessageSignature,
12504
- ...debugReadChat ? { debugReadChat } : {}
12505
- };
12506
- }
12507
- const sync = computeReadChatSync(messages, cursor);
11506
+ const messages = normalizeReadChatMessages(validatedPayload);
11507
+ const sync = buildFullTail(messages, normalizeReadChatTailLimit(args));
12508
11508
  return {
12509
11509
  success: true,
12510
11510
  ...validatedPayload,
12511
11511
  messages: sync.messages,
12512
- syncMode: sync.syncMode,
12513
- replaceFrom: sync.replaceFrom,
12514
11512
  totalMessages: sync.totalMessages,
12515
- lastMessageSignature: sync.lastMessageSignature,
12516
11513
  ...debugReadChat ? { debugReadChat } : {}
12517
11514
  };
12518
11515
  }
@@ -12737,10 +11734,6 @@ async function handleGetChatDebugBundle(h, args) {
12737
11734
  status: readResult.status,
12738
11735
  title: readResult.title,
12739
11736
  totalMessages: readResult.totalMessages,
12740
- returnedMessages: Array.isArray(readResult.messages) ? readResult.messages.length : void 0,
12741
- syncMode: readResult.syncMode,
12742
- replaceFrom: readResult.replaceFrom,
12743
- lastMessageSignature: readResult.lastMessageSignature,
12744
11737
  providerSessionId: readResult.providerSessionId,
12745
11738
  transcriptAuthority: readResult.transcriptAuthority,
12746
11739
  coverage: readResult.coverage,
@@ -12850,22 +11843,13 @@ function toNonNegativeNumber(value) {
12850
11843
  return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
12851
11844
  }
12852
11845
  function getCliVisibleTranscriptCount(adapter) {
12853
- const adapterStatus = adapter?.getStatus?.() || {};
12854
- const adapterMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
12855
- let parsedRecord = null;
12856
- if (typeof adapter?.getScriptParsedStatus === "function") {
12857
- try {
12858
- const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
12859
- parsedRecord = parsed && typeof parsed === "object" ? parsed : null;
12860
- } catch {
12861
- parsedRecord = null;
12862
- }
11846
+ if (typeof adapter?.getScriptParsedStatus !== "function") return 0;
11847
+ try {
11848
+ const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
11849
+ return Array.isArray(parsed?.messages) ? parsed.messages.length : 0;
11850
+ } catch {
11851
+ return 0;
12863
11852
  }
12864
- const parsedMessages = Array.isArray(parsedRecord?.messages) ? parsedRecord.messages : [];
12865
- if (!parsedRecord) return adapterMessages.length;
12866
- const parsedIsProviderAuthoritative = parsedRecord.transcriptAuthority === "provider" || parsedRecord.coverage === "full";
12867
- const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && adapterMessages.length > 0 && adapterMessages.length > parsedMessages.length;
12868
- return shouldPreferAdapterMessages ? adapterMessages.length : parsedMessages.length;
12869
11853
  }
12870
11854
  async function getStableExtensionBaseline(h) {
12871
11855
  const first = await readExtensionChatState(h);
@@ -12927,52 +11911,46 @@ async function handleReadChat(h, args) {
12927
11911
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
12928
11912
  if (adapter) {
12929
11913
  _log(`${transport} adapter: ${adapter.cliType}`);
11914
+ if (typeof adapter.getScriptParsedStatus !== "function") {
11915
+ return { success: false, error: `${transport} adapter parseSession unavailable` };
11916
+ }
12930
11917
  let parsedStatus = null;
12931
- if (typeof adapter.getScriptParsedStatus === "function") {
12932
- try {
12933
- parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
12934
- } catch (error) {
12935
- return { success: false, error: error?.message || String(error) };
12936
- }
11918
+ try {
11919
+ parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
11920
+ } catch (error) {
11921
+ return { success: false, error: error?.message || String(error) };
12937
11922
  }
12938
11923
  const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
12939
- const adapterStatus = adapter.getStatus();
12940
- const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.coverage === "full";
12941
- const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
12942
- const parsedShowsApproval = hasNonEmptyModalButtons(parsedRecord?.activeModal) && parsedRecord?.status === "waiting_approval";
12943
- const status = parsedRecord ? {
12944
- ...parsedRecord,
12945
- messages: shouldPreferAdapterMessages ? adapterStatus.messages : parsedRecord.messages,
12946
- status: parsedShowsApproval ? parsedRecord.status : adapterStatus.status !== "idle" ? adapterStatus.status : parsedRecord.status || adapterStatus.status,
12947
- activeModal: parsedRecord.activeModal || adapterStatus.activeModal
12948
- } : adapterStatus;
12949
- const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
12950
- const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
12951
- const transcriptAuthority = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
12952
- const coverage = parsedRecord?.coverage === "full" || parsedRecord?.coverage === "tail" || parsedRecord?.coverage === "current-turn" ? parsedRecord.coverage : void 0;
12953
- if (status) {
12954
- 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}`);
12955
- return buildReadChatCommandResult({
12956
- messages: status.messages || [],
12957
- status: status.status,
12958
- activeModal: status.activeModal,
12959
- debugReadChat: {
12960
- provider: adapter.cliType,
12961
- targetSessionId: String(args?.targetSessionId || ""),
12962
- adapterStatus: String(adapterStatus.status || ""),
12963
- parsedStatus: String(parsedRecord?.status || ""),
12964
- returnedStatus: String(status.status || ""),
12965
- shouldPreferAdapterMessages,
12966
- adapterMsgCount: Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0,
12967
- parsedMsgCount: Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0,
12968
- returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
12969
- },
12970
- ...title ? { title } : {},
12971
- ...providerSessionId ? { providerSessionId } : {},
12972
- ...transcriptAuthority ? { transcriptAuthority } : {},
12973
- ...coverage ? { coverage } : {}
12974
- }, args);
12975
- }
11924
+ if (!parsedRecord || !Array.isArray(parsedRecord.messages)) {
11925
+ return { success: false, error: `${transport} parser did not return messages` };
11926
+ }
11927
+ const adapterStatus = typeof adapter.getStatus === "function" ? adapter.getStatus() : {};
11928
+ const title = typeof parsedRecord.title === "string" ? parsedRecord.title : void 0;
11929
+ const providerSessionId = typeof parsedRecord.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
11930
+ const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
11931
+ const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
11932
+ const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
11933
+ const returnedStatus = parsedRecord.status || "idle";
11934
+ 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}`);
11935
+ return buildReadChatCommandResult({
11936
+ messages: parsedRecord.messages,
11937
+ status: returnedStatus,
11938
+ activeModal,
11939
+ debugReadChat: {
11940
+ provider: adapter.cliType,
11941
+ targetSessionId: String(args?.targetSessionId || ""),
11942
+ adapterStatus: String(adapterStatus.status || ""),
11943
+ parsedStatus: String(parsedRecord.status || ""),
11944
+ returnedStatus: String(returnedStatus || ""),
11945
+ shouldPreferAdapterMessages: false,
11946
+ parsedMsgCount: parsedRecord.messages.length,
11947
+ returnedMsgCount: parsedRecord.messages.length
11948
+ },
11949
+ ...title ? { title } : {},
11950
+ ...providerSessionId ? { providerSessionId } : {},
11951
+ ...transcriptAuthority ? { transcriptAuthority } : {},
11952
+ ...coverage ? { coverage } : {}
11953
+ }, args);
12976
11954
  }
12977
11955
  return { success: false, error: `${transport} adapter not found` };
12978
11956
  }
@@ -15276,7 +14254,6 @@ var path15 = __toESM(require("path"));
15276
14254
  var crypto3 = __toESM(require("crypto"));
15277
14255
  var fs6 = __toESM(require("fs"));
15278
14256
  var import_node_module = require("module");
15279
- init_contracts();
15280
14257
  init_provider_cli_adapter();
15281
14258
  init_logger();
15282
14259
 
@@ -15298,7 +14275,6 @@ function normalizeProviderSessionId(provider, providerSessionId) {
15298
14275
  }
15299
14276
 
15300
14277
  // src/providers/cli-provider-instance.ts
15301
- init_chat_message_normalization();
15302
14278
  function normalizePersistableCliHistoryContent(content) {
15303
14279
  return flattenContent(content).replace(/\s+/g, " ").trim();
15304
14280
  }
@@ -15538,17 +14514,11 @@ var CliProviderInstance = class {
15538
14514
  }
15539
14515
  const runtime = this.adapter.getRuntimeMetadata();
15540
14516
  this.maybeAppendRuntimeRecoveryMessage(runtime);
15541
- let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : parseErrorMessage ? normalizeChatMessages(Array.isArray(adapterStatus.messages) ? adapterStatus.messages : []) : [];
14517
+ let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
15542
14518
  const historyMessageCount = Number.isFinite(parsedStatus?.historyMessageCount) ? Math.max(0, Number(parsedStatus.historyMessageCount)) : null;
15543
14519
  if (historyMessageCount !== null) {
15544
14520
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
15545
14521
  }
15546
- const committedMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
15547
- const isActiveNonIdle = adapterStatus.status !== "idle";
15548
- const shouldApplyCommittedFloor = parsedMessages.length < committedMessages.length && (adapterStatus.status === "waiting_approval" || isActiveNonIdle && historyMessageCount === null);
15549
- if (shouldApplyCommittedFloor) {
15550
- parsedMessages = normalizeChatMessages(committedMessages);
15551
- }
15552
14522
  const mergedMessages = this.mergeConversationMessages(parsedMessages);
15553
14523
  const canonicalBackedHistory = this.syncCanonicalSavedHistoryIfNeeded();
15554
14524
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
@@ -15641,11 +14611,9 @@ var CliProviderInstance = class {
15641
14611
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
15642
14612
  const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
15643
14613
  const runtime = this.adapter.getRuntimeMetadata();
15644
- const lastCommittedMessageActivityAt = typeof this.adapter.getLastCommittedMessageActivityAt === "function" ? this.adapter.getLastCommittedMessageActivityAt() : 0;
15645
14614
  return {
15646
14615
  id: this.instanceId,
15647
14616
  status: visibleStatus,
15648
- lastMessageAt: lastCommittedMessageActivityAt || void 0,
15649
14617
  runtimeLifecycle: runtime?.lifecycle ?? null,
15650
14618
  runtimeSurfaceKind: runtime?.surfaceKind,
15651
14619
  runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
@@ -15751,7 +14719,7 @@ var CliProviderInstance = class {
15751
14719
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
15752
14720
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
15753
14721
  const partial = this.adapter.getPartialResponse();
15754
- const progressFingerprint = newStatus === "generating" ? `${partial || ""}::${adapterStatus.messages.at(-1)?.content || ""}`.slice(-2e3) : void 0;
14722
+ const progressFingerprint = newStatus === "generating" ? `${partial || ""}`.slice(-2e3) : void 0;
15755
14723
  const previousStatus = this.lastStatus;
15756
14724
  if (newStatus !== this.lastStatus) {
15757
14725
  LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
@@ -16197,18 +15165,6 @@ ${effect.notification.body || ""}`.trim();
16197
15165
  receivedAt: message.receivedAt
16198
15166
  }));
16199
15167
  this.suppressIdleHistoryReplay = restoredHistory.messages.length > 0;
16200
- if (restoredHistory.messages.length > 0) {
16201
- this.adapter.seedCommittedMessages(
16202
- restoredHistory.messages.map((message) => ({
16203
- role: message.role,
16204
- content: message.content,
16205
- timestamp: message.receivedAt,
16206
- receivedAt: message.receivedAt,
16207
- kind: message.kind,
16208
- senderName: message.senderName
16209
- }))
16210
- );
16211
- }
16212
15168
  }
16213
15169
  getProbeDirectories() {
16214
15170
  const dirs = /* @__PURE__ */ new Set();
@@ -16258,8 +15214,6 @@ ${effect.notification.body || ""}`.trim();
16258
15214
  var import_stream = require("stream");
16259
15215
  var import_child_process5 = require("child_process");
16260
15216
  var import_sdk = require("@agentclientprotocol/sdk");
16261
- init_contracts();
16262
- init_chat_message_normalization();
16263
15217
  init_logger();
16264
15218
  function getPromptCapabilityFlags(agentCapabilities) {
16265
15219
  const prompt = agentCapabilities?.promptCapabilities || {};
@@ -17403,7 +16357,6 @@ ${rawInput}` : rawInput;
17403
16357
  };
17404
16358
 
17405
16359
  // src/commands/cli-manager.ts
17406
- init_contracts();
17407
16360
  init_logger();
17408
16361
 
17409
16362
  // src/commands/hosted-runtime-restore.ts
@@ -20337,13 +19290,24 @@ async function launchWithCdp(options = {}) {
20337
19290
  break;
20338
19291
  }
20339
19292
  }
19293
+ if (!cdpReady) {
19294
+ return {
19295
+ success: false,
19296
+ ideId: targetIde.id,
19297
+ ideName: targetIde.displayName,
19298
+ port,
19299
+ action: "failed",
19300
+ message: "",
19301
+ error: `${targetIde.displayName} launched but CDP did not become available on port ${port}`
19302
+ };
19303
+ }
20340
19304
  return {
20341
19305
  success: true,
20342
19306
  ideId: targetIde.id,
20343
19307
  ideName: targetIde.displayName,
20344
19308
  port,
20345
19309
  action: alreadyRunning ? "restarted" : "started",
20346
- message: cdpReady ? `${targetIde.displayName} launched with CDP on port ${port}` : `${targetIde.displayName} launched (CDP may take a moment to initialize)`
19310
+ message: `${targetIde.displayName} launched with CDP on port ${port}`
20347
19311
  };
20348
19312
  } catch (e) {
20349
19313
  return {
@@ -22271,9 +21235,6 @@ var DEFAULT_DAEMON_PORT = 19222;
22271
21235
  var DAEMON_WS_PATH = "/ipc";
22272
21236
 
22273
21237
  // src/chat/subscription-updates.ts
22274
- function normalizeSyncMode(syncMode) {
22275
- return syncMode === "append" || syncMode === "replace_tail" || syncMode === "noop" || syncMode === "full" ? syncMode : "full";
22276
- }
22277
21238
  function normalizeModalButtons(value) {
22278
21239
  return Array.isArray(value) ? value.filter((button) => typeof button === "string") : [];
22279
21240
  }
@@ -22300,55 +21261,39 @@ function normalizeSessionModalFields(activeModal) {
22300
21261
  modalButtons: normalizeModalButtons(activeModal.buttons)
22301
21262
  };
22302
21263
  }
22303
- function buildNextChatCursor(cursor, result) {
22304
- return {
22305
- knownMessageCount: Math.max(0, Number(result.totalMessages || cursor.knownMessageCount)),
22306
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : cursor.lastMessageSignature,
22307
- tailLimit: cursor.tailLimit
22308
- };
22309
- }
22310
21264
  function prepareSessionChatTailUpdate(input) {
22311
21265
  const result = input.result;
22312
- if (!result?.success || result.syncMode === "noop") {
21266
+ if (!result?.success) {
22313
21267
  return {
22314
- cursor: result?.success ? buildNextChatCursor(input.cursor, result) : input.cursor,
21268
+ cursor: input.cursor,
22315
21269
  seq: input.seq,
22316
21270
  lastDeliveredSignature: input.lastDeliveredSignature,
22317
21271
  update: null
22318
21272
  };
22319
21273
  }
22320
- const syncMode = normalizeSyncMode(result.syncMode);
22321
- const cursor = {
22322
- knownMessageCount: Math.max(0, Number(result.totalMessages || 0)),
22323
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : "",
22324
- tailLimit: input.cursor.tailLimit
22325
- };
21274
+ const messages = Array.isArray(result.messages) ? result.messages : [];
22326
21275
  const title = typeof result.title === "string" ? result.title : void 0;
22327
21276
  const activeModal = normalizeChatTailActiveModal(result.activeModal);
22328
21277
  const status = typeof result.status === "string" ? result.status : "idle";
22329
21278
  const deliverySignature = buildChatTailDeliverySignature({
22330
21279
  sessionId: input.sessionId,
22331
21280
  ...input.historySessionId ? { historySessionId: input.historySessionId } : {},
22332
- messages: Array.isArray(result.messages) ? result.messages : [],
21281
+ messages,
22333
21282
  status,
22334
21283
  ...title ? { title } : {},
22335
- ...activeModal ? { activeModal } : {},
22336
- syncMode,
22337
- replaceFrom: Number(result.replaceFrom || 0),
22338
- totalMessages: Number(result.totalMessages || 0),
22339
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
21284
+ ...activeModal ? { activeModal } : {}
22340
21285
  });
22341
21286
  const seq = input.seq + 1;
22342
21287
  if (deliverySignature === input.lastDeliveredSignature) {
22343
21288
  return {
22344
- cursor,
21289
+ cursor: input.cursor,
22345
21290
  seq,
22346
21291
  lastDeliveredSignature: input.lastDeliveredSignature,
22347
21292
  update: null
22348
21293
  };
22349
21294
  }
22350
21295
  return {
22351
- cursor,
21296
+ cursor: input.cursor,
22352
21297
  seq,
22353
21298
  lastDeliveredSignature: deliverySignature,
22354
21299
  update: {
@@ -22359,14 +21304,10 @@ function prepareSessionChatTailUpdate(input) {
22359
21304
  ...input.interactionId ? { interactionId: input.interactionId } : {},
22360
21305
  seq,
22361
21306
  timestamp: input.timestamp,
22362
- messages: Array.isArray(result.messages) ? result.messages : [],
21307
+ messages,
22363
21308
  status,
22364
21309
  ...title ? { title } : {},
22365
- ...activeModal ? { activeModal } : {},
22366
- syncMode,
22367
- replaceFrom: Number(result.replaceFrom || 0),
22368
- totalMessages: Number(result.totalMessages || 0),
22369
- lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
21310
+ ...activeModal ? { activeModal } : {}
22370
21311
  }
22371
21312
  };
22372
21313
  }
@@ -22426,8 +21367,6 @@ async function runAsyncBatch(items, worker, options = {}) {
22426
21367
  }
22427
21368
 
22428
21369
  // src/agent-stream/provider-adapter.ts
22429
- init_read_chat_contract();
22430
- init_chat_message_normalization();
22431
21370
  var ProviderStreamAdapter = class {
22432
21371
  agentType;
22433
21372
  agentName;
@@ -23112,7 +22051,6 @@ var DaemonAgentStreamManager = class {
23112
22051
 
23113
22052
  // src/agent-stream/poller.ts
23114
22053
  init_logger();
23115
- init_chat_message_normalization();
23116
22054
  var AgentStreamPoller = class {
23117
22055
  deps;
23118
22056
  timer = null;
@@ -23591,10 +22529,6 @@ var ProviderInstanceManager = class {
23591
22529
  }
23592
22530
  };
23593
22531
 
23594
- // src/index.ts
23595
- init_io_contracts();
23596
- init_chat_message_normalization();
23597
-
23598
22532
  // src/providers/version-archive.ts
23599
22533
  var fs11 = __toESM(require("fs"));
23600
22534
  var path21 = __toESM(require("path"));
@@ -27032,7 +25966,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
27032
25966
  lines.push("Provider category: `cli`");
27033
25967
  lines.push("");
27034
25968
  const funcToFile = {
27035
- parseOutput: "parse_output.js",
25969
+ parseSession: "parse_session.js",
27036
25970
  detectStatus: "detect_status.js",
27037
25971
  parseApproval: "parse_approval.js"
27038
25972
  };
@@ -27121,7 +26055,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
27121
26055
  lines.push("");
27122
26056
  lines.push("| Function | Input | Return |");
27123
26057
  lines.push("|---|---|---|");
27124
- lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
26058
+ lines.push("| `parseSession` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
27125
26059
  lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
27126
26060
  lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
27127
26061
  lines.push("");
@@ -27341,7 +26275,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
27341
26275
  lines.push("");
27342
26276
  lines.push("## Required Validation");
27343
26277
  lines.push("1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.");
27344
- lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
26278
+ lines.push("2. Confirm `parseSession` produces a stable transcript without duplicating past turns when the PTY redraws.");
27345
26279
  lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
27346
26280
  lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
27347
26281
  lines.push("5. Confirm the Python file was actually created and executed, not just described in chat text.");
@@ -28611,7 +27545,7 @@ var DevServer = class _DevServer {
28611
27545
  lines.push("Provider category: `cli`");
28612
27546
  lines.push("");
28613
27547
  const funcToFile = {
28614
- parseOutput: "parse_output.js",
27548
+ parseSession: "parse_session.js",
28615
27549
  detectStatus: "detect_status.js",
28616
27550
  parseApproval: "parse_approval.js"
28617
27551
  };
@@ -28700,7 +27634,7 @@ var DevServer = class _DevServer {
28700
27634
  lines.push("");
28701
27635
  lines.push("| Function | Input | Return |");
28702
27636
  lines.push("|---|---|---|");
28703
- lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
27637
+ lines.push("| `parseSession` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
28704
27638
  lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
28705
27639
  lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
28706
27640
  lines.push("");
@@ -28795,7 +27729,7 @@ var DevServer = class _DevServer {
28795
27729
  lines.push("");
28796
27730
  lines.push("## Required Validation");
28797
27731
  lines.push("1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.");
28798
- lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
27732
+ lines.push("2. Confirm `parseSession` produces a stable transcript without duplicating past turns when the PTY redraws.");
28799
27733
  lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
28800
27734
  lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
28801
27735
  lines.push("5. Confirm the Python file was actually created and executed, not just described in chat text.");