tarsk 0.5.77 → 0.5.78

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 (152) hide show
  1. package/dist/index.js +704 -143
  2. package/dist/public/assets/account-view-Bzv2EHnc.js +1 -0
  3. package/dist/public/assets/api-OO3KSG8d.js +2 -0
  4. package/dist/public/assets/{async-error-boundary-p7xL6pqw.js → async-error-boundary-Dll_zcqr.js} +1 -1
  5. package/dist/public/assets/browser-tab-Cwa1TB3I.js +12 -0
  6. package/dist/public/assets/button-B5aMz2Rk.js +1 -0
  7. package/dist/public/assets/card-DRr14MEQ.js +1 -0
  8. package/dist/public/assets/chat-dock-context-Cnq0BWgm.js +1 -0
  9. package/dist/public/assets/commit-dialog-C-JfaoS6.js +1 -0
  10. package/dist/public/assets/commit-error-dialog-VXqZLeta.js +1 -0
  11. package/dist/public/assets/commit-method-fields-DAd1unUF.js +1 -0
  12. package/dist/public/assets/context-menu-BKOotkeD.js +1 -0
  13. package/dist/public/assets/conversation-history-view-CcdQRxoP.js +1 -0
  14. package/dist/public/assets/{create-project-dialog-fc3B-dqb.js → create-project-dialog-D1VaSgqh.js} +2 -2
  15. package/dist/public/assets/create-repo-dialog-mBGGkX-g.js +1 -0
  16. package/dist/public/assets/delete-confirm-dialog-Cx9nT7Xd.js +1 -0
  17. package/dist/public/assets/diff-view-CyOnLSEA.js +4 -0
  18. package/dist/public/assets/{dist-bBjaCw3d.js → dist-COfI64N5.js} +1 -1
  19. package/dist/public/assets/dist-CWYnBq-n.js +1 -0
  20. package/dist/public/assets/dist-DDYi9MQo.js +1 -0
  21. package/dist/public/assets/dist-DNkA3vYh.js +2 -0
  22. package/dist/public/assets/dist-DwblUvSf.js +1 -0
  23. package/dist/public/assets/dist-T8-4ZfS0.js +1 -0
  24. package/dist/public/assets/dist-TCNzmc2V.js +5 -0
  25. package/dist/public/assets/dist-sThe8WYP.js +1 -0
  26. package/dist/public/assets/es2015-Bu0NIPbn.js +41 -0
  27. package/dist/public/assets/{explorer-monaco-editor-DuU68YH9.js → explorer-monaco-editor-q8CnSwWA.js} +1 -1
  28. package/dist/public/assets/explorer-tab-view-G2HmkQyY.js +2 -0
  29. package/dist/public/assets/explorer-tree-DAuc2Npx.js +1 -0
  30. package/dist/public/assets/explorer-view-BDMlnV3f.js +76 -0
  31. package/dist/public/assets/git-history-dialog-XEr5pugf.js +1 -0
  32. package/dist/public/assets/index-C4WzOmf3.css +1 -0
  33. package/dist/public/assets/index-DD_a7tQU.js +3665 -0
  34. package/dist/public/assets/lucide-react-B-115rul.js +1 -0
  35. package/dist/public/assets/main-tab-context-CNgxXqnH.js +1 -0
  36. package/dist/public/assets/model-list-controls-DAZM0NBC.js +1 -0
  37. package/dist/public/assets/onboarding-dialog-Dd9hiOOf.js +1 -0
  38. package/dist/public/assets/pill-tabs-QsjH027B.js +1 -0
  39. package/dist/public/assets/progress-indicator-C01aPXIe.js +1 -0
  40. package/dist/public/assets/project-coding-view-DbKI7sbW.js +1 -0
  41. package/dist/public/assets/project-danger-zone-view-BaSu793w.js +1 -0
  42. package/dist/public/assets/project-env-vars-view-BB66j52E.js +1 -0
  43. package/dist/public/assets/project-model-aliases-view-o1-Z2es5.js +1 -0
  44. package/dist/public/assets/project-settings-view-BKjvtOtk.js +1 -0
  45. package/dist/public/assets/project-tools-view-CZbblznF.js +1 -0
  46. package/dist/public/assets/providers-list-view-ChY2DXYc.js +1 -0
  47. package/dist/public/assets/pull-request-dialog-BZgY4vrw.js +1 -0
  48. package/dist/public/assets/pull-with-changes-dialog-DDp_srHq.js +1 -0
  49. package/dist/public/assets/{push-before-pr-dialog-CxboQlmj.js → push-before-pr-dialog-Bt0BChlV.js} +1 -1
  50. package/dist/public/assets/scroll-area-DwRwR2nQ.js +1 -0
  51. package/dist/public/assets/settings-general-tabs-view-BH7AaXyP.js +2 -0
  52. package/dist/public/assets/settings-general-view-B-t99LmD.js +1 -0
  53. package/dist/public/assets/settings-list-Dn4CHP4Z.js +1 -0
  54. package/dist/public/assets/{settings-logs-view-BiY8r9HI.js → settings-logs-view-BCRjz-Fr.js} +3 -3
  55. package/dist/public/assets/settings-mcp-servers-view-xv9D4DPO.js +5 -0
  56. package/dist/public/assets/settings-models-view-rUeqlE4k.js +1 -0
  57. package/dist/public/assets/settings-plugins-view-qnWmII61.js +2 -0
  58. package/dist/public/assets/settings-providers-view-DsxTdBEQ.js +2 -0
  59. package/dist/public/assets/settings-setup-view-ew5KW8gL.js +2 -0
  60. package/dist/public/assets/settings-skills-view-C4NxP4gI.js +3 -0
  61. package/dist/public/assets/settings-slack-view-BNT5ervf.js +1 -0
  62. package/dist/public/assets/settings-slash-commands-view-CE7FT3dB.js +1 -0
  63. package/dist/public/assets/settings-statistics-view-jKPoSWBs.js +1 -0
  64. package/dist/public/assets/settings-storage-view-C_Rs-9Hw.js +1 -0
  65. package/dist/public/assets/settings-subagents-view-DHVSAmCY.js +2 -0
  66. package/dist/public/assets/settings-system-prompt-view-B_nF2HUy.js +1 -0
  67. package/dist/public/assets/settings-tab-bar-DAHxT5KE.js +1 -0
  68. package/dist/public/assets/settings-view-BY6OO-xy.js +2 -0
  69. package/dist/public/assets/slug-utils-BQZ6c2py.js +1 -0
  70. package/dist/public/assets/store-B7EgrEO7.js +9 -0
  71. package/dist/public/assets/suspense-resource-DzlMlIgR.js +1 -0
  72. package/dist/public/assets/table-7hMwxpkF.js +1 -0
  73. package/dist/public/assets/tasks-view-Dc7sthjm.js +1 -0
  74. package/dist/public/assets/terminal-output-activity-B1bjjsl7.js +1 -0
  75. package/dist/public/assets/terminal-panel-BNOIOh8z.js +38 -0
  76. package/dist/public/assets/toggle-group-UiksQ0n9.js +1 -0
  77. package/dist/public/assets/tooltip-Dvmz78Z_.js +1 -0
  78. package/dist/public/assets/{use-active-dock-panel-instance-DjhNdiNZ.js → use-active-dock-panel-instance-2LfvItRH.js} +1 -1
  79. package/dist/public/assets/use-installed-ai-files-BkpswqGI.js +1 -0
  80. package/dist/public/assets/{useBaseQuery-BytIT4Si.js → useBaseQuery-D5as4SgS.js} +1 -1
  81. package/dist/public/assets/utils-B-qS8qMg.js +1 -0
  82. package/dist/public/assets/{web-HPHkrB3q.js → web-B9ndApmi.js} +1 -1
  83. package/dist/public/assets/{web-CWmUhqaq.js → web-BkuMY08B.js} +1 -1
  84. package/dist/public/assets/{web-C28hpsuV.js → web-DyqJbQ3L.js} +1 -1
  85. package/dist/public/assets/{web-BogjYrUi.js → web-gEWIDddb.js} +1 -1
  86. package/dist/public/index.html +24 -22
  87. package/package.json +1 -1
  88. package/dist/public/assets/account-view-DqN6PuZx.js +0 -1
  89. package/dist/public/assets/api-BEi04Nbw.js +0 -2
  90. package/dist/public/assets/async-loading-fallback-cCtsF_26.js +0 -1
  91. package/dist/public/assets/browser-tab-D8O7Fv9w.js +0 -12
  92. package/dist/public/assets/button-D1ArHt_o.js +0 -1
  93. package/dist/public/assets/card-Bp7fZl_f.js +0 -1
  94. package/dist/public/assets/chat-dock-context-BlxEXa9b.js +0 -1
  95. package/dist/public/assets/commit-dialog-DY4D8-I1.js +0 -1
  96. package/dist/public/assets/commit-error-dialog-DBXZAW1l.js +0 -1
  97. package/dist/public/assets/commit-method-fields-C335Y5Id.js +0 -1
  98. package/dist/public/assets/context-menu-BUjcm0iJ.js +0 -1
  99. package/dist/public/assets/conversation-history-view-DQ_PXqZ9.js +0 -1
  100. package/dist/public/assets/create-repo-dialog-DchKq-aa.js +0 -1
  101. package/dist/public/assets/delete-confirm-dialog-DEuqA4Wk.js +0 -1
  102. package/dist/public/assets/diff-view-CVlpWjUp.js +0 -4
  103. package/dist/public/assets/dist-BGVtJOIV.js +0 -2
  104. package/dist/public/assets/dist-BQOHvuU5.js +0 -1
  105. package/dist/public/assets/dist-BrrQ4RKZ.js +0 -1
  106. package/dist/public/assets/dist-CRRMWh4A.js +0 -5
  107. package/dist/public/assets/dist-DLuGyArC.js +0 -1
  108. package/dist/public/assets/dist-DSd8c-dh.js +0 -1
  109. package/dist/public/assets/dist-DTleMiQ4.js +0 -1
  110. package/dist/public/assets/dist-sGpOBecq.js +0 -1
  111. package/dist/public/assets/es2015-SVM3tAoD.js +0 -41
  112. package/dist/public/assets/explorer-tab-view-CHQ0mxMq.js +0 -2
  113. package/dist/public/assets/explorer-tree-BHqNnEtP.js +0 -1
  114. package/dist/public/assets/explorer-view-CgdDN1D-.js +0 -76
  115. package/dist/public/assets/git-history-dialog-BAWqdcQy.js +0 -1
  116. package/dist/public/assets/index-BHXl-V4W.js +0 -3665
  117. package/dist/public/assets/index-CLo6-Tya.css +0 -1
  118. package/dist/public/assets/main-tab-context-Byl1LybL.js +0 -1
  119. package/dist/public/assets/model-list-controls-BTd-p6XD.js +0 -1
  120. package/dist/public/assets/onboarding-dialog-DXg4wTyD.js +0 -1
  121. package/dist/public/assets/project-coding-view-R1jPpXkA.js +0 -1
  122. package/dist/public/assets/project-danger-zone-view-B8gSJxHw.js +0 -1
  123. package/dist/public/assets/project-env-vars-view-CHfsOYa_.js +0 -1
  124. package/dist/public/assets/project-model-aliases-view-DnEbS87g.js +0 -1
  125. package/dist/public/assets/project-settings-view-34BqFxN-.js +0 -1
  126. package/dist/public/assets/project-tools-view-DCBhdS_I.js +0 -1
  127. package/dist/public/assets/providers-list-view-m6xHKltt.js +0 -1
  128. package/dist/public/assets/pull-request-dialog-Bmtin2Mh.js +0 -1
  129. package/dist/public/assets/pull-with-changes-dialog-Cmh1vFmo.js +0 -1
  130. package/dist/public/assets/radio-group-DzcDTzWb.js +0 -1
  131. package/dist/public/assets/scroll-area-DgahW31C.js +0 -1
  132. package/dist/public/assets/settings-general-view-XHYGeoAk.js +0 -1
  133. package/dist/public/assets/settings-list-D-51AyVy.js +0 -1
  134. package/dist/public/assets/settings-mcp-servers-view-DEmqI7is.js +0 -5
  135. package/dist/public/assets/settings-models-view-CB6htSan.js +0 -1
  136. package/dist/public/assets/settings-skills-view-QL-AL_vP.js +0 -3
  137. package/dist/public/assets/settings-slack-view-Bo1oDUFr.js +0 -1
  138. package/dist/public/assets/settings-slash-commands-view-CUY_SkzD.js +0 -1
  139. package/dist/public/assets/settings-statistics-view-B1iibWb7.js +0 -1
  140. package/dist/public/assets/settings-storage-view-BClnyDai.js +0 -1
  141. package/dist/public/assets/settings-subagents-view-D4OEJJk8.js +0 -2
  142. package/dist/public/assets/settings-system-prompt-view-e6CgLFVs.js +0 -1
  143. package/dist/public/assets/settings-view-Bk-knKOJ.js +0 -2
  144. package/dist/public/assets/slug-utils-DgUDtDRP.js +0 -1
  145. package/dist/public/assets/store-IJouqtOd.js +0 -9
  146. package/dist/public/assets/suspense-resource-BFrb_XJX.js +0 -1
  147. package/dist/public/assets/table-CYtkHxHy.js +0 -1
  148. package/dist/public/assets/tasks-view-DpGp9_WH.js +0 -1
  149. package/dist/public/assets/terminal-panel-OW4yyorA.js +0 -38
  150. package/dist/public/assets/toggle-group-rSptomuG.js +0 -1
  151. package/dist/public/assets/tooltip-BqGy0Y1-.js +0 -1
  152. package/dist/public/assets/use-installed-ai-files-BcrX9Nna.js +0 -1
package/dist/index.js CHANGED
@@ -880,6 +880,110 @@ var init_observations = __esm({
880
880
  }
881
881
  });
882
882
 
883
+ // ../shared/dist/grep-limits.js
884
+ function clampGrepContextLines(value2) {
885
+ if (value2 === void 0) {
886
+ return void 0;
887
+ }
888
+ if (!Number.isFinite(value2)) {
889
+ return 0;
890
+ }
891
+ return Math.max(0, Math.min(MAX_GREP_CONTENT_CONTEXT, Math.trunc(value2)));
892
+ }
893
+ function grepContextWidth(before, after) {
894
+ return Math.max(1, before + after + 1);
895
+ }
896
+ function scaleGrepHeadLimitForContext(requested, contextWidth) {
897
+ if (contextWidth <= 1) {
898
+ return requested;
899
+ }
900
+ const scaled = Math.ceil(requested / contextWidth);
901
+ return Math.max(contextWidth, scaled);
902
+ }
903
+ function isContentMode(mode) {
904
+ return mode === void 0 || mode === "content";
905
+ }
906
+ function contextWasClamped(requested, clamped) {
907
+ if (requested === void 0 || clamped === void 0) {
908
+ return false;
909
+ }
910
+ return requested !== clamped;
911
+ }
912
+ function resolveGrepContentBudget(input2) {
913
+ if (!isContentMode(input2.output_mode)) {
914
+ return {
915
+ contextWidth: 1,
916
+ contextClamped: false,
917
+ headLimit: input2.head_limit,
918
+ headLimitScaled: false
919
+ };
920
+ }
921
+ const context2 = clampGrepContextLines(input2.context);
922
+ const contextC = clampGrepContextLines(input2["-C"]);
923
+ const contextBefore = clampGrepContextLines(input2["-B"]);
924
+ const contextAfter = clampGrepContextLines(input2["-A"]);
925
+ const contextClamped = contextWasClamped(input2.context, context2) || contextWasClamped(input2["-C"], contextC) || contextWasClamped(input2["-B"], contextBefore) || contextWasClamped(input2["-A"], contextAfter);
926
+ let before = 0;
927
+ let after = 0;
928
+ if (context2 !== void 0) {
929
+ before = context2;
930
+ after = context2;
931
+ } else if (contextC !== void 0) {
932
+ before = contextC;
933
+ after = contextC;
934
+ } else {
935
+ before = contextBefore ?? 0;
936
+ after = contextAfter ?? 0;
937
+ }
938
+ const contextWidth = grepContextWidth(before, after);
939
+ if (contextWidth <= 1) {
940
+ return {
941
+ context: context2,
942
+ contextC,
943
+ contextBefore,
944
+ contextAfter,
945
+ contextWidth: 1,
946
+ contextClamped,
947
+ headLimit: input2.head_limit,
948
+ headLimitScaled: false
949
+ };
950
+ }
951
+ const requested = input2.head_limit === void 0 || input2.head_limit === 0 ? DEFAULT_GREP_HEAD_LIMIT : input2.head_limit;
952
+ const headLimit = scaleGrepHeadLimitForContext(requested, contextWidth);
953
+ return {
954
+ context: context2,
955
+ contextC,
956
+ contextBefore,
957
+ contextAfter,
958
+ contextWidth,
959
+ contextClamped,
960
+ headLimit,
961
+ headLimitScaled: headLimit !== input2.head_limit
962
+ };
963
+ }
964
+ function formatGrepContextBudgetNotice(budget) {
965
+ const parts = [];
966
+ if (budget.contextClamped) {
967
+ parts.push(`Context limited to ${MAX_GREP_CONTENT_CONTEXT} lines per side.`);
968
+ }
969
+ if (budget.headLimitScaled && budget.headLimit) {
970
+ parts.push(`Output line budget scaled to ${budget.headLimit}.`);
971
+ }
972
+ if (parts.length === 0) {
973
+ return "";
974
+ }
975
+ return `[${parts.join(" ")}]`;
976
+ }
977
+ var DEFAULT_GREP_HEAD_LIMIT, DEFAULT_GREP_CONTENT_CONTEXT, MAX_GREP_CONTENT_CONTEXT;
978
+ var init_grep_limits = __esm({
979
+ "../shared/dist/grep-limits.js"() {
980
+ "use strict";
981
+ DEFAULT_GREP_HEAD_LIMIT = 40;
982
+ DEFAULT_GREP_CONTENT_CONTEXT = 0;
983
+ MAX_GREP_CONTENT_CONTEXT = 2;
984
+ }
985
+ });
986
+
883
987
  // ../shared/dist/selection.js
884
988
  function areResultSelectionsEnabled() {
885
989
  return process.env[RESULT_SELECTION_ENV_FLAG] !== "false";
@@ -950,7 +1054,7 @@ function isPromptCacheUnavailable(cacheHitRate) {
950
1054
  function isMicrocompactEligibleTool(toolName2) {
951
1055
  return MICROCOMPACT_ELIGIBLE_TOOL_SET.has(toolName2);
952
1056
  }
953
- var MICROCOMPACT_KEEP_RECENT, MICROCOMPACT_KEEP_TOKENS, MICROCOMPACT_TRIGGER_MARGIN, MICROCOMPACT_MIN_SAVE_TOKENS, MICROCOMPACT_DIGEST_MIN_CHARS, MICROCOMPACT_NO_CACHE_DIGEST_MIN_CHARS, MICROCOMPACT_SHORT_STUB_MAX_CHARS, MICROCOMPACT_PROACTIVE_TURN_THRESHOLD, MICROCOMPACT_PROACTIVE_PAYLOAD_TOKENS, MICROCOMPACT_PROACTIVE_MIN_SAVE_TOKENS, MICROCOMPACT_PROACTIVE_KEEP_TOKENS, MICROCOMPACT_NO_CACHE_KEEP_TOKENS, MICROCOMPACT_OVERFLOW_KEEP_RECENT, MICROCOMPACT_OVERFLOW_KEEP_TOKENS, MICROCOMPACT_OVERFLOW_MIN_SAVE_TOKENS, MICROCOMPACT_OVERFLOW_DIGEST_MIN_CHARS, MICROCOMPACT_NO_CACHE_HIT_RATE_THRESHOLD, MICROCOMPACT_NO_CACHE_AGGRESSION_FACTOR, MICROCOMPACT_MARKER_PREFIX, SUPERSESSION_MARKER_PREFIX, MICROCOMPACT_ELIGIBLE_TOOLS, MICROCOMPACT_ELIGIBLE_TOOL_SET;
1057
+ var MICROCOMPACT_KEEP_RECENT, MICROCOMPACT_KEEP_TOKENS, MICROCOMPACT_TRIGGER_MARGIN, MICROCOMPACT_MIN_SAVE_TOKENS, MICROCOMPACT_DIGEST_MIN_CHARS, MICROCOMPACT_NO_CACHE_DIGEST_MIN_CHARS, MICROCOMPACT_SHORT_STUB_MAX_CHARS, MICROCOMPACT_PROACTIVE_TURN_THRESHOLD, MICROCOMPACT_PROACTIVE_PAYLOAD_TOKENS, MICROCOMPACT_CACHE_RECLAIM_PAYLOAD_TOKENS, MICROCOMPACT_CACHE_RECLAIM_MESSAGE_COUNT, MICROCOMPACT_PROACTIVE_MIN_SAVE_TOKENS, MICROCOMPACT_PROACTIVE_KEEP_TOKENS, MICROCOMPACT_NO_CACHE_KEEP_TOKENS, MICROCOMPACT_OVERFLOW_KEEP_RECENT, MICROCOMPACT_OVERFLOW_KEEP_TOKENS, MICROCOMPACT_OVERFLOW_MIN_SAVE_TOKENS, MICROCOMPACT_OVERFLOW_DIGEST_MIN_CHARS, MICROCOMPACT_NO_CACHE_HIT_RATE_THRESHOLD, MICROCOMPACT_NO_CACHE_AGGRESSION_FACTOR, MICROCOMPACT_MARKER_PREFIX, SUPERSESSION_MARKER_PREFIX, MICROCOMPACT_ELIGIBLE_TOOLS, MICROCOMPACT_ELIGIBLE_TOOL_SET;
954
1058
  var init_microcompact = __esm({
955
1059
  "../shared/dist/microcompact.js"() {
956
1060
  "use strict";
@@ -963,6 +1067,8 @@ var init_microcompact = __esm({
963
1067
  MICROCOMPACT_SHORT_STUB_MAX_CHARS = 2048;
964
1068
  MICROCOMPACT_PROACTIVE_TURN_THRESHOLD = 15;
965
1069
  MICROCOMPACT_PROACTIVE_PAYLOAD_TOKENS = 5e4;
1070
+ MICROCOMPACT_CACHE_RECLAIM_PAYLOAD_TOKENS = 8e4;
1071
+ MICROCOMPACT_CACHE_RECLAIM_MESSAGE_COUNT = 80;
966
1072
  MICROCOMPACT_PROACTIVE_MIN_SAVE_TOKENS = 5e3;
967
1073
  MICROCOMPACT_PROACTIVE_KEEP_TOKENS = 1e4;
968
1074
  MICROCOMPACT_NO_CACHE_KEEP_TOKENS = 2e3;
@@ -1010,6 +1116,13 @@ var init_processing_similes = __esm({
1010
1116
  }
1011
1117
  });
1012
1118
 
1119
+ // ../shared/dist/processing-polling.js
1120
+ var init_processing_polling = __esm({
1121
+ "../shared/dist/processing-polling.js"() {
1122
+ "use strict";
1123
+ }
1124
+ });
1125
+
1013
1126
  // ../shared/dist/context-rollover.js
1014
1127
  var CONTEXT_ROLLOVER_MARKER, CONTEXT_ROLLOVER_NOTICE, CONTEXT_ROLLOVER_MAX_HANDOFF_CHARS, CONTEXT_ROLLOVER_MAX_NOTE_CHARS, CONTEXT_ROLLOVER_MAX_TODO_CHARS, CONTEXT_ROLLOVER_MAX_RECENT_MESSAGE_CHARS, CONTEXT_ROLLOVER_MAX_REPOSITORY_STATE_CHARS, CONTEXT_ROLLOVER_MAX_CHANGE_DIGEST_CHARS, CONTEXT_ROLLOVER_MAX_HUNKS_PER_FILE, CONTEXT_HISTORY_PAGE_CHARS, CONTEXT_HISTORY_SEARCH_LIMIT, CONTEXT_HISTORY_SEARCH_EXCERPT_CHARS, CONTEXT_NOTE_NAME_MAX_CHARS, CONTEXT_NOTE_CONTENT_MAX_CHARS, CONTEXT_NOTE_PAGE_CHARS, CONTEXT_NOTE_SEARCH_EXCERPT_CHARS, CONTEXT_MEMORY_INSTRUCTIONS;
1015
1128
  var init_context_rollover = __esm({
@@ -2430,6 +2543,34 @@ var init_providers = __esm({
2430
2543
  }
2431
2544
  });
2432
2545
 
2546
+ // ../shared/dist/provider-settings.js
2547
+ var init_provider_settings = __esm({
2548
+ "../shared/dist/provider-settings.js"() {
2549
+ "use strict";
2550
+ }
2551
+ });
2552
+
2553
+ // ../shared/dist/general-settings.js
2554
+ var init_general_settings = __esm({
2555
+ "../shared/dist/general-settings.js"() {
2556
+ "use strict";
2557
+ }
2558
+ });
2559
+
2560
+ // ../shared/dist/plugin-settings.js
2561
+ var init_plugin_settings = __esm({
2562
+ "../shared/dist/plugin-settings.js"() {
2563
+ "use strict";
2564
+ }
2565
+ });
2566
+
2567
+ // ../shared/dist/setup-settings.js
2568
+ var init_setup_settings = __esm({
2569
+ "../shared/dist/setup-settings.js"() {
2570
+ "use strict";
2571
+ }
2572
+ });
2573
+
2433
2574
  // ../shared/dist/web-fetch.js
2434
2575
  function normalizeFetchHostname(hostname4) {
2435
2576
  const lower2 = hostname4.toLowerCase();
@@ -13414,10 +13555,12 @@ var init_dist = __esm({
13414
13555
  init_assistant_summary();
13415
13556
  init_conversation_title();
13416
13557
  init_observations();
13558
+ init_grep_limits();
13417
13559
  init_selection();
13418
13560
  init_user_message();
13419
13561
  init_microcompact();
13420
13562
  init_processing_similes();
13563
+ init_processing_polling();
13421
13564
  init_system_prompt();
13422
13565
  init_context_rollover();
13423
13566
  init_image_payload();
@@ -13433,6 +13576,10 @@ var init_dist = __esm({
13433
13576
  init_smart_js_plan();
13434
13577
  init_smart_js_results();
13435
13578
  init_providers();
13579
+ init_provider_settings();
13580
+ init_general_settings();
13581
+ init_plugin_settings();
13582
+ init_setup_settings();
13436
13583
  init_web_fetch();
13437
13584
  init_permission_messages();
13438
13585
  init_explorer_media();
@@ -57557,6 +57704,13 @@ function isProactiveMicrocompactTrigger(messages, options2) {
57557
57704
  const tokensBefore = sumMessageTokens(messages) + config3.fixedOverheadTokens;
57558
57705
  return countAssistantTurns(messages) >= config3.proactiveTurnThreshold || tokensBefore >= config3.proactivePayloadTokens;
57559
57706
  }
57707
+ function isCacheReclaimTrigger(messages, config3, cacheHitRate) {
57708
+ if (isPromptCacheUnavailable(cacheHitRate) || cacheHitRate === void 0 || cacheHitRate <= 0) {
57709
+ return false;
57710
+ }
57711
+ const tokensBefore = sumMessageTokens(messages) + config3.fixedOverheadTokens;
57712
+ return tokensBefore >= config3.cacheReclaimPayloadTokens || messages.length >= config3.cacheReclaimMessageCount;
57713
+ }
57560
57714
  function isNearWindowCeilingTrigger(messages, options2, config3, cacheHitRate) {
57561
57715
  if (options2.overflowRecovery === true) {
57562
57716
  return true;
@@ -57581,6 +57735,37 @@ function unprotectInTurnFrozenIds(messages, frozenToolCallIds, unprotectInTurn)
57581
57735
  }
57582
57736
  return stillFrozen;
57583
57737
  }
57738
+ function unprotectOldestFrozenIds(messages, frozenToolCallIds, keepRecent, keepTokens) {
57739
+ if (!frozenToolCallIds || frozenToolCallIds.size === 0) {
57740
+ return frozenToolCallIds;
57741
+ }
57742
+ const frozenIndexes = [];
57743
+ for (let index4 = 0; index4 < messages.length; index4++) {
57744
+ const message = messages[index4];
57745
+ if (isToolResultMessage3(message) && frozenToolCallIds.has(message.toolCallId)) {
57746
+ frozenIndexes.push(index4);
57747
+ }
57748
+ }
57749
+ if (frozenIndexes.length === 0) {
57750
+ return frozenToolCallIds;
57751
+ }
57752
+ const stillFrozen = /* @__PURE__ */ new Set();
57753
+ let keptTokens = 0;
57754
+ let keptRecent = 0;
57755
+ for (let cursor = frozenIndexes.length - 1; cursor >= 0; cursor--) {
57756
+ const message = messages[frozenIndexes[cursor]];
57757
+ if (!isToolResultMessage3(message)) {
57758
+ continue;
57759
+ }
57760
+ if (keptRecent >= keepRecent && keptTokens >= keepTokens) {
57761
+ break;
57762
+ }
57763
+ stillFrozen.add(message.toolCallId);
57764
+ keptRecent += 1;
57765
+ keptTokens += estimateMessageTokens(message);
57766
+ }
57767
+ return stillFrozen;
57768
+ }
57584
57769
  function isCompactedToolResultText(text) {
57585
57770
  return text.startsWith(MICROCOMPACT_MARKER_PREFIX) || text.startsWith(TODO_DUPLICATE_OMITTED_PREFIX) || isSupersessionMarker(text);
57586
57771
  }
@@ -57798,6 +57983,14 @@ function resolveMicrocompactConfig(options2) {
57798
57983
  MICROCOMPACT_PROACTIVE_MIN_SAVE_TOKENS
57799
57984
  ),
57800
57985
  proactiveKeepTokens: overflowRecovery ? MICROCOMPACT_OVERFLOW_KEEP_TOKENS : resolveNumericOption(options2.proactiveKeepTokens, MICROCOMPACT_PROACTIVE_KEEP_TOKENS),
57986
+ cacheReclaimPayloadTokens: resolveNumericOption(
57987
+ options2.cacheReclaimPayloadTokens,
57988
+ MICROCOMPACT_CACHE_RECLAIM_PAYLOAD_TOKENS
57989
+ ),
57990
+ cacheReclaimMessageCount: resolveNumericOption(
57991
+ options2.cacheReclaimMessageCount,
57992
+ MICROCOMPACT_CACHE_RECLAIM_MESSAGE_COUNT
57993
+ ),
57801
57994
  // Callers guard against an absent context window before resolving config, so
57802
57995
  // the fallback value is never actually used to make a decision.
57803
57996
  effectiveWindow: computeEffectiveContextWindow(
@@ -57898,13 +58091,20 @@ function computeMicrocompactTriggerState(messages, options2, config3) {
57898
58091
  cacheHitRate
57899
58092
  );
57900
58093
  const proactiveTrigger = isProactiveMicrocompactTrigger(messages, options2);
57901
- const frozenToolCallIds = overflowRecovery || noCache ? void 0 : unprotectInTurnFrozenIds(messages, options2.frozenToolCallIds, nearWindowCeiling);
58094
+ const cacheReclaim = isCacheReclaimTrigger(messages, config3, cacheHitRate);
58095
+ const frozenToolCallIds = overflowRecovery || noCache ? void 0 : cacheReclaim ? unprotectOldestFrozenIds(
58096
+ messages,
58097
+ options2.frozenToolCallIds,
58098
+ config3.keepRecent,
58099
+ config3.proactiveKeepTokens
58100
+ ) : unprotectInTurnFrozenIds(messages, options2.frozenToolCallIds, nearWindowCeiling);
57902
58101
  const { messageCount: cacheProtectedMessageCount, tokens: cacheProtectedTokens } = countCacheProtected(messages, frozenToolCallIds);
57903
58102
  if (cacheProtectedMessageCount > 0) {
57904
58103
  log4.debug("Preserving cache-protected prompt prefix", {
57905
58104
  cacheProtectedMessageCount,
57906
58105
  cacheProtectedTokens,
57907
- tokensBefore
58106
+ tokensBefore,
58107
+ cacheReclaim
57908
58108
  });
57909
58109
  }
57910
58110
  return {
@@ -57914,23 +58114,24 @@ function computeMicrocompactTriggerState(messages, options2, config3) {
57914
58114
  frozenToolCallIds,
57915
58115
  nearWindowCeiling,
57916
58116
  proactiveTrigger,
58117
+ cacheReclaim,
57917
58118
  cacheProtectedMessageCount,
57918
58119
  cacheProtectedTokens
57919
58120
  };
57920
58121
  }
57921
- function resolveEffectiveMinSaveTokens(config3, noCache, proactiveTrigger, nearWindowCeiling) {
58122
+ function resolveEffectiveMinSaveTokens(config3, noCache, proactiveTrigger, nearWindowCeiling, cacheReclaim) {
57922
58123
  if (noCache) {
57923
58124
  return Math.min(
57924
58125
  Math.floor(config3.minSaveTokens * MICROCOMPACT_NO_CACHE_AGGRESSION_FACTOR),
57925
58126
  config3.proactiveMinSaveTokens
57926
58127
  );
57927
58128
  }
57928
- if (proactiveTrigger && !nearWindowCeiling) {
58129
+ if ((proactiveTrigger || cacheReclaim) && !nearWindowCeiling) {
57929
58130
  return config3.proactiveMinSaveTokens;
57930
58131
  }
57931
58132
  return config3.minSaveTokens;
57932
58133
  }
57933
- function resolveEffectiveKeepTokens(config3, noCache, proactiveTrigger, nearWindowCeiling) {
58134
+ function resolveEffectiveKeepTokens(config3, noCache, proactiveTrigger, nearWindowCeiling, cacheReclaim) {
57934
58135
  if (noCache) {
57935
58136
  return Math.min(
57936
58137
  config3.keepTokens,
@@ -57938,7 +58139,7 @@ function resolveEffectiveKeepTokens(config3, noCache, proactiveTrigger, nearWind
57938
58139
  MICROCOMPACT_NO_CACHE_KEEP_TOKENS
57939
58140
  );
57940
58141
  }
57941
- if (proactiveTrigger && !nearWindowCeiling) {
58142
+ if ((proactiveTrigger || cacheReclaim) && !nearWindowCeiling) {
57942
58143
  return Math.min(config3.keepTokens, config3.proactiveKeepTokens);
57943
58144
  }
57944
58145
  return config3.keepTokens;
@@ -57951,13 +58152,15 @@ function resolveMicrocompactThresholds(config3, trigger) {
57951
58152
  config3,
57952
58153
  trigger.noCache,
57953
58154
  trigger.proactiveTrigger,
57954
- trigger.nearWindowCeiling
58155
+ trigger.nearWindowCeiling,
58156
+ trigger.cacheReclaim
57955
58157
  );
57956
58158
  const effectiveKeepTokens = resolveEffectiveKeepTokens(
57957
58159
  config3,
57958
58160
  trigger.noCache,
57959
58161
  trigger.proactiveTrigger,
57960
- trigger.nearWindowCeiling
58162
+ trigger.nearWindowCeiling,
58163
+ trigger.cacheReclaim
57961
58164
  );
57962
58165
  const effectiveDigestMinChars = resolveEffectiveDigestMinChars(config3, trigger.noCache);
57963
58166
  if (trigger.noCache) {
@@ -58052,8 +58255,8 @@ function shouldSkipPrefixRewriteForCacheEconomics(trigger, options2, messages, c
58052
58255
  const projected = projectClearedMessages(messages, clearCandidates);
58053
58256
  return !isMicrocompactRewriteCheaperThanKeep(previousWire, messages, projected);
58054
58257
  }
58055
- function isUnprotectedInTurnCandidate(trigger, options2, messages, index4) {
58056
- if (!trigger.nearWindowCeiling) {
58258
+ function isUnprotectedFrozenCandidate(trigger, options2, messages, index4) {
58259
+ if (!trigger.nearWindowCeiling && !trigger.cacheReclaim) {
58057
58260
  return false;
58058
58261
  }
58059
58262
  const message = messages[index4];
@@ -58071,7 +58274,7 @@ function selectCacheEconomicClearCandidates(trigger, options2, messages, clearCa
58071
58274
  }
58072
58275
  const prefixLength = options2.previousWire?.length ?? 0;
58073
58276
  return clearCandidates.filter(function isAllowedRewrite(index4) {
58074
- return index4 >= prefixLength || isUnprotectedInTurnCandidate(trigger, options2, messages, index4);
58277
+ return index4 >= prefixLength || isUnprotectedFrozenCandidate(trigger, options2, messages, index4);
58075
58278
  });
58076
58279
  }
58077
58280
  async function applyMicrocompactClearance(params) {
@@ -58102,7 +58305,7 @@ async function microcompactMessages(messages, options2 = {}) {
58102
58305
  }
58103
58306
  const config3 = resolveMicrocompactConfig(options2);
58104
58307
  const trigger = computeMicrocompactTriggerState(messages, options2, config3);
58105
- if (!trigger.nearWindowCeiling && !trigger.proactiveTrigger) {
58308
+ if (!trigger.nearWindowCeiling && !trigger.proactiveTrigger && !trigger.cacheReclaim) {
58106
58309
  return unchangedMicrocompactResult(messages, emptyStats2, trigger.tokensBefore);
58107
58310
  }
58108
58311
  const { effectiveMinSaveTokens, effectiveKeepTokens, effectiveDigestMinChars } = resolveMicrocompactThresholds(config3, trigger);
@@ -58805,7 +59008,12 @@ async function reconcileInterruptedSessionTurns(db, sessionId, sessionEntryCurso
58805
59008
  if (earliestOpenStart === null) {
58806
59009
  return 0;
58807
59010
  }
58808
- const entries = await loadSessionEntriesFrom(db, sessionId, earliestOpenStart, sessionEntryCursor);
59011
+ const entries = await loadSessionEntriesFrom(
59012
+ db,
59013
+ sessionId,
59014
+ earliestOpenStart,
59015
+ sessionEntryCursor
59016
+ );
58809
59017
  let reconciledCount = 0;
58810
59018
  for (let index4 = 0; index4 < turns.length; index4 += 1) {
58811
59019
  const reconciled = await reconcileOpenTurn(
@@ -59198,6 +59406,10 @@ async function clearConversationHistory(db, threadId, conversationId) {
59198
59406
  {
59199
59407
  sql: "DELETE FROM conversation_reads WHERE threadId = ? AND conversationId = ?",
59200
59408
  args: [threadId, conversationId]
59409
+ },
59410
+ {
59411
+ sql: "DELETE FROM conversation_completions WHERE threadId = ? AND conversationId = ?",
59412
+ args: [threadId, conversationId]
59201
59413
  }
59202
59414
  ],
59203
59415
  "write"
@@ -59550,7 +59762,13 @@ async function getRecentConversations(db, limit3, offset = 0, projectId, exclude
59550
59762
  AND last_turn.status = 'active'
59551
59763
  ORDER BY last_turn.timestamp DESC
59552
59764
  LIMIT 1
59553
- ) as model
59765
+ ) as model,
59766
+ EXISTS (
59767
+ SELECT 1
59768
+ FROM conversation_completions completions
59769
+ WHERE completions.threadId = recent.threadId
59770
+ AND completions.conversationId = recent.conversationId
59771
+ ) as isComplete
59554
59772
  FROM recent_conversations recent
59555
59773
  INNER JOIN (
59556
59774
  SELECT threadId, conversationId, input_tokens, output_tokens
@@ -59588,6 +59806,23 @@ async function markConversationRead(db, threadId, conversationId) {
59588
59806
  throw error2;
59589
59807
  }
59590
59808
  }
59809
+ async function markConversationComplete(db, threadId, conversationId) {
59810
+ await db.execute(
59811
+ `
59812
+ INSERT INTO conversation_completions (threadId, conversationId, completedAt)
59813
+ VALUES (?, ?, ?)
59814
+ ON CONFLICT (threadId, conversationId)
59815
+ DO UPDATE SET completedAt = excluded.completedAt
59816
+ `,
59817
+ [threadId, conversationId, (/* @__PURE__ */ new Date()).toISOString()]
59818
+ );
59819
+ }
59820
+ async function unmarkConversationComplete(db, threadId, conversationId) {
59821
+ await db.execute(
59822
+ "DELETE FROM conversation_completions WHERE threadId = ? AND conversationId = ?",
59823
+ [threadId, conversationId]
59824
+ );
59825
+ }
59591
59826
  async function unmarkConversationRead(db, threadId, conversationId) {
59592
59827
  try {
59593
59828
  await db.execute("DELETE FROM conversation_reads WHERE threadId = ? AND conversationId = ?", [
@@ -59684,6 +59919,7 @@ async function purgeAllConversationHistory(db) {
59684
59919
  [
59685
59920
  "DELETE FROM agent_sessions",
59686
59921
  "DELETE FROM conversation_reads",
59922
+ "DELETE FROM conversation_completions",
59687
59923
  "DELETE FROM conversation_history"
59688
59924
  ],
59689
59925
  "write"
@@ -59705,6 +59941,10 @@ async function purgeConversationHistoryForThread(db, threadId) {
59705
59941
  sql: "DELETE FROM conversation_reads WHERE threadId = ?",
59706
59942
  args: [threadId]
59707
59943
  },
59944
+ {
59945
+ sql: "DELETE FROM conversation_completions WHERE threadId = ?",
59946
+ args: [threadId]
59947
+ },
59708
59948
  {
59709
59949
  sql: "DELETE FROM conversation_history WHERE threadId = ?",
59710
59950
  args: [threadId]
@@ -59739,6 +59979,15 @@ async function purgeConversationHistoryForProject(db, projectId) {
59739
59979
  `,
59740
59980
  args: [projectId]
59741
59981
  },
59982
+ {
59983
+ sql: `
59984
+ DELETE FROM conversation_completions
59985
+ WHERE threadId IN (
59986
+ SELECT threads.id FROM threads WHERE threads.projectId = ?
59987
+ )
59988
+ `,
59989
+ args: [projectId]
59990
+ },
59742
59991
  {
59743
59992
  sql: `
59744
59993
  DELETE FROM conversation_history
@@ -148381,6 +148630,24 @@ async function migrateConversationReads(db) {
148381
148630
  )
148382
148631
  `);
148383
148632
  }
148633
+ async function migrateConversationCompletions(db) {
148634
+ const exists = await db.execute(
148635
+ `SELECT name FROM sqlite_master WHERE type='table' AND name='conversation_completions'`
148636
+ );
148637
+ if (exists.rows.length > 0) {
148638
+ return;
148639
+ }
148640
+ tarskDebugLog("[db] Running migration: Creating conversation_completions table");
148641
+ await db.execute(`
148642
+ CREATE TABLE conversation_completions (
148643
+ threadId TEXT NOT NULL,
148644
+ conversationId TEXT NOT NULL,
148645
+ completedAt TEXT NOT NULL,
148646
+ PRIMARY KEY (threadId, conversationId),
148647
+ FOREIGN KEY (threadId) REFERENCES threads(id) ON DELETE CASCADE
148648
+ )
148649
+ `);
148650
+ }
148384
148651
  async function migrateCrossProjectLaunches(db) {
148385
148652
  const exists = await db.execute(
148386
148653
  `SELECT name FROM sqlite_master WHERE type='table' AND name='cross_project_launches'`
@@ -148482,6 +148749,7 @@ async function runMigrations(db) {
148482
148749
  await migrateConversationHistorySummary(db);
148483
148750
  await migrateConversationProcessingStarts(db);
148484
148751
  await migrateConversationReads(db);
148752
+ await migrateConversationCompletions(db);
148485
148753
  await migrateCrossProjectLaunches(db);
148486
148754
  await migrateCrossProjectRoutes(db);
148487
148755
  await migrateThreadsChatTitles(db);
@@ -148623,6 +148891,17 @@ var init_database = __esm({
148623
148891
  PRIMARY KEY (threadId, conversationId),
148624
148892
  FOREIGN KEY (threadId) REFERENCES threads(id) ON DELETE CASCADE
148625
148893
  )
148894
+ `,
148895
+ // Conversations completed after their pull request merged. A subsequent
148896
+ // user message clears the marker and makes the conversation active again.
148897
+ `
148898
+ CREATE TABLE IF NOT EXISTS conversation_completions (
148899
+ threadId TEXT NOT NULL,
148900
+ conversationId TEXT NOT NULL,
148901
+ completedAt TEXT NOT NULL,
148902
+ PRIMARY KEY (threadId, conversationId),
148903
+ FOREIGN KEY (threadId) REFERENCES threads(id) ON DELETE CASCADE
148904
+ )
148626
148905
  `,
148627
148906
  `
148628
148907
  CREATE TABLE IF NOT EXISTS cross_project_launches (
@@ -172260,6 +172539,9 @@ var init_conversation_prompt_snapshot = __esm({
172260
172539
 
172261
172540
  // src/agent/prompt-cache-fingerprint.ts
172262
172541
  import { createHash as createHash4 } from "node:crypto";
172542
+ function promptCacheLaneSessionId(sessionId, lane = "agent") {
172543
+ return lane === "compact" ? `${sessionId}:compact` : sessionId;
172544
+ }
172263
172545
  function readNumber(value2) {
172264
172546
  return typeof value2 === "number" && Number.isFinite(value2) && value2 > 0 ? value2 : 0;
172265
172547
  }
@@ -172331,6 +172613,33 @@ function hash(value2) {
172331
172613
  function hashCanonical(value2) {
172332
172614
  return hashSerialized(serializeCanonical(value2));
172333
172615
  }
172616
+ function touchTrackedMap(map3, key2, value2) {
172617
+ map3.delete(key2);
172618
+ map3.set(key2, value2);
172619
+ if (map3.size <= MAX_TRACKED_SESSIONS2) {
172620
+ return;
172621
+ }
172622
+ const oldest = map3.keys().next().value;
172623
+ if (oldest !== void 0) {
172624
+ map3.delete(oldest);
172625
+ }
172626
+ }
172627
+ function rollingCacheHitRateFromTotals(totals) {
172628
+ return calculatePromptCacheHitRate(
172629
+ totals.cacheReadTokens,
172630
+ billablePromptTokensFromCounts(
172631
+ totals.inputTokens,
172632
+ totals.cacheReadTokens,
172633
+ totals.cacheWriteTokens
172634
+ )
172635
+ );
172636
+ }
172637
+ function shouldWarnPromptCacheMiss(totals, implicitPromptCache) {
172638
+ if (implicitPromptCache || totals.calls < ZERO_CACHE_MIN_CALLS) {
172639
+ return false;
172640
+ }
172641
+ return rollingCacheHitRateFromTotals(totals) < ZERO_CACHE_HIT_RATE_THRESHOLD;
172642
+ }
172334
172643
  function extractPayloadSections(payload) {
172335
172644
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
172336
172645
  return { system: void 0, tools: void 0, messages: payload };
@@ -172451,9 +172760,10 @@ function applyStablePromptCacheKey(payload, model, provider, sessionId, baseUrl)
172451
172760
  prompt_cache_key: createStablePromptCacheKey(model, payload, provider)
172452
172761
  };
172453
172762
  }
172454
- function applyPromptCacheToProviderPayload(payload, modelId, provider, sessionId, baseUrl) {
172455
- const next = applyStablePromptCacheKey(payload, modelId, provider, sessionId, baseUrl);
172456
- recordPromptCacheFingerprint(sessionId, provider, modelId, next, baseUrl);
172763
+ function applyPromptCacheToProviderPayload(payload, modelId, provider, sessionId, baseUrl, lane = "agent") {
172764
+ const cacheSessionId = promptCacheLaneSessionId(sessionId, lane);
172765
+ const next = applyStablePromptCacheKey(payload, modelId, provider, cacheSessionId, baseUrl);
172766
+ recordPromptCacheFingerprint(cacheSessionId, provider, modelId, next, baseUrl);
172457
172767
  return next;
172458
172768
  }
172459
172769
  function promptCacheTurnMetrics(usage2, firstTurn) {
@@ -172518,9 +172828,10 @@ function recordPromptCacheUsage(sessionId, event) {
172518
172828
  totals.inputTokens += usage2.inputTokens;
172519
172829
  totals.cacheReadTokens += usage2.cacheReadTokens;
172520
172830
  totals.cacheWriteTokens += usage2.cacheWriteTokens;
172521
- usageBySession.set(sessionId, totals);
172831
+ touchTrackedMap(usageBySession, sessionId, totals);
172522
172832
  const last2 = lastFingerprintBySession.get(sessionId);
172523
172833
  const metrics = promptCacheTurnMetrics(usage2, last2?.firstTurn === true);
172834
+ const rollingHitRate = rollingCacheHitRateFromTotals(totals);
172524
172835
  if (last2?.firstTurn) {
172525
172836
  lastFingerprintBySession.set(sessionId, { ...last2, firstTurn: false });
172526
172837
  }
@@ -172529,6 +172840,7 @@ function recordPromptCacheUsage(sessionId, event) {
172529
172840
  sessionId,
172530
172841
  ...usage2,
172531
172842
  ...metrics,
172843
+ rollingHitRate,
172532
172844
  promptCacheKey: last2?.promptCacheKey,
172533
172845
  sessionAffinityId: last2?.sessionAffinityId,
172534
172846
  implicitPromptCache: last2?.implicitPromptCache,
@@ -172539,12 +172851,12 @@ function recordPromptCacheUsage(sessionId, event) {
172539
172851
  payloadBytes: last2?.fingerprint.payloadBytes,
172540
172852
  messageCount: last2?.fingerprint.messageHashes.length
172541
172853
  });
172542
- if (!warnedNoCacheSessions.has(sessionId) && !last2?.implicitPromptCache && totals.calls >= ZERO_CACHE_MIN_CALLS && metrics.cacheHitRate < ZERO_CACHE_HIT_RATE_THRESHOLD) {
172854
+ if (!warnedNoCacheSessions.has(sessionId) && shouldWarnPromptCacheMiss(totals, last2?.implicitPromptCache === true)) {
172543
172855
  warnedNoCacheSessions.add(sessionId);
172544
172856
  log35.warn("Prompt cache is not being hit for this session", {
172545
172857
  sessionId,
172546
172858
  calls: totals.calls,
172547
- cacheHitRate: metrics.cacheHitRate,
172859
+ cacheHitRate: rollingHitRate,
172548
172860
  cacheReadTokens: totals.cacheReadTokens,
172549
172861
  cacheWriteTokens: totals.cacheWriteTokens,
172550
172862
  inputTokens: totals.inputTokens,
@@ -172559,12 +172871,7 @@ function getSessionCacheHitRate(sessionId) {
172559
172871
  if (!totals || totals.calls < ZERO_CACHE_MIN_CALLS) {
172560
172872
  return void 0;
172561
172873
  }
172562
- const billable = billablePromptTokensFromCounts(
172563
- totals.inputTokens,
172564
- totals.cacheReadTokens,
172565
- totals.cacheWriteTokens
172566
- );
172567
- const cacheHitRate = calculatePromptCacheHitRate(totals.cacheReadTokens, billable);
172874
+ const cacheHitRate = rollingCacheHitRateFromTotals(totals);
172568
172875
  if (last2?.implicitPromptCache && cacheHitRate < ZERO_CACHE_HIT_RATE_THRESHOLD) {
172569
172876
  return void 0;
172570
172877
  }
@@ -172581,7 +172888,7 @@ function logPromptCacheDiagnostics(sessionId) {
172581
172888
  totals.cacheReadTokens,
172582
172889
  totals.cacheWriteTokens
172583
172890
  );
172584
- const cacheHitRate = calculatePromptCacheHitRate(totals.cacheReadTokens, billablePromptTokens2);
172891
+ const cacheHitRate = rollingCacheHitRateFromTotals(totals);
172585
172892
  const caching = !last2?.implicitPromptCache && totals.calls >= ZERO_CACHE_MIN_CALLS && cacheHitRate < ZERO_CACHE_HIT_RATE_THRESHOLD ? "unavailable" : totals.cacheReadTokens > 0 ? "available" : "unknown";
172586
172893
  const diagnostics = {
172587
172894
  sessionId,
@@ -172607,7 +172914,6 @@ function logPromptCacheDiagnostics(sessionId) {
172607
172914
  });
172608
172915
  }
172609
172916
  log35.info("Prompt cache session diagnostics", diagnostics);
172610
- clearPromptCacheSessionState(sessionId);
172611
172917
  return diagnostics;
172612
172918
  }
172613
172919
  function clearPromptCacheSessionState(sessionId) {
@@ -172626,17 +172932,10 @@ function recordPromptCacheFingerprint(sessionId, provider, model, payload, baseU
172626
172932
  const fingerprint = createPromptCacheFingerprint(payload, previous);
172627
172933
  const promptCacheKey = extractPromptCacheKey(payload);
172628
172934
  const firstTurn = previous === void 0;
172629
- previousBySession.delete(key2);
172630
- previousBySession.set(key2, fingerprint);
172631
- if (previousBySession.size > MAX_TRACKED_SESSIONS2) {
172632
- const oldest = previousBySession.keys().next().value;
172633
- if (oldest !== void 0) {
172634
- previousBySession.delete(oldest);
172635
- }
172636
- }
172935
+ touchTrackedMap(previousBySession, key2, fingerprint);
172637
172936
  const sessionAffinityId = extractOpenRouterSessionId(payload);
172638
172937
  const implicitPromptCache = openRouterUsesImplicitPromptCache(model, baseUrl);
172639
- lastFingerprintBySession.set(sessionId, {
172938
+ touchTrackedMap(lastFingerprintBySession, sessionId, {
172640
172939
  fingerprint,
172641
172940
  promptCacheKey,
172642
172941
  sessionAffinityId,
@@ -173121,6 +173420,7 @@ async function executeSubagent(options2) {
173121
173420
  if (signal) signal.removeEventListener("abort", onAbort);
173122
173421
  unsubscribe();
173123
173422
  logPromptCacheDiagnostics(sessionId);
173423
+ clearPromptCacheSessionState(sessionId);
173124
173424
  await harness.close(SESSION_CONTEXT).catch((error2) => {
173125
173425
  log36.warn("Subagent cleanup failed", { error: error2 });
173126
173426
  });
@@ -177143,8 +177443,15 @@ function findFilesByBasenameInCwd(fileBasename, cwd, limit3) {
177143
177443
  try {
177144
177444
  const found = ts(`**/${fileBasename}`, {
177145
177445
  cwd,
177146
- dot: false,
177147
- ignore: ["**/node_modules/**", "**/.git/**"],
177446
+ dot: true,
177447
+ ignore: [
177448
+ "**/node_modules/**",
177449
+ "**/.git/**",
177450
+ "**/.hg/**",
177451
+ "**/.svn/**",
177452
+ "**/.jj/**",
177453
+ "**/.sl/**"
177454
+ ],
177148
177455
  nodir: true
177149
177456
  });
177150
177457
  return found.slice(0, limit3).map((match2) => match2.replace(/\\/g, "/"));
@@ -177152,6 +177459,39 @@ function findFilesByBasenameInCwd(fileBasename, cwd, limit3) {
177152
177459
  return [];
177153
177460
  }
177154
177461
  }
177462
+ function findHiddenDotSegmentPath(resolvedPath2, cwd) {
177463
+ const relativePath = relative4(cwd, resolvedPath2).replace(/\\/g, "/");
177464
+ if (!relativePath || relativePath.startsWith("..") || isAbsolute4(relativePath)) {
177465
+ return void 0;
177466
+ }
177467
+ const segments = relativePath.split("/").filter(Boolean);
177468
+ const rebuilt = [];
177469
+ let current = cwd;
177470
+ for (let index4 = 0; index4 < segments.length; index4++) {
177471
+ const segment = segments[index4];
177472
+ const next = resolvePath3(current, segment);
177473
+ if (fileExists(next)) {
177474
+ rebuilt.push(segment);
177475
+ current = next;
177476
+ continue;
177477
+ }
177478
+ if (segment.startsWith(".")) {
177479
+ return void 0;
177480
+ }
177481
+ const dotted = `.${segment}`;
177482
+ if (TOP_LEVEL_LAYOUT_SKIP.has(dotted)) {
177483
+ return void 0;
177484
+ }
177485
+ const remainder = segments.slice(index4 + 1);
177486
+ const candidateRel = [...rebuilt, dotted, ...remainder].join("/");
177487
+ const candidateAbs = resolvePath3(cwd, candidateRel);
177488
+ if (fileExists(candidateAbs)) {
177489
+ return candidateRel;
177490
+ }
177491
+ return void 0;
177492
+ }
177493
+ return void 0;
177494
+ }
177155
177495
  function segmentEditDistance(a2, b2) {
177156
177496
  if (a2 === b2) return 0;
177157
177497
  const al = a2.length;
@@ -177220,6 +177560,10 @@ function collectFileNotFoundHints(resolvedPath2, cwd) {
177220
177560
  if (suffixMatch && suffixMatch !== requestedRelative && suffixMatch !== ".") {
177221
177561
  return [`Try: ${suffixMatch}`];
177222
177562
  }
177563
+ const hiddenDotMatch = findHiddenDotSegmentPath(resolvedPath2, cwd);
177564
+ if (hiddenDotMatch && hiddenDotMatch !== requestedRelative) {
177565
+ return [`Try: ${hiddenDotMatch}`];
177566
+ }
177223
177567
  const siblingTypos = findSiblingNameTypos(resolvedPath2, cwd).filter(
177224
177568
  (match2) => match2 !== requestedRelative
177225
177569
  );
@@ -178915,7 +179259,7 @@ var init_tool_helpers = __esm({
178915
179259
 
178916
179260
  // src/tools/try-path-from-error.ts
178917
179261
  function extractTryPathFromError(error2) {
178918
- const pattern = /\bTry:\s*([A-Za-z0-9_./@+-]+\.[A-Za-z0-9]+|[A-Za-z0-9_./@+-]+\/[A-Za-z0-9_./@+-]+|[A-Za-z0-9_][A-Za-z0-9_./@+-]*)/g;
179262
+ const pattern = /\bTry:\s*(\.?[A-Za-z0-9_./@+-]+\.[A-Za-z0-9]+|\.?[A-Za-z0-9_./@+-]+\/[A-Za-z0-9_./@+-]+|\.?[A-Za-z0-9_][A-Za-z0-9_./@+-]*)/g;
178919
179263
  let match2;
178920
179264
  let lastValid = null;
178921
179265
  while ((match2 = pattern.exec(error2)) !== null) {
@@ -181678,20 +182022,34 @@ var init_grep = __esm({
181678
182022
  // src/tools/rip-grep.ts
181679
182023
  import { statSync as statSync8 } from "node:fs";
181680
182024
  import path9 from "node:path";
182025
+ function grepContentBudgetFor(input2) {
182026
+ return resolveGrepContentBudget({
182027
+ output_mode: input2.output_mode,
182028
+ head_limit: input2.head_limit,
182029
+ context: input2.context,
182030
+ "-C": input2["-C"],
182031
+ "-A": input2["-A"],
182032
+ "-B": input2["-B"]
182033
+ });
182034
+ }
181681
182035
  function resolveMaxOutputLines(input2, smartJsCapture) {
181682
- if (input2.head_limit === 0) {
182036
+ if (input2.head_limit === void 0 && smartJsCapture) {
181683
182037
  return void 0;
181684
182038
  }
181685
- if (input2.head_limit === void 0 && smartJsCapture) {
182039
+ const budget = grepContentBudgetFor(input2);
182040
+ if (budget.headLimit === 0) {
182041
+ return void 0;
182042
+ }
182043
+ if (input2.head_limit === 0 && !budget.headLimitScaled) {
181686
182044
  return void 0;
181687
182045
  }
181688
- return (input2.head_limit ?? DEFAULT_HEAD_LIMIT) + (input2.offset ?? 0) + 1;
182046
+ return (budget.headLimit ?? DEFAULT_GREP_HEAD_LIMIT) + (input2.offset ?? 0) + 1;
181689
182047
  }
181690
182048
  function applyHeadLimit(items, limit3, offset = 0) {
181691
182049
  if (limit3 === 0) {
181692
182050
  return { items: items.slice(offset), appliedLimit: void 0 };
181693
182051
  }
181694
- const effectiveLimit = limit3 ?? DEFAULT_HEAD_LIMIT;
182052
+ const effectiveLimit = limit3 ?? DEFAULT_GREP_HEAD_LIMIT;
181695
182053
  const sliced = items.slice(offset, offset + effectiveLimit);
181696
182054
  const wasTruncated = items.length - offset > effectiveLimit;
181697
182055
  return {
@@ -181771,14 +182129,11 @@ function buildRipgrepArgs(input2, fixedStrings = false, smartJsCapture = false)
181771
182129
  glob: glob2,
181772
182130
  type,
181773
182131
  output_mode = "content",
181774
- "-B": contextBefore,
181775
- "-A": contextAfter,
181776
- "-C": contextC,
181777
- context: context2,
181778
182132
  "-n": showLineNumbers = true,
181779
182133
  "-i": caseInsensitive = false,
181780
182134
  multiline = false
181781
182135
  } = input2;
182136
+ const budget = grepContentBudgetFor(input2);
181782
182137
  const args2 = ["--hidden", "--color=never"];
181783
182138
  if (fixedStrings) {
181784
182139
  args2.push("--fixed-strings");
@@ -181797,7 +182152,13 @@ function buildRipgrepArgs(input2, fixedStrings = false, smartJsCapture = false)
181797
182152
  if (smartJsCapture && output_mode === "count") args2.push("--with-filename");
181798
182153
  if (output_mode === "content") {
181799
182154
  if (hasExplicitGrepContext(input2)) {
181800
- appendContextArgs(args2, context2, contextC, contextBefore, contextAfter);
182155
+ appendContextArgs(
182156
+ args2,
182157
+ budget.context,
182158
+ budget.contextC,
182159
+ budget.contextBefore,
182160
+ budget.contextAfter
182161
+ );
181801
182162
  } else if (DEFAULT_GREP_CONTENT_CONTEXT > 0) {
181802
182163
  appendContextArgs(args2, void 0, DEFAULT_GREP_CONTENT_CONTEXT, void 0, void 0);
181803
182164
  }
@@ -181954,10 +182315,11 @@ function emptyMatchText(input2) {
181954
182315
  }
181955
182316
  return "No matches found";
181956
182317
  }
181957
- function formatContentResult(cwd, results, headLimit, offset, emptyText) {
182318
+ function formatContentResult(cwd, results, headLimit, offset, emptyText, budget) {
181958
182319
  const { items: limitedResults, appliedLimit } = applyHeadLimit(results, headLimit, offset);
181959
182320
  const finalLines = limitedResults.map((line) => relativizeContentLine(cwd, line));
181960
182321
  const limitInfo = formatLimitInfo(appliedLimit, offset > 0 ? offset : void 0);
182322
+ const budgetNotice = budget ? formatGrepContextBudgetNotice(budget) : "";
181961
182323
  let text;
181962
182324
  if (finalLines.length === 0) {
181963
182325
  text = emptyText;
@@ -181967,6 +182329,11 @@ function formatContentResult(cwd, results, headLimit, offset, emptyText) {
181967
182329
  logCompressOutput("grep.content", flat, compressed.text);
181968
182330
  text = compressed.applied ? `${GREP_CONTENT_BANNER}
181969
182331
  ${compressed.text}` : compressed.text;
182332
+ if (budgetNotice) {
182333
+ text += `
182334
+
182335
+ ${budgetNotice}`;
182336
+ }
181970
182337
  if (limitInfo) {
181971
182338
  text += `
181972
182339
 
@@ -182072,9 +182439,9 @@ function createRipGrepTool(cwd, options2) {
182072
182439
  }
182073
182440
  };
182074
182441
  }
182075
- function formatOutputByMode(cwd, results, outputMode, headLimit, offset, emptyText) {
182442
+ function formatOutputByMode(cwd, results, outputMode, headLimit, offset, emptyText, budget) {
182076
182443
  if (outputMode === "content") {
182077
- return formatContentResult(cwd, results, headLimit, offset, emptyText);
182444
+ return formatContentResult(cwd, results, headLimit, offset, emptyText, budget);
182078
182445
  }
182079
182446
  if (outputMode === "count") {
182080
182447
  return formatCountResult(cwd, results, headLimit, offset, emptyText);
@@ -182174,11 +182541,19 @@ function selectRawRipgrepCaptureSource(mode, input2, ordered) {
182174
182541
  return mode === "content" && !hasExplicitGrepContext(input2) ? ordered.filter(isGrepContentMatchLine) : ordered;
182175
182542
  }
182176
182543
  function resolveRawRipgrepDisplayLimit(input2) {
182177
- return input2.head_limit === 0 ? 0 : input2.head_limit ?? DEFAULT_HEAD_LIMIT;
182544
+ const budget = grepContentBudgetFor(input2);
182545
+ if (budget.headLimit === 0) {
182546
+ return 0;
182547
+ }
182548
+ return budget.headLimit ?? DEFAULT_GREP_HEAD_LIMIT;
182178
182549
  }
182179
182550
  function buildRawRipgrepText(params) {
182180
182551
  const { searchedAsLiteral, skippedPaths, displayItems, emptyText, diagnostics } = params;
182181
182552
  let text = `${buildPrefixNotices(searchedAsLiteral, skippedPaths)}${displayItems.join("\n") || emptyText}${diagnostics}`;
182553
+ const budgetNotice = params.budget ? formatGrepContextBudgetNotice(params.budget) : "";
182554
+ if (budgetNotice) text += `
182555
+
182556
+ ${budgetNotice}`;
182182
182557
  const limitInfo = formatLimitInfo(params.appliedLimit, params.offset ? params.offset : void 0);
182183
182558
  if (limitInfo) text += `
182184
182559
 
@@ -182220,7 +182595,8 @@ ${capture.diagnostics.join("\n")}` : "";
182220
182595
  emptyText,
182221
182596
  diagnostics,
182222
182597
  appliedLimit,
182223
- offset: input2.offset
182598
+ offset: input2.offset,
182599
+ budget: grepContentBudgetFor(input2)
182224
182600
  });
182225
182601
  const details = buildRawRipgrepDetails({
182226
182602
  mode,
@@ -182251,7 +182627,8 @@ async function executeRipgrepSearch(cwd, input2, smartJsCapture = false, signal)
182251
182627
  return executeRawRipgrepSearch(cwd, effectiveInput, absolutePaths, skippedPaths, runOptions);
182252
182628
  }
182253
182629
  const outputMode = effectiveInput.output_mode ?? "content";
182254
- const headLimit = effectiveInput.head_limit;
182630
+ const budget = grepContentBudgetFor(effectiveInput);
182631
+ const headLimit = budget.headLimit;
182255
182632
  const offset = effectiveInput.offset ?? 0;
182256
182633
  const { results, searchedAsLiteral } = await runRipgrepMultiWithLiteralFallback(
182257
182634
  { ...effectiveInput, output_mode: outputMode },
@@ -182265,7 +182642,8 @@ async function executeRipgrepSearch(cwd, input2, smartJsCapture = false, signal)
182265
182642
  outputMode,
182266
182643
  headLimit,
182267
182644
  offset,
182268
- emptyMatchText(effectiveInput)
182645
+ emptyMatchText(effectiveInput),
182646
+ budget
182269
182647
  );
182270
182648
  const truncation = truncateHead2(formatted.text);
182271
182649
  const trailing = buildTrailingNotice(truncation);
@@ -182296,7 +182674,7 @@ async function executeRipgrepSearch(cwd, input2, smartJsCapture = false, signal)
182296
182674
  details: Object.keys(details).length > 0 ? details : void 0
182297
182675
  };
182298
182676
  }
182299
- var VCS_DIRECTORIES_TO_EXCLUDE, DEFAULT_HEAD_LIMIT, DEFAULT_GREP_CONTENT_CONTEXT, GREP_TOOL_DESCRIPTION, ripGrepSchema, log40, PATHLESS_CONTENT_LINE2, REGEX_PARSE_ERROR_RE, REGEX_PARSE_HINT, LITERAL_FALLBACK_NOTICE;
182677
+ var VCS_DIRECTORIES_TO_EXCLUDE, GREP_TOOL_DESCRIPTION, ripGrepSchema, log40, PATHLESS_CONTENT_LINE2, REGEX_PARSE_ERROR_RE, REGEX_PARSE_HINT, LITERAL_FALLBACK_NOTICE;
182300
182678
  var init_rip_grep = __esm({
182301
182679
  "src/tools/rip-grep.ts"() {
182302
182680
  "use strict";
@@ -182319,8 +182697,6 @@ var init_rip_grep = __esm({
182319
182697
  "node_modules",
182320
182698
  ".bun"
182321
182699
  ];
182322
- DEFAULT_HEAD_LIMIT = 40;
182323
- DEFAULT_GREP_CONTENT_CONTEXT = 0;
182324
182700
  GREP_TOOL_DESCRIPTION = "Search file contents with regex (ripgrep-compatible grepts). Use read directly when the exact file path is already known. Content mode defaults to match lines only (-C 0); pass -C 3 (or -A/-B/context) when you need nearby lines for a unique edit hunk. Batch independent searches in one turn. output_mode: content (default; -A/-B/-C/context/-n apply here, -n defaults true), files_with_matches, count. Scope with path; glob for name/extension (*.ts, **/*.tsx)\u2014not a path substitute. type = rg --type. head_limit default 40 (0=unlimited); offset skips. multiline: . matches newlines. Respects .gitignore.";
182325
182701
  ripGrepSchema = Type2.Object({
182326
182702
  pattern: Type2.String(),
@@ -187181,13 +187557,50 @@ function normalizeSkillRef(input2) {
187181
187557
  }
187182
187558
  return { value: trimmed };
187183
187559
  }
187560
+ function stripTaskIdTruncation(id) {
187561
+ const trimmed = id.trim();
187562
+ const cleaned = trimmed.replace(/(?:\.{2,}|[?…]+)+$/u, "");
187563
+ return { cleaned, truncated: cleaned !== trimmed };
187564
+ }
187565
+ function isUuidPrefix(value2) {
187566
+ if (value2.length < 8 || value2.length >= 36) return false;
187567
+ return /^[0-9a-f]{8}(?:-[0-9a-f]{0,4}){0,4}[0-9a-f]*$/i.test(value2);
187568
+ }
187569
+ function formatTaskIdSuggestions(matches) {
187570
+ return matches.map((task) => ` - ${task.id}: ${task.title}`).join("\n");
187571
+ }
187572
+ async function resolveTaskById(db, projectId, rawId) {
187573
+ const { cleaned, truncated } = stripTaskIdTruncation(rawId);
187574
+ const exact = await getTaskById(db, rawId);
187575
+ if (exact && exact.projectId === projectId) {
187576
+ return { ok: true, id: exact.id, task: exact };
187577
+ }
187578
+ if (cleaned !== rawId) {
187579
+ const cleanedMatch = await getTaskById(db, cleaned);
187580
+ if (cleanedMatch && cleanedMatch.projectId === projectId) {
187581
+ return { ok: true, id: cleanedMatch.id, task: cleanedMatch };
187582
+ }
187583
+ }
187584
+ if (truncated || isUuidPrefix(cleaned)) {
187585
+ const matches = (await getTasksByProject(db, projectId)).filter(
187586
+ (task) => task.id.toLowerCase().startsWith(cleaned.toLowerCase())
187587
+ );
187588
+ if (matches.length === 1) {
187589
+ return { ok: true, id: matches[0].id, task: matches[0] };
187590
+ }
187591
+ if (matches.length > 1) {
187592
+ return {
187593
+ ok: false,
187594
+ error: `Error: task not found: ${rawId}. Similar ids:
187595
+ ${formatTaskIdSuggestions(matches)}`
187596
+ };
187597
+ }
187598
+ }
187599
+ return { ok: false, error: `Error: task not found: ${rawId}` };
187600
+ }
187184
187601
  async function resolveTaskReference(db, projectId, id, reference, action) {
187185
187602
  if (id?.trim()) {
187186
- const existing = await getTaskById(db, id);
187187
- if (!existing || existing.projectId !== projectId) {
187188
- return { ok: false, error: `Error: task not found: ${id}` };
187189
- }
187190
- return { ok: true, id, task: existing };
187603
+ return resolveTaskById(db, projectId, id.trim());
187191
187604
  }
187192
187605
  if (reference?.trim()) {
187193
187606
  const { exact, contains } = await findTasksByReference(db, projectId, reference.trim());
@@ -187413,8 +187826,14 @@ function createTasksTool(projectId, threadId, executionDeps) {
187413
187826
  if (tagIds) {
187414
187827
  rows = rows.filter((task) => tagIds.has(task.id));
187415
187828
  }
187829
+ const serialized = await serializeTasksWithTags(db, rows);
187416
187830
  const payload = {
187417
- tasks: rows.map((task) => ({ id: task.id, title: task.title, status: task.status }))
187831
+ tasks: serialized.map((task) => ({
187832
+ id: task.id,
187833
+ title: task.title,
187834
+ status: task.status,
187835
+ tags: task.tags.map((tag) => tag.name)
187836
+ }))
187418
187837
  };
187419
187838
  if (trimmedQuery) payload.query = trimmedQuery;
187420
187839
  return jsonResult(payload);
@@ -187643,7 +188062,7 @@ var init_tasks = __esm({
187643
188062
  init_task_trigger_validation();
187644
188063
  init_task_default_model();
187645
188064
  VALID_STATUSES = ["Ready", "Plan", "Build", "Test", "Review", "Done"];
187646
- TASKS_TOOL_DESCRIPTION = "Project tasks. add/schedule: title+description required; optional tags, skillRef, trigger. list: id/title/status, hides Done; filter query/status/tags. get: full task. tags: vocabulary+counts. update any field (null clears trigger/skill). implement this chat; runNow new thread (scheduled/event only). delete. Target by id or unique reference. Skills load only at run.";
188065
+ TASKS_TOOL_DESCRIPTION = "Project tasks. add/schedule: title+description required; optional tags, skillRef, trigger. list: id/title/status/tags, hides Done; filter query/status/tags. get: full task. tags: vocabulary+counts. update any field (null clears trigger/skill). implement this chat; runNow new thread (scheduled/event only). delete. Target by id or unique reference. Truncated ids resolve when unique. Skills load only at run.";
187647
188066
  tasksSchema = Type2.Object({
187648
188067
  action: Type2.Union([
187649
188068
  Type2.Literal("add"),
@@ -218242,8 +218661,8 @@ async function resolveInlineLlmModel(metadataManager, options2) {
218242
218661
  const resolved = await resolveModelAndKey(options2.provider, options2.model, metadataManager);
218243
218662
  return resolved ? { ...resolved, provider: options2.provider } : null;
218244
218663
  }
218664
+ const db = await getDatabase();
218245
218665
  if (options2.threadId) {
218246
- const db = await getDatabase();
218247
218666
  const thread = await getThread(db, options2.threadId);
218248
218667
  if (thread?.modelProvider && thread.model) {
218249
218668
  const resolved = await resolveModelAndKey(
@@ -218254,14 +218673,28 @@ async function resolveInlineLlmModel(metadataManager, options2) {
218254
218673
  return resolved ? { ...resolved, provider: thread.modelProvider } : null;
218255
218674
  }
218256
218675
  }
218676
+ try {
218677
+ const defaultAlias = resolveModelAlias("default", await getModelAliases(db));
218678
+ if (defaultAlias) {
218679
+ const resolved = await resolveModelAndKey(
218680
+ defaultAlias.provider,
218681
+ defaultAlias.model,
218682
+ metadataManager
218683
+ );
218684
+ return resolved ? { ...resolved, provider: defaultAlias.provider } : null;
218685
+ }
218686
+ } catch {
218687
+ }
218257
218688
  return null;
218258
218689
  }
218259
218690
  var init_inline_model = __esm({
218260
218691
  "src/core/inline-model.ts"() {
218261
218692
  "use strict";
218693
+ init_dist();
218262
218694
  init_git_utils();
218263
218695
  init_database();
218264
218696
  init_threads_database();
218697
+ init_model_aliases_store();
218265
218698
  }
218266
218699
  });
218267
218700
 
@@ -223341,6 +223774,8 @@ var init_agent_executor_run = __esm({
223341
223774
  usageCompactCount = 0;
223342
223775
  pendingUsageCompact = false;
223343
223776
  skipUsageCompactOnce = false;
223777
+ /** Compact/rollover payloads must not share the agent prompt-cache lane. */
223778
+ compactPayloadLane = false;
223344
223779
  incompleteStopResumeCount = 0;
223345
223780
  observationHandler;
223346
223781
  harness;
@@ -223680,12 +224115,14 @@ ${prompt}` : prompt;
223680
224115
  }
223681
224116
  registerHarnessPayloadHandler() {
223682
224117
  this.harness.hooks.on("before_payload", (event) => {
224118
+ const lane = this.compactPayloadLane ? "compact" : "agent";
223683
224119
  const payload = applyPromptCacheToProviderPayload(
223684
224120
  compactToolSchemasInPayload(event.payload),
223685
224121
  event.model.id,
223686
224122
  event.model.provider,
223687
224123
  this.sessionMetadata.id,
223688
- event.model.baseUrl
224124
+ event.model.baseUrl,
224125
+ lane
223689
224126
  );
223690
224127
  return { payload };
223691
224128
  });
@@ -223834,36 +224271,51 @@ ${prompt}` : prompt;
223834
224271
  return 0;
223835
224272
  }
223836
224273
  }
224274
+ async withCompactCacheLane(run) {
224275
+ this.compactPayloadLane = true;
224276
+ try {
224277
+ return await run();
224278
+ } finally {
224279
+ this.compactPayloadLane = false;
224280
+ }
224281
+ }
223837
224282
  async compactForOverflowResume(notice = OVERFLOW_COMPACT_NOTICE) {
223838
224283
  await this.lane.waitForIdle(this.runContext);
223839
224284
  const messagesBefore = await this.countSessionUserMessages();
223840
224285
  const contextBefore = await readContextMessages(this.session, this.runContext);
223841
224286
  const tokensBefore = estimateContextTokens(contextBefore).tokens;
223842
- if (this.persistentTurn && this.context.conversationId && this.context.projectId) {
223843
- await rolloverConversationContext(
223844
- {
223845
- db: this.persistentTurn.db,
223846
- harness: this.harness,
223847
- lane: this.lane,
223848
- session: this.session,
223849
- projectId: this.context.projectId,
223850
- threadId: this.context.threadId,
223851
- conversationId: this.context.conversationId,
223852
- requestModel: normalizeCompactModelId(
223853
- this.model,
223854
- this.providerName,
223855
- this.resolvedModel.id
223856
- ),
223857
- reason: this.pendingOverflowError ? "overflow" : "mid-turn",
223858
- projectMarker: false
223859
- },
223860
- this.runContext
224287
+ const persistentTurn = this.persistentTurn;
224288
+ const conversationId = this.context.conversationId;
224289
+ const projectId = this.context.projectId;
224290
+ if (persistentTurn && conversationId && projectId) {
224291
+ await this.withCompactCacheLane(
224292
+ () => rolloverConversationContext(
224293
+ {
224294
+ db: persistentTurn.db,
224295
+ harness: this.harness,
224296
+ lane: this.lane,
224297
+ session: this.session,
224298
+ projectId,
224299
+ threadId: this.context.threadId,
224300
+ conversationId,
224301
+ requestModel: normalizeCompactModelId(
224302
+ this.model,
224303
+ this.providerName,
224304
+ this.resolvedModel.id
224305
+ ),
224306
+ reason: this.pendingOverflowError ? "overflow" : "mid-turn",
224307
+ projectMarker: false
224308
+ },
224309
+ this.runContext
224310
+ )
223861
224311
  );
223862
224312
  } else {
223863
- const result = await this.lane.compact(
223864
- { customInstructions: `${COMPACT_SUMMARY_PROMPT}
224313
+ const result = await this.withCompactCacheLane(
224314
+ () => this.lane.compact(
224315
+ { customInstructions: `${COMPACT_SUMMARY_PROMPT}
223865
224316
  ${OVERFLOW_COMPACT_FOCUS}` },
223866
- this.runContext
224317
+ this.runContext
224318
+ )
223867
224319
  );
223868
224320
  if (Result.isErr(result)) {
223869
224321
  throw new Error(`Overflow compaction failed: ${result.error.message}`);
@@ -223933,7 +224385,6 @@ ${OVERFLOW_COMPACT_FOCUS}` },
223933
224385
  });
223934
224386
  return;
223935
224387
  }
223936
- clearPromptCacheSessionState(this.sessionMetadata.id);
223937
224388
  handlePromptError(err2, {
223938
224389
  eventQueue: this.eventQueue,
223939
224390
  promptRequest: this.promptRequest
@@ -226749,6 +227200,49 @@ var init_stream_helper = __esm({
226749
227200
  }
226750
227201
  });
226751
227202
 
227203
+ // src/features/chat/chat-auto-route.service.ts
227204
+ async function routePromptToDecision(prompt, aliases, metadataManager, dependencies = {}) {
227205
+ const router = resolveAutoRouteModelAlias(aliases);
227206
+ if (!router || !prompt.trim()) {
227207
+ return "default";
227208
+ }
227209
+ try {
227210
+ const modelResolver = dependencies.modelResolver ?? resolveModelAndKey;
227211
+ const resolved = await modelResolver(router.provider, router.model, metadataManager);
227212
+ if (!resolved) {
227213
+ return "default";
227214
+ }
227215
+ const complete = dependencies.complete ?? completeSimpleWithSpend;
227216
+ const response = await complete(
227217
+ resolved.model,
227218
+ {
227219
+ systemPrompt: AUTO_ROUTE_SYSTEM_PROMPT,
227220
+ messages: [
227221
+ {
227222
+ role: "user",
227223
+ content: prompt.trim(),
227224
+ timestamp: Date.now()
227225
+ }
227226
+ ]
227227
+ },
227228
+ { apiKey: resolved.apiKey },
227229
+ router.provider
227230
+ );
227231
+ const raw2 = response.content.filter((block) => block.type === "text").map((block) => block.text).join("").trim();
227232
+ return parseAutoRouteDecision(raw2) ?? "default";
227233
+ } catch {
227234
+ return "default";
227235
+ }
227236
+ }
227237
+ var init_chat_auto_route_service = __esm({
227238
+ "src/features/chat/chat-auto-route.service.ts"() {
227239
+ "use strict";
227240
+ init_dist();
227241
+ init_git_utils();
227242
+ init_spend_record();
227243
+ }
227244
+ });
227245
+
226752
227246
  // src/core/runtime-log-level.ts
226753
227247
  function syncRuntimeLogLevel(isDebug2) {
226754
227248
  setLogLevel(
@@ -227677,7 +228171,8 @@ function prepareChatRequest(c, body) {
227677
228171
  attribution: rawAttribution,
227678
228172
  idempotencyKey: rawIdempotencyKey,
227679
228173
  hideUserMessage: rawHideUserMessage,
227680
- runInBackground: rawRunInBackground
228174
+ runInBackground: rawRunInBackground,
228175
+ autoRoute: rawAutoRoute
227681
228176
  } = body;
227682
228177
  if (!threadId || typeof threadId !== "string") {
227683
228178
  return {
@@ -227756,7 +228251,8 @@ function prepareChatRequest(c, body) {
227756
228251
  attribution: parseTurnAttribution(rawAttribution),
227757
228252
  ...idempotencyKey ? { idempotencyKey } : {},
227758
228253
  hideUserMessage: rawHideUserMessage === true,
227759
- runInBackground: rawRunInBackground === true
228254
+ runInBackground: rawRunInBackground === true,
228255
+ autoRoute: rawAutoRoute === true
227760
228256
  }
227761
228257
  };
227762
228258
  }
@@ -227905,7 +228401,9 @@ async function launchReservedChatTurn(args2) {
227905
228401
  return args2.c.json({
227906
228402
  ok: true,
227907
228403
  threadId: args2.deps.activeThreadId,
227908
- conversationId: args2.deps.conversationId
228404
+ conversationId: args2.deps.conversationId,
228405
+ model: args2.deps.model,
228406
+ provider: args2.deps.provider
227909
228407
  });
227910
228408
  }
227911
228409
  return streamAsyncGenerator(args2.c, withCompleteSignal(), {
@@ -228050,6 +228548,7 @@ async function postChatMessage(c, threadManager, agentExecutor, conversationMana
228050
228548
  requestedConversationId,
228051
228549
  attribution,
228052
228550
  idempotencyKey,
228551
+ autoRoute,
228053
228552
  hideUserMessage,
228054
228553
  runInBackground
228055
228554
  } = prepared.request;
@@ -228093,15 +228592,23 @@ async function postChatMessage(c, threadManager, agentExecutor, conversationMana
228093
228592
  });
228094
228593
  return conversationBusyResponse(c, activeThreadId, conversationId);
228095
228594
  }
228595
+ const db = await getDatabase();
228596
+ const project = await getProject(db, thread.projectId);
228597
+ const seatbeltSandboxEnabled = await resolveSeatbeltSandboxEnabled(db);
228598
+ const modelAliases = await getModelAliases(db);
228599
+ if (autoRoute) {
228600
+ const decision = await routePromptToDecision(userContent, modelAliases, metadataManager);
228601
+ const routedAlias = decision === "cheap" ? resolveModelAlias("cheap", modelAliases) : decision === "smart" ? resolveSmartModelAlias(modelAliases) : null;
228602
+ if (routedAlias) {
228603
+ model = routedAlias.model;
228604
+ provider = routedAlias.provider;
228605
+ }
228606
+ }
228096
228607
  const { availableSkills, activatedSkills, agents } = await loadSkillAndAgentContext(
228097
228608
  thread,
228098
228609
  threadPath,
228099
228610
  userContent
228100
228611
  );
228101
- const db = await getDatabase();
228102
- const project = await getProject(db, thread.projectId);
228103
- const seatbeltSandboxEnabled = await resolveSeatbeltSandboxEnabled(db);
228104
- const modelAliases = await getModelAliases(db);
228105
228612
  const orchestrated = resolveOrchestrateModel(c, modelAliases, orchestrateMode, model, provider);
228106
228613
  if (!orchestrated.ok) {
228107
228614
  return orchestrated.response;
@@ -228206,6 +228713,7 @@ var init_chat_post_route = __esm({
228206
228713
  init_conversations_content();
228207
228714
  init_route_helpers();
228208
228715
  init_error_responses();
228716
+ init_chat_auto_route_service();
228209
228717
  init_database();
228210
228718
  init_database_state();
228211
228719
  init_account_settings_route();
@@ -228529,49 +229037,6 @@ var init_chat_compact_route = __esm({
228529
229037
  }
228530
229038
  });
228531
229039
 
228532
- // src/features/chat/chat-auto-route.service.ts
228533
- async function routePromptToDecision(prompt, aliases, metadataManager, dependencies = {}) {
228534
- const router = resolveAutoRouteModelAlias(aliases);
228535
- if (!router || !prompt.trim()) {
228536
- return "default";
228537
- }
228538
- try {
228539
- const modelResolver = dependencies.modelResolver ?? resolveModelAndKey;
228540
- const resolved = await modelResolver(router.provider, router.model, metadataManager);
228541
- if (!resolved) {
228542
- return "default";
228543
- }
228544
- const complete = dependencies.complete ?? completeSimpleWithSpend;
228545
- const response = await complete(
228546
- resolved.model,
228547
- {
228548
- systemPrompt: AUTO_ROUTE_SYSTEM_PROMPT,
228549
- messages: [
228550
- {
228551
- role: "user",
228552
- content: prompt.trim(),
228553
- timestamp: Date.now()
228554
- }
228555
- ]
228556
- },
228557
- { apiKey: resolved.apiKey },
228558
- router.provider
228559
- );
228560
- const raw2 = response.content.filter((block) => block.type === "text").map((block) => block.text).join("").trim();
228561
- return parseAutoRouteDecision(raw2) ?? "default";
228562
- } catch {
228563
- return "default";
228564
- }
228565
- }
228566
- var init_chat_auto_route_service = __esm({
228567
- "src/features/chat/chat-auto-route.service.ts"() {
228568
- "use strict";
228569
- init_dist();
228570
- init_git_utils();
228571
- init_spend_record();
228572
- }
228573
- });
228574
-
228575
229040
  // src/features/chat/chat-auto-route.route.ts
228576
229041
  async function handleAutoRoute(c, threadManager, metadataManager) {
228577
229042
  const threadId = c.req.param("threadId");
@@ -228858,6 +229323,9 @@ async function postAgentNote(c, threadManager, conversationManager) {
228858
229323
  await conversationManager.completeMessage(messageId, content, [
228859
229324
  { type: "message", role: "assistant", content }
228860
229325
  ]);
229326
+ if (body.markComplete === true) {
229327
+ await conversationManager.markConversationComplete(threadId, conversationId);
229328
+ }
228861
229329
  const history2 = await conversationManager.getConversationHistoryByConversationId(
228862
229330
  threadId,
228863
229331
  conversationId
@@ -229394,6 +229862,9 @@ var init_conversations_manager = __esm({
229394
229862
  if (!this.db) {
229395
229863
  await this.initialize();
229396
229864
  }
229865
+ if (message.trim()) {
229866
+ await unmarkConversationComplete(this.db, threadId, conversationId);
229867
+ }
229397
229868
  const messageId = await insertMessage(
229398
229869
  this.db,
229399
229870
  threadId,
@@ -229700,6 +230171,14 @@ var init_conversations_manager = __esm({
229700
230171
  * Removes a conversation's read mark so it returns to the unread Chats
229701
230172
  * list. Used when the user resumes a chat from History.
229702
230173
  */
230174
+ async markConversationComplete(threadId, conversationId) {
230175
+ try {
230176
+ await markConversationComplete(this.db, threadId, conversationId);
230177
+ } catch (error2) {
230178
+ log83.error("Failed to mark conversation complete", { error: error2, threadId, conversationId });
230179
+ throw error2;
230180
+ }
230181
+ }
229703
230182
  async unmarkConversationRead(threadId, conversationId) {
229704
230183
  try {
229705
230184
  await unmarkConversationRead(this.db, threadId, conversationId);
@@ -230287,7 +230766,8 @@ async function getRecentConversations2(c, conversationManager) {
230287
230766
  inputTokens: Number(conversation.inputTokens) || 0,
230288
230767
  outputTokens: Number(conversation.outputTokens) || 0,
230289
230768
  model: conversation.model,
230290
- branch: conversation.branch
230769
+ branch: conversation.branch,
230770
+ isComplete: Boolean(conversation.isComplete)
230291
230771
  }));
230292
230772
  return successResponse(c, { conversations, total, limit: safeLimit, offset: safeOffset }, 200);
230293
230773
  } catch (error2) {
@@ -242815,11 +243295,91 @@ var init_providers_open_external_route = __esm({
242815
243295
  }
242816
243296
  });
242817
243297
 
243298
+ // src/features/providers/providers-openrouter-oauth.route.ts
243299
+ function encodeBase64Url(bytes) {
243300
+ let binary = "";
243301
+ for (const byte of bytes) binary += String.fromCharCode(byte);
243302
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
243303
+ }
243304
+ async function createPkcePair() {
243305
+ const verifierBytes = new Uint8Array(32);
243306
+ crypto.getRandomValues(verifierBytes);
243307
+ const verifier = encodeBase64Url(verifierBytes);
243308
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
243309
+ return { verifier, challenge: encodeBase64Url(new Uint8Array(digest)) };
243310
+ }
243311
+ function removeExpiredAuthorizations() {
243312
+ const now = Date.now();
243313
+ for (const [state3, authorization] of pendingAuthorizations) {
243314
+ if (now - authorization.createdAt > PENDING_TTL_MS) pendingAuthorizations.delete(state3);
243315
+ }
243316
+ }
243317
+ async function startOpenRouterOAuth(c) {
243318
+ removeExpiredAuthorizations();
243319
+ const { verifier, challenge } = await createPkcePair();
243320
+ const stateBytes = new Uint8Array(24);
243321
+ crypto.getRandomValues(stateBytes);
243322
+ const state3 = encodeBase64Url(stateBytes);
243323
+ const callbackUrl = new URL("/api/providers/openrouter/oauth/callback", c.req.url).toString();
243324
+ pendingAuthorizations.set(state3, { verifier, callbackUrl, createdAt: Date.now() });
243325
+ const authorizationUrl = new URL(OPENROUTER_AUTH_URL);
243326
+ authorizationUrl.searchParams.set("callback_url", callbackUrl);
243327
+ authorizationUrl.searchParams.set("code_challenge", challenge);
243328
+ authorizationUrl.searchParams.set("code_challenge_method", "S256");
243329
+ authorizationUrl.searchParams.set("key_label", "Tarsk");
243330
+ authorizationUrl.searchParams.set("state", state3);
243331
+ return c.json({ url: authorizationUrl.toString() });
243332
+ }
243333
+ async function completeOpenRouterOAuth(c, metadataManager) {
243334
+ const code = new URL(c.req.url).searchParams.get("code");
243335
+ const state3 = new URL(c.req.url).searchParams.get("state");
243336
+ if (!code || !state3) return c.text("Missing OAuth code or state", 400);
243337
+ const pending2 = pendingAuthorizations.get(state3);
243338
+ pendingAuthorizations.delete(state3);
243339
+ if (!pending2 || Date.now() - pending2.createdAt > PENDING_TTL_MS) {
243340
+ return c.text("This OAuth session has expired. Return to Tarsk and try again.", 400);
243341
+ }
243342
+ const response = await fetch(OPENROUTER_EXCHANGE_URL, {
243343
+ method: "POST",
243344
+ headers: { "Content-Type": "application/json" },
243345
+ body: JSON.stringify({
243346
+ code,
243347
+ code_verifier: pending2.verifier,
243348
+ code_challenge_method: "S256"
243349
+ })
243350
+ });
243351
+ if (!response.ok)
243352
+ return c.text("OpenRouter authorization could not be completed. Try again.", 502);
243353
+ const result = await response.json();
243354
+ if (!result.key) return c.text("OpenRouter did not return an API key. Try again.", 502);
243355
+ await metadataManager.saveProviderKey("openrouter", result.key);
243356
+ const keyName = await resolveProviderKeyName("openrouter");
243357
+ if (keyName) {
243358
+ updateRuntimeEnv({ [keyName]: result.key });
243359
+ await updateEnvFile({ [keyName]: result.key });
243360
+ }
243361
+ return c.html("<h1>OpenRouter connected</h1><p>You can close this tab and return to Tarsk.</p>");
243362
+ }
243363
+ var OPENROUTER_AUTH_URL, OPENROUTER_EXCHANGE_URL, PENDING_TTL_MS, pendingAuthorizations;
243364
+ var init_providers_openrouter_oauth_route = __esm({
243365
+ "src/features/providers/providers-openrouter-oauth.route.ts"() {
243366
+ "use strict";
243367
+ init_env_manager();
243368
+ init_provider_resolver();
243369
+ OPENROUTER_AUTH_URL = "https://openrouter.ai/auth";
243370
+ OPENROUTER_EXCHANGE_URL = "https://openrouter.ai/api/v1/auth/keys";
243371
+ PENDING_TTL_MS = 10 * 60 * 1e3;
243372
+ pendingAuthorizations = /* @__PURE__ */ new Map();
243373
+ }
243374
+ });
243375
+
242818
243376
  // src/features/providers/providers.routes.ts
242819
243377
  function createProviderRoutes(metadataManager) {
242820
243378
  const router = new Hono2();
242821
243379
  router.get("/", (c) => getProviders(c, metadataManager));
242822
243380
  router.post("/open-external", (c) => openExternalUrl(c));
243381
+ router.get("/openrouter/oauth/start", (c) => startOpenRouterOAuth(c));
243382
+ router.get("/openrouter/oauth/callback", (c) => completeOpenRouterOAuth(c, metadataManager));
242823
243383
  router.post("/keys", (c) => postProviderKeys(c, metadataManager));
242824
243384
  router.post("/bulk-keys", (c) => postProviderBulkKeys(c, metadataManager));
242825
243385
  router.post("/env", (c) => postProviderEnv(c, metadataManager));
@@ -242838,6 +243398,7 @@ var init_providers_routes = __esm({
242838
243398
  init_providers_get_credits_route();
242839
243399
  init_providers_get_logo_route();
242840
243400
  init_providers_open_external_route();
243401
+ init_providers_openrouter_oauth_route();
242841
243402
  }
242842
243403
  });
242843
243404