@sideboard-ai/core 0.1.208 → 0.1.210

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 (51) hide show
  1. package/dist/{abletime-I4IYZBKU.js → abletime-GDZLZRMY.js} +4 -4
  2. package/dist/{abletime-UWSSLXH3.js → abletime-QGGYL2G4.js} +4 -4
  3. package/dist/{abletime-oauth-C3BQXKW3.js → abletime-oauth-3X3BAPTF.js} +3 -3
  4. package/dist/{abletime-oauth-UZHPB3W2.js → abletime-oauth-F335TWKY.js} +3 -3
  5. package/dist/{abletime-rest-HYNYDYK3.js → abletime-rest-LAGTPAJL.js} +3 -3
  6. package/dist/{abletime-rest-5YPPEOKK.js → abletime-rest-PLJVY3H3.js} +3 -3
  7. package/dist/agents/cursor-runner.js +3 -3
  8. package/dist/{agents-QHQXR55O.js → agents-G3TFVFBQ.js} +6 -5
  9. package/dist/{agents-CCS5IEBV.js → agents-IQZUN47D.js} +6 -5
  10. package/dist/{app-settings-GJ6KDYEF.js → app-settings-2TN3WLZV.js} +7 -1
  11. package/dist/{app-settings-R2KNCT37.js → app-settings-XCRNCEEE.js} +7 -1
  12. package/dist/{chunk-F4LZUEIO.js → chunk-2M5B7YNY.js} +2 -2
  13. package/dist/{chunk-C6ZNQV5W.js → chunk-2R6BZRRB.js} +117 -25
  14. package/dist/{chunk-HA4EZKFY.js → chunk-3S2LDD2F.js} +3 -3
  15. package/dist/{chunk-6YZLSZLK.js → chunk-42IULNIY.js} +3 -3
  16. package/dist/{chunk-C5MNMITQ.js → chunk-AOQZZA3M.js} +119 -25
  17. package/dist/{chunk-4EGK47WV.js → chunk-BTC2D6LS.js} +217 -0
  18. package/dist/{chunk-7DKX5JLT.js → chunk-FGTPRMPS.js} +18 -3
  19. package/dist/{chunk-X45BV4VX.js → chunk-G4TANQC3.js} +5 -5
  20. package/dist/{chunk-Y4CF7LHH.js → chunk-L5CIEBLR.js} +232 -0
  21. package/dist/{chunk-WXWJ5MJ4.js → chunk-LS6TSOCE.js} +5 -5
  22. package/dist/{chunk-6J4OQ6TF.js → chunk-MN6YUD4O.js} +3 -3
  23. package/dist/{chunk-7PEIIN7P.js → chunk-NDE5RKZP.js} +24 -87
  24. package/dist/{chunk-W6X4GZJG.js → chunk-REZRGCKV.js} +3 -3
  25. package/dist/{chunk-NJ2CCLV6.js → chunk-WX4S775K.js} +2 -2
  26. package/dist/chunk-X5B3OS5I.js +34 -0
  27. package/dist/{chunk-ZHCB4CKR.js → chunk-X5PUFYDJ.js} +18 -3
  28. package/dist/{chunk-TEDEVD4O.js → chunk-YVE4PXCJ.js} +2 -2
  29. package/dist/{chunk-A6SOSLUV.js → chunk-YYELAUKP.js} +24 -94
  30. package/dist/{chunk-DNTPX6HV.js → chunk-ZC664YBJ.js} +3 -3
  31. package/dist/{chunk-OP6CFVTB.js → chunk-ZZNZX2QW.js} +2 -2
  32. package/dist/{coordinator-prompt-WOTJQMD5.js → coordinator-prompt-GCITY3Q5.js} +5 -4
  33. package/dist/{coordinator-prompt-TUHB6ZFA.js → coordinator-prompt-PONGPWIP.js} +5 -4
  34. package/dist/{cursor-recover-TXVTLAMA.js → cursor-recover-4PQAADAU.js} +3 -28
  35. package/dist/{global-workspace-V6G2KH2V.js → global-workspace-LIZHU4GM.js} +5 -4
  36. package/dist/{global-workspace-5UUUNA4A.js → global-workspace-LQZLTGFL.js} +5 -4
  37. package/dist/index.cjs +681 -385
  38. package/dist/index.d.cts +96 -5
  39. package/dist/index.d.ts +96 -5
  40. package/dist/index.js +52 -19
  41. package/dist/mcp/run-stdio.cjs +647 -385
  42. package/dist/mcp/run-stdio.js +12 -11
  43. package/dist/{orchestrator-4IGHVRAF.js → orchestrator-G5HELCVT.js} +7 -6
  44. package/dist/{orchestrator-D4AQNF25.js → orchestrator-ZBUXJCII.js} +7 -6
  45. package/dist/{thread-store-FMWDFAO5.js → thread-store-FCWU7Y3X.js} +2 -1
  46. package/dist/{thread-store-ESZYZSVC.js → thread-store-KMZRQEPY.js} +2 -1
  47. package/dist/{workspaces-PZ36M7EQ.js → workspaces-2XW2DMRG.js} +5 -4
  48. package/dist/{workspaces-CLNANACI.js → workspaces-T6PMQZYQ.js} +5 -4
  49. package/dist/{worktree-JKTM47K5.js → worktree-2OEMMFRT.js} +4 -3
  50. package/dist/{worktree-NC4XQNQI.js → worktree-5ZGWKKZ6.js} +4 -3
  51. package/package.json +1 -1
@@ -8,9 +8,7 @@ import {
8
8
  adjustBrightsyTurnExit,
9
9
  allAdapters,
10
10
  applyAgentEvent,
11
- applyTurnUsage,
12
11
  clipAgentEventForPaint,
13
- contextTokens,
14
12
  finalizeParts,
15
13
  getAdapter,
16
14
  isBrightsyNdjsonLine,
@@ -25,9 +23,8 @@ import {
25
23
  partsToAssistantText,
26
24
  resolveQuotaFallbackAgent,
27
25
  stripBrightsyNdjsonNoise,
28
- sumUsageList,
29
26
  toolDescription
30
- } from "./chunk-A6SOSLUV.js";
27
+ } from "./chunk-YYELAUKP.js";
31
28
  import {
32
29
  SLACK_REPLY_FORMATTING,
33
30
  addWorkspace,
@@ -50,7 +47,7 @@ import {
50
47
  stageAbsolutePathsAsAttachments,
51
48
  stageBuffersAsAttachments,
52
49
  syncWorkspacesFromThreads
53
- } from "./chunk-HA4EZKFY.js";
50
+ } from "./chunk-3S2LDD2F.js";
54
51
  import {
55
52
  addPrStackLayer,
56
53
  allocateTeamName,
@@ -100,7 +97,7 @@ import {
100
97
  worktreeDisplayLabelForGroup,
101
98
  worktreeNameFromPath,
102
99
  worktreeSlugForTicket
103
- } from "./chunk-OP6CFVTB.js";
100
+ } from "./chunk-ZZNZX2QW.js";
104
101
  import {
105
102
  ATTACHMENTS_DIR,
106
103
  DETACHED_JOBS_DIR,
@@ -134,19 +131,28 @@ import {
134
131
  turnFailChatText
135
132
  } from "./chunk-JZHRZ3DR.js";
136
133
  import {
134
+ HISTORY_CLEANUP_INTERVAL_HOURS_DEFAULT,
135
+ applyTurnUsage,
137
136
  assertOrchestratorCapableAgent,
137
+ autoCleanupHistoryEnabled,
138
138
  childEnvWithAppSettings,
139
139
  coerceOrchestratorAgent,
140
+ contextTokens,
140
141
  followUpBehavior,
141
142
  formatViewerContextDirective,
142
143
  formatViewerContextReminder,
143
144
  getIssueSource,
145
+ historyMaxCount,
146
+ historyMaxDays,
147
+ historyRetentionStubMessage,
144
148
  isAbleTimeConnected,
145
149
  isLinearConnected,
146
150
  isOrchestratorCapableAgent,
147
151
  isSecureFileEncrypted,
148
152
  loadAppSettings,
149
153
  orchestrationQuotaFallbackAgent,
154
+ planHistoryAgePurge,
155
+ planHistoryRetention,
150
156
  readSecureJson,
151
157
  resolveEffectiveIssueSource,
152
158
  resolveNewThreadOptions,
@@ -154,10 +160,11 @@ import {
154
160
  resolveVaultKey,
155
161
  resolveViewerProfileForRepo,
156
162
  saveAppSettings,
163
+ sumUsageList,
157
164
  updateAdvancedSettings,
158
165
  usageOnLimit,
159
166
  writeSecureJson
160
- } from "./chunk-Y4CF7LHH.js";
167
+ } from "./chunk-L5CIEBLR.js";
161
168
  import {
162
169
  stripNestedElectronEnv
163
170
  } from "./chunk-4TR3HZFT.js";
@@ -182,7 +189,7 @@ import {
182
189
  updateThread,
183
190
  withThreadLock,
184
191
  writeThread
185
- } from "./chunk-7DKX5JLT.js";
192
+ } from "./chunk-FGTPRMPS.js";
186
193
  import {
187
194
  appDataDir,
188
195
  findConventionSetup,
@@ -476,7 +483,7 @@ async function continueSourceThread(threadId, prompt) {
476
483
  await continueOnReply(threadId, prompt);
477
484
  return;
478
485
  }
479
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-D4AQNF25.js");
486
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-ZBUXJCII.js");
480
487
  await getOrchestrator2().send(threadId, prompt);
481
488
  } catch {
482
489
  }
@@ -810,9 +817,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
810
817
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
811
818
  );
812
819
  }
813
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-5UUUNA4A.js");
820
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-LQZLTGFL.js");
814
821
  if (isGlobalThread2(thread)) {
815
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-WOTJQMD5.js");
822
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-GCITY3Q5.js");
816
823
  ensureGlobalCoordinatorCwd2(
817
824
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
818
825
  );
@@ -2592,6 +2599,69 @@ function worktreeCleanupSettings() {
2592
2599
  };
2593
2600
  }
2594
2601
 
2602
+ // src/store/history-cleanup.ts
2603
+ function stripArchivedTranscript(thread) {
2604
+ writeThread(
2605
+ {
2606
+ ...thread,
2607
+ attachments: [],
2608
+ pendingTurnAttachments: [],
2609
+ messages: [historyRetentionStubMessage(thread)]
2610
+ },
2611
+ { touch: false }
2612
+ );
2613
+ }
2614
+ function cleanupArchivedHistory(opts = {}) {
2615
+ const settings = loadAppSettings();
2616
+ if (!opts.force && opts.purgeOlderThanDays == null && !autoCleanupHistoryEnabled(settings)) {
2617
+ return { stripped: [], purged: [] };
2618
+ }
2619
+ const archived = listThreads({ includeArchived: true }).filter((t) => t.status === "archived");
2620
+ const nowMs = opts.nowMs ?? Date.now();
2621
+ const plan = opts.purgeOlderThanDays != null ? { stripIds: [], purgeIds: planHistoryAgePurge(archived, opts.purgeOlderThanDays, nowMs) } : planHistoryRetention(archived, {
2622
+ maxCount: opts.maxCount ?? historyMaxCount(settings),
2623
+ maxDays: opts.maxDays ?? historyMaxDays(settings),
2624
+ nowMs
2625
+ });
2626
+ const stripped = [];
2627
+ const purged = [];
2628
+ if (opts.dryRun) {
2629
+ return { stripped: plan.stripIds, purged: plan.purgeIds };
2630
+ }
2631
+ for (const id of plan.stripIds) {
2632
+ const thread = readThread(id);
2633
+ if (!thread || thread.status !== "archived") continue;
2634
+ try {
2635
+ stripArchivedTranscript(thread);
2636
+ stripped.push(id);
2637
+ } catch {
2638
+ }
2639
+ }
2640
+ for (const id of plan.purgeIds) {
2641
+ const thread = readThread(id);
2642
+ if (!thread || thread.status !== "archived") continue;
2643
+ try {
2644
+ deleteThreadRecord(id);
2645
+ purged.push(id);
2646
+ } catch {
2647
+ }
2648
+ }
2649
+ if (stripped.length > 0 || purged.length > 0) {
2650
+ updateAdvancedSettings({
2651
+ historyLastCleanupAt: new Date(nowMs).toISOString()
2652
+ });
2653
+ }
2654
+ return { stripped, purged };
2655
+ }
2656
+ function shouldRunHistoryCleanup(settings = loadAppSettings()) {
2657
+ if (!autoCleanupHistoryEnabled(settings)) return false;
2658
+ const intervalHours = settings.advanced.historyCleanupIntervalHours ?? HISTORY_CLEANUP_INTERVAL_HOURS_DEFAULT;
2659
+ const last = settings.advanced.historyLastCleanupAt;
2660
+ if (!last) return true;
2661
+ const elapsed = Date.now() - Date.parse(last);
2662
+ return Number.isFinite(elapsed) && elapsed >= intervalHours * 36e5;
2663
+ }
2664
+
2595
2665
  // src/git/apply-into-main.ts
2596
2666
  import { execa as execa3 } from "execa";
2597
2667
  async function applyThreadIntoMain(thread, opts) {
@@ -3808,7 +3878,7 @@ async function createThread(input, _onSetupLine) {
3808
3878
  });
3809
3879
  await requireAgent(resolved.agent);
3810
3880
  if (input.cowboy) {
3811
- const { cowboyModeEnabled } = await import("./app-settings-GJ6KDYEF.js");
3881
+ const { cowboyModeEnabled } = await import("./app-settings-2TN3WLZV.js");
3812
3882
  if (!cowboyModeEnabled()) {
3813
3883
  throw new Error(
3814
3884
  "Cowboy mode is off. Enable it in Settings \u2192 Advanced."
@@ -3866,7 +3936,7 @@ async function createThread(input, _onSetupLine) {
3866
3936
  let sourceIsFork = false;
3867
3937
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
3868
3938
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
3869
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-I4IYZBKU.js");
3939
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-GDZLZRMY.js");
3870
3940
  const task = await ensureAbleTimeTask({
3871
3941
  title: title?.trim() || "Untitled work",
3872
3942
  description: input.prompt?.trim() || void 0
@@ -3968,7 +4038,7 @@ async function createThread(input, _onSetupLine) {
3968
4038
  return readThread(thread.id) ?? thread;
3969
4039
  }
3970
4040
  async function listLinearIssues(agent, repoPath) {
3971
- const { getAdapter: getAdapter2 } = await import("./agents-CCS5IEBV.js");
4041
+ const { getAdapter: getAdapter2 } = await import("./agents-IQZUN47D.js");
3972
4042
  await requireAgent(agent, { requireLinear: true });
3973
4043
  const adapter = getAdapter2(agent);
3974
4044
  if (!adapter.listLinearIssues) {
@@ -4414,7 +4484,7 @@ async function adoptThread(input) {
4414
4484
  messages: input.messages ?? []
4415
4485
  });
4416
4486
  writeThread(thread);
4417
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-PZ36M7EQ.js");
4487
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-2XW2DMRG.js");
4418
4488
  await ensureWorkspace2(repoPath);
4419
4489
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-X54WSOXM.js");
4420
4490
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -7020,7 +7090,7 @@ function formatScheduledPrompt(name, prompt) {
7020
7090
  ${prompt}`;
7021
7091
  }
7022
7092
  async function defaultDeps() {
7023
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-D4AQNF25.js");
7093
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-ZBUXJCII.js");
7024
7094
  const orch = getOrchestrator2();
7025
7095
  return {
7026
7096
  findThread: (id) => findThreadByRef(id),
@@ -7290,12 +7360,18 @@ var Orchestrator = class {
7290
7360
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
7291
7361
  });
7292
7362
  }
7293
- const { autoCleanupOrphansEnabled } = await import("./app-settings-GJ6KDYEF.js");
7363
+ const { autoCleanupOrphansEnabled } = await import("./app-settings-2TN3WLZV.js");
7294
7364
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
7295
7365
  await cleanupOrphanWorktrees({ repoPaths });
7296
7366
  }
7297
7367
  } catch {
7298
7368
  }
7369
+ try {
7370
+ if (shouldRunHistoryCleanup()) {
7371
+ cleanupArchivedHistory();
7372
+ }
7373
+ } catch {
7374
+ }
7299
7375
  if (drainQueues) {
7300
7376
  this.adoptPersistedQueues();
7301
7377
  }
@@ -7582,7 +7658,7 @@ var Orchestrator = class {
7582
7658
  }
7583
7659
  await setup;
7584
7660
  if (skipSetup) return;
7585
- const { autoRunAfterSetupEnabled } = await import("./app-settings-GJ6KDYEF.js");
7661
+ const { autoRunAfterSetupEnabled } = await import("./app-settings-2TN3WLZV.js");
7586
7662
  if (autoRunAfterSetupEnabled()) {
7587
7663
  try {
7588
7664
  await this.startDev(threadId);
@@ -7912,7 +7988,7 @@ var Orchestrator = class {
7912
7988
  }
7913
7989
  const isBrightsy = fresh.agent === "brightsy";
7914
7990
  const isOrchestration = isOrchestratorThread(fresh);
7915
- const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-GJ6KDYEF.js");
7991
+ const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-2TN3WLZV.js");
7916
7992
  const gitAuthMode = getGithubGitAuthMode();
7917
7993
  const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
7918
7994
  githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
@@ -8624,6 +8700,20 @@ var Orchestrator = class {
8624
8700
  repoPaths
8625
8701
  });
8626
8702
  }
8703
+ /** Bound Settings → History. After archive always; reconcile is interval-gated. */
8704
+ enforceHistoryRetention() {
8705
+ try {
8706
+ cleanupArchivedHistory();
8707
+ } catch {
8708
+ }
8709
+ }
8710
+ cleanupHistory(opts) {
8711
+ return cleanupArchivedHistory({
8712
+ dryRun: opts?.dryRun,
8713
+ purgeOlderThanDays: opts?.purgeOlderThanDays,
8714
+ force: opts?.force
8715
+ });
8716
+ }
8627
8717
  /**
8628
8718
  * Best-of-n / fanout: create N threads (one per agent) with the same prompt.
8629
8719
  */
@@ -8930,7 +9020,7 @@ var Orchestrator = class {
8930
9020
  if (!titled.userSetTitle && meta.title && titled.title !== meta.title) {
8931
9021
  updateThread(thread.id, { title: meta.title });
8932
9022
  }
8933
- const { autoArchiveOnMergeEnabled } = await import("./app-settings-GJ6KDYEF.js");
9023
+ const { autoArchiveOnMergeEnabled } = await import("./app-settings-2TN3WLZV.js");
8934
9024
  const latest = this.requireThread(thread.id);
8935
9025
  if (!shouldAutoArchiveOnPrMerge({
8936
9026
  previousPrState: prevState || null,
@@ -9184,6 +9274,7 @@ var Orchestrator = class {
9184
9274
  if (isGlobalThread(thread)) {
9185
9275
  const archived2 = setStatus(thread.id, "archived");
9186
9276
  this.emit({ type: "status_changed", threadId: archived2.id, status: "archived" });
9277
+ this.enforceHistoryRetention();
9187
9278
  return archived2;
9188
9279
  }
9189
9280
  const siblings = threadsSharingWorktree(thread.worktreePath).filter((t) => t.id !== thread.id);
@@ -9205,9 +9296,10 @@ var Orchestrator = class {
9205
9296
  }
9206
9297
  const archived = setStatus(thread.id, "archived");
9207
9298
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
9299
+ this.enforceHistoryRetention();
9208
9300
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
9209
9301
  try {
9210
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-PZ36M7EQ.js");
9302
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-2XW2DMRG.js");
9211
9303
  await ensureWorkspace2(thread.repoPath);
9212
9304
  } catch {
9213
9305
  }
@@ -9234,7 +9326,7 @@ var Orchestrator = class {
9234
9326
  await runArchiveScript(thread.repoPath, thread.worktreePath);
9235
9327
  } catch {
9236
9328
  }
9237
- const { deleteBranchOnPurgeEnabled } = await import("./app-settings-GJ6KDYEF.js");
9329
+ const { deleteBranchOnPurgeEnabled } = await import("./app-settings-2TN3WLZV.js");
9238
9330
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
9239
9331
  await removeWorktree(thread.repoPath, thread.worktreePath, {
9240
9332
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -9261,7 +9353,7 @@ var Orchestrator = class {
9261
9353
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
9262
9354
  );
9263
9355
  }
9264
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-NC4XQNQI.js");
9356
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-5ZGWKKZ6.js");
9265
9357
  const slug = thread.worktreePath.split("/").pop();
9266
9358
  const dest = thread.worktreePath;
9267
9359
  await withRepoGitLock(thread.repoPath, async () => {
@@ -9371,7 +9463,7 @@ async function startOrchestration(opts) {
9371
9463
  sourceRef: "default",
9372
9464
  ...createOpts
9373
9465
  }).catch(async () => {
9374
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-NC4XQNQI.js");
9466
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-5ZGWKKZ6.js");
9375
9467
  const repo = await resolveRepoRoot2(repoPath);
9376
9468
  const def = await resolveDefaultBranch2(repo);
9377
9469
  return orch.createThread({
@@ -9381,7 +9473,7 @@ async function startOrchestration(opts) {
9381
9473
  repoPath: repo
9382
9474
  });
9383
9475
  });
9384
- const { updateThread: upd } = await import("./thread-store-ESZYZSVC.js");
9476
+ const { updateThread: upd } = await import("./thread-store-KMZRQEPY.js");
9385
9477
  const updated = upd(thread.id, {
9386
9478
  sourceType: "orchestration",
9387
9479
  sourceRef: goal
@@ -9540,6 +9632,8 @@ export {
9540
9632
  cleanupOrphanWorktrees,
9541
9633
  shouldRunWorktreeCleanup,
9542
9634
  worktreeCleanupSettings,
9635
+ cleanupArchivedHistory,
9636
+ shouldRunHistoryCleanup,
9543
9637
  applyThreadIntoMain,
9544
9638
  cloneRepoIntoSideboard,
9545
9639
  mcpWaitForTurnTimeoutMs,
@@ -383,6 +383,167 @@ function normalizeVault(raw) {
383
383
  return out;
384
384
  }
385
385
 
386
+ // src/agents/usage.ts
387
+ function sumOptional(a, b) {
388
+ if (a == null && b == null) return void 0;
389
+ return (a ?? 0) + (b ?? 0);
390
+ }
391
+ function fromInclusiveInputUsage(opts) {
392
+ const totalInput = Number(opts.inputTokens) || 0;
393
+ const outputTokens = Number(opts.outputTokens) || 0;
394
+ const cached = Number(opts.cachedInputTokens) || 0;
395
+ if (!totalInput && !outputTokens) return null;
396
+ const cacheReadTokens = cached > 0 ? Math.min(cached, totalInput) : 0;
397
+ return {
398
+ inputTokens: Math.max(0, totalInput - cacheReadTokens),
399
+ outputTokens,
400
+ cacheReadTokens: cacheReadTokens || void 0
401
+ };
402
+ }
403
+ function requestOccupancy(u) {
404
+ return u.inputTokens + (u.cacheReadTokens ?? 0) + (u.cacheWriteTokens ?? 0);
405
+ }
406
+ function mergeUsage(a, b) {
407
+ return {
408
+ inputTokens: (a?.inputTokens ?? 0) + b.inputTokens,
409
+ outputTokens: (a?.outputTokens ?? 0) + b.outputTokens,
410
+ cacheReadTokens: sumOptional(a?.cacheReadTokens, b.cacheReadTokens),
411
+ cacheWriteTokens: sumOptional(a?.cacheWriteTokens, b.cacheWriteTokens),
412
+ costUsd: sumOptional(a?.costUsd, b.costUsd),
413
+ lastRequestTokens: b.lastRequestTokens ?? a?.lastRequestTokens
414
+ };
415
+ }
416
+ function sumUsageList(list) {
417
+ let acc = null;
418
+ for (const u of list) {
419
+ if (!u) continue;
420
+ acc = mergeUsage(acc, {
421
+ inputTokens: u.inputTokens,
422
+ outputTokens: u.outputTokens,
423
+ cacheReadTokens: u.cacheReadTokens,
424
+ cacheWriteTokens: u.cacheWriteTokens,
425
+ costUsd: u.costUsd
426
+ });
427
+ }
428
+ if (!acc) return null;
429
+ return {
430
+ inputTokens: acc.inputTokens,
431
+ outputTokens: acc.outputTokens,
432
+ ...acc.cacheReadTokens != null ? { cacheReadTokens: acc.cacheReadTokens } : {},
433
+ ...acc.cacheWriteTokens != null ? { cacheWriteTokens: acc.cacheWriteTokens } : {},
434
+ ...acc.costUsd != null ? { costUsd: acc.costUsd } : {}
435
+ };
436
+ }
437
+ function hasBilledTokens(u) {
438
+ return Boolean(
439
+ u.inputTokens || u.outputTokens || u.cacheReadTokens || u.cacheWriteTokens
440
+ );
441
+ }
442
+ function applyTurnUsage(current, incoming, scope = "request") {
443
+ if (scope === "turn") {
444
+ if (!hasBilledTokens(incoming) && current && incoming.costUsd != null) {
445
+ return { ...current, costUsd: incoming.costUsd };
446
+ }
447
+ return {
448
+ ...incoming,
449
+ costUsd: incoming.costUsd ?? current?.costUsd,
450
+ lastRequestTokens: current?.lastRequestTokens ?? requestOccupancy(incoming)
451
+ };
452
+ }
453
+ const merged = mergeUsage(current, incoming);
454
+ const occ = incoming.lastRequestTokens != null && incoming.lastRequestTokens > 0 ? incoming.lastRequestTokens : requestOccupancy(incoming);
455
+ return {
456
+ ...merged,
457
+ lastRequestTokens: occ > 0 ? occ : current?.lastRequestTokens ?? occ
458
+ };
459
+ }
460
+ function contextTokens(u) {
461
+ if (u.lastRequestTokens != null && u.lastRequestTokens > 0) return u.lastRequestTokens;
462
+ return requestOccupancy(u);
463
+ }
464
+
465
+ // src/store/history-retention.ts
466
+ var HISTORY_MAX_COUNT_DEFAULT = 200;
467
+ var HISTORY_MAX_COUNT_MIN = 1;
468
+ var HISTORY_MAX_COUNT_MAX = 2e3;
469
+ var HISTORY_MAX_DAYS_DEFAULT = 0;
470
+ var HISTORY_MAX_DAYS_MAX = 3650;
471
+ var HISTORY_CLEANUP_INTERVAL_HOURS_DEFAULT = 6;
472
+ var HISTORY_DISCARDED_TEXT = "Transcript discarded by History retention.";
473
+ function clampHistoryMaxCount(value) {
474
+ return Math.max(HISTORY_MAX_COUNT_MIN, Math.min(HISTORY_MAX_COUNT_MAX, Math.floor(value)));
475
+ }
476
+ function clampHistoryMaxDays(value) {
477
+ if (!Number.isFinite(value) || value <= 0) return 0;
478
+ return Math.min(HISTORY_MAX_DAYS_MAX, Math.floor(value));
479
+ }
480
+ function archivedUpdatedMs(thread) {
481
+ const stamped = thread.archivedAt ? Date.parse(thread.archivedAt) : NaN;
482
+ if (Number.isFinite(stamped)) return stamped;
483
+ const updated = Date.parse(thread.updatedAt);
484
+ if (Number.isFinite(updated)) return updated;
485
+ const created = Date.parse(thread.createdAt);
486
+ return Number.isFinite(created) ? created : 0;
487
+ }
488
+ function isHistoryRetentionStub(thread) {
489
+ if ((thread.attachments?.length ?? 0) > 0) return false;
490
+ const messages = thread.messages ?? [];
491
+ if (messages.length === 0) return true;
492
+ if (messages.length > 1) return false;
493
+ const only = messages[0];
494
+ if (only.parts?.length) return false;
495
+ if ((only.attachments?.length ?? 0) > 0) return false;
496
+ const text = (only.text ?? "").trim();
497
+ return text === "" || text === HISTORY_DISCARDED_TEXT;
498
+ }
499
+ function historyRetentionStubMessage(thread) {
500
+ const usage = sumUsageList((thread.messages ?? []).map((m) => m.usage));
501
+ return {
502
+ role: "summary",
503
+ text: HISTORY_DISCARDED_TEXT,
504
+ ts: thread.updatedAt,
505
+ ...usage ? { usage } : {}
506
+ };
507
+ }
508
+ function sortArchivedOldestFirst(threads) {
509
+ return [...threads].sort((a, b) => archivedUpdatedMs(a) - archivedUpdatedMs(b));
510
+ }
511
+ function planHistoryRetention(archived, thresholds = {}) {
512
+ const maxCount = clampHistoryMaxCount(thresholds.maxCount ?? HISTORY_MAX_COUNT_DEFAULT);
513
+ const maxDays = clampHistoryMaxDays(thresholds.maxDays ?? HISTORY_MAX_DAYS_DEFAULT);
514
+ const nowMs = thresholds.nowMs ?? Date.now();
515
+ const oldestFirst = sortArchivedOldestFirst(archived);
516
+ const expiredIds = /* @__PURE__ */ new Set();
517
+ if (maxDays > 0) {
518
+ const cutoff = nowMs - maxDays * 864e5;
519
+ for (const thread of oldestFirst) {
520
+ if (archivedUpdatedMs(thread) < cutoff) expiredIds.add(thread.id);
521
+ }
522
+ }
523
+ const remaining = oldestFirst.filter((t) => !expiredIds.has(t.id));
524
+ const overflow = remaining.length > maxCount ? remaining.slice(0, remaining.length - maxCount) : [];
525
+ const stripIds = [];
526
+ const purgeIds = [...expiredIds];
527
+ const seenPurge = new Set(purgeIds);
528
+ for (const thread of overflow) {
529
+ if (isHistoryRetentionStub(thread)) {
530
+ if (!seenPurge.has(thread.id)) {
531
+ seenPurge.add(thread.id);
532
+ purgeIds.push(thread.id);
533
+ }
534
+ } else {
535
+ stripIds.push(thread.id);
536
+ }
537
+ }
538
+ return { stripIds, purgeIds };
539
+ }
540
+ function planHistoryAgePurge(archived, olderThanDays, nowMs = Date.now()) {
541
+ const days = clampHistoryMaxDays(olderThanDays);
542
+ if (days <= 0) return [];
543
+ const cutoff = nowMs - days * 864e5;
544
+ return sortArchivedOldestFirst(archived).filter((t) => archivedUpdatedMs(t) < cutoff).map((t) => t.id);
545
+ }
546
+
386
547
  // src/store/usage-on-limit.ts
387
548
  var USAGE_ON_LIMIT_VALUES = [
388
549
  "keep_going",
@@ -843,6 +1004,24 @@ function normalizeAdvanced(raw) {
843
1004
  if (typeof source.autoCleanupOrphans === "boolean") {
844
1005
  out.autoCleanupOrphans = source.autoCleanupOrphans;
845
1006
  }
1007
+ if (typeof source.autoCleanupHistory === "boolean") {
1008
+ out.autoCleanupHistory = source.autoCleanupHistory;
1009
+ }
1010
+ if (typeof source.historyMaxCount === "number" && Number.isFinite(source.historyMaxCount)) {
1011
+ out.historyMaxCount = clampHistoryMaxCount(source.historyMaxCount);
1012
+ }
1013
+ if (typeof source.historyMaxDays === "number" && Number.isFinite(source.historyMaxDays)) {
1014
+ out.historyMaxDays = clampHistoryMaxDays(source.historyMaxDays);
1015
+ }
1016
+ if (typeof source.historyCleanupIntervalHours === "number" && Number.isFinite(source.historyCleanupIntervalHours)) {
1017
+ out.historyCleanupIntervalHours = Math.max(
1018
+ 1,
1019
+ Math.min(168, Math.floor(source.historyCleanupIntervalHours))
1020
+ );
1021
+ }
1022
+ if (typeof source.historyLastCleanupAt === "string" && source.historyLastCleanupAt.trim()) {
1023
+ out.historyLastCleanupAt = source.historyLastCleanupAt.trim();
1024
+ }
846
1025
  if (source.orchestrationQuotaOnLimit === "switch_agent" || source.orchestrationQuotaOnLimit === "wait_reset") {
847
1026
  out.orchestrationQuotaOnLimit = source.orchestrationQuotaOnLimit;
848
1027
  }
@@ -1748,6 +1927,24 @@ function updateAdvancedSettings(patch) {
1748
1927
  if (typeof patch.autoCleanupOrphans === "boolean") {
1749
1928
  advanced.autoCleanupOrphans = patch.autoCleanupOrphans;
1750
1929
  }
1930
+ if (typeof patch.autoCleanupHistory === "boolean") {
1931
+ advanced.autoCleanupHistory = patch.autoCleanupHistory;
1932
+ }
1933
+ if (typeof patch.historyMaxCount === "number" && Number.isFinite(patch.historyMaxCount)) {
1934
+ advanced.historyMaxCount = clampHistoryMaxCount(patch.historyMaxCount);
1935
+ }
1936
+ if (typeof patch.historyMaxDays === "number" && Number.isFinite(patch.historyMaxDays)) {
1937
+ advanced.historyMaxDays = clampHistoryMaxDays(patch.historyMaxDays);
1938
+ }
1939
+ if (typeof patch.historyCleanupIntervalHours === "number" && Number.isFinite(patch.historyCleanupIntervalHours)) {
1940
+ advanced.historyCleanupIntervalHours = Math.max(
1941
+ 1,
1942
+ Math.min(168, Math.floor(patch.historyCleanupIntervalHours))
1943
+ );
1944
+ }
1945
+ if (typeof patch.historyLastCleanupAt === "string") {
1946
+ advanced.historyLastCleanupAt = patch.historyLastCleanupAt;
1947
+ }
1751
1948
  if (patch.orchestrationQuotaOnLimit === "switch_agent" || patch.orchestrationQuotaOnLimit === "wait_reset") {
1752
1949
  advanced.orchestrationQuotaOnLimit = patch.orchestrationQuotaOnLimit;
1753
1950
  }
@@ -1798,6 +1995,15 @@ function autoArchiveOnMergeEnabled(settings = loadAppSettings()) {
1798
1995
  function autoCleanupOrphansEnabled(settings = loadAppSettings()) {
1799
1996
  return Boolean(settings.advanced.autoCleanupOrphans);
1800
1997
  }
1998
+ function autoCleanupHistoryEnabled(settings = loadAppSettings()) {
1999
+ return settings.advanced.autoCleanupHistory !== false;
2000
+ }
2001
+ function historyMaxCount(settings = loadAppSettings()) {
2002
+ return clampHistoryMaxCount(settings.advanced.historyMaxCount ?? HISTORY_MAX_COUNT_DEFAULT);
2003
+ }
2004
+ function historyMaxDays(settings = loadAppSettings()) {
2005
+ return clampHistoryMaxDays(settings.advanced.historyMaxDays ?? HISTORY_MAX_DAYS_DEFAULT);
2006
+ }
1801
2007
  function usageOnLimit(settings = loadAppSettings()) {
1802
2008
  return resolveUsageOnLimit(settings.advanced);
1803
2009
  }
@@ -1932,6 +2138,14 @@ export {
1932
2138
  formatWorkspaceProfileSuffix,
1933
2139
  formatViewerContextDirective,
1934
2140
  formatViewerContextReminder,
2141
+ fromInclusiveInputUsage,
2142
+ sumUsageList,
2143
+ applyTurnUsage,
2144
+ contextTokens,
2145
+ HISTORY_CLEANUP_INTERVAL_HOURS_DEFAULT,
2146
+ historyRetentionStubMessage,
2147
+ planHistoryRetention,
2148
+ planHistoryAgePurge,
1935
2149
  USAGE_ON_LIMIT_VALUES,
1936
2150
  isUsageOnLimit,
1937
2151
  resolveUsageOnLimit,
@@ -2001,6 +2215,9 @@ export {
2001
2215
  confirmClaudeUsageOverLimitEnabled,
2002
2216
  autoArchiveOnMergeEnabled,
2003
2217
  autoCleanupOrphansEnabled,
2218
+ autoCleanupHistoryEnabled,
2219
+ historyMaxCount,
2220
+ historyMaxDays,
2004
2221
  usageOnLimit,
2005
2222
  orchestrationQuotaOnLimit,
2006
2223
  orchestrationQuotaFallbackAgent,
@@ -1,3 +1,6 @@
1
+ import {
2
+ cursorSdkStoreDir
3
+ } from "./chunk-7J72QJOM.js";
1
4
  import {
2
5
  normalizeThinkingEffort
3
6
  } from "./chunk-77WWLBCI.js";
@@ -13,6 +16,7 @@ import {
13
16
  existsSync,
14
17
  readFileSync,
15
18
  renameSync,
19
+ rmSync,
16
20
  statSync,
17
21
  unlinkSync,
18
22
  writeFileSync,
@@ -52,7 +56,8 @@ function normalizeThread(raw) {
52
56
  userSetTitle: Boolean(raw.userSetTitle),
53
57
  activeRuns: Array.isArray(raw.activeRuns) ? raw.activeRuns : [],
54
58
  quotaResumeAt: raw.quotaResumeAt ?? null,
55
- quotaContinuedFromId: raw.quotaContinuedFromId ?? null
59
+ quotaContinuedFromId: raw.quotaContinuedFromId ?? null,
60
+ archivedAt: typeof raw.archivedAt === "string" && raw.archivedAt.trim() ? raw.archivedAt.trim() : void 0
56
61
  };
57
62
  }
58
63
  function createEmptyThread(partial) {
@@ -87,6 +92,7 @@ function createEmptyThread(partial) {
87
92
  pendingTurnAttachments: partial.pendingTurnAttachments ?? [],
88
93
  createdAt: ts,
89
94
  updatedAt: ts,
95
+ archivedAt: typeof partial.archivedAt === "string" && partial.archivedAt.trim() ? partial.archivedAt.trim() : void 0,
90
96
  title: partial.title,
91
97
  sourceType: partial.sourceType,
92
98
  sourceRef: partial.sourceRef,
@@ -159,10 +165,10 @@ function readThread(id) {
159
165
  rememberThread(thread, mtimeMs);
160
166
  return thread;
161
167
  }
162
- function writeThread(thread) {
168
+ function writeThread(thread, opts) {
163
169
  const path = threadFilePath(idPath(thread.id));
164
170
  const tmp = `${path}.${process.pid}.tmp`;
165
- const next = { ...thread, updatedAt: nowIso() };
171
+ const next = opts?.touch === false ? { ...thread } : { ...thread, updatedAt: nowIso() };
166
172
  writeFileSync(tmp, JSON.stringify(next, null, 2), "utf8");
167
173
  renameSync(tmp, path);
168
174
  rememberThread(next, fileMtimeMs(path) ?? Date.now());
@@ -207,11 +213,20 @@ function deleteThreadRecord(id) {
207
213
  } catch {
208
214
  }
209
215
  }
216
+ try {
217
+ rmSync(cursorSdkStoreDir(id), { recursive: true, force: true });
218
+ } catch {
219
+ }
210
220
  }
211
221
  function updateThread(id, patch) {
212
222
  const current = readThread(id);
213
223
  if (!current) throw new Error(`Thread not found: ${id}`);
214
224
  const next = { ...current, ...patch, id: current.id, updatedAt: nowIso() };
225
+ if (next.status === "archived") {
226
+ next.archivedAt = typeof next.archivedAt === "string" && next.archivedAt.trim() || current.archivedAt || nowIso();
227
+ } else {
228
+ delete next.archivedAt;
229
+ }
215
230
  writeThread(next);
216
231
  return next;
217
232
  }