@p4code/cli 0.0.50 → 0.0.52

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 (88) hide show
  1. package/dist/bin.mjs +508 -11
  2. package/dist/client/assets/{DiffPanel-BUvVWIMX.js → DiffPanel-wkFFgH2M.js} +3 -3
  3. package/dist/client/assets/{FilePreviewPanel-Bk7x7hMd.js → FilePreviewPanel-D0sXtk7J.js} +5 -5
  4. package/dist/client/assets/PreviewPanel-BKcBSqy8.js +2 -0
  5. package/dist/client/assets/{angular-html-CvITUhcj.js → angular-html-SfFqn_n1.js} +2 -2
  6. package/dist/client/assets/{angular-ts-CI8oh2Bi.js → angular-ts-TqTMcSgN.js} +2 -2
  7. package/dist/client/assets/{apl-BewkNmrv.js → apl-DvTVLZcC.js} +2 -2
  8. package/dist/client/assets/arrow-right-BHEVGFLQ.js +2 -0
  9. package/dist/client/assets/{astro-CNN681lo.js → astro-DEpzE1sb.js} +2 -2
  10. package/dist/client/assets/{blade-X4RszKFf.js → blade-Brgi-xhV.js} +2 -2
  11. package/dist/client/assets/{c-C8AJe2jK.js → c-7H0fCJJT.js} +2 -2
  12. package/dist/client/assets/{cobol-DQjALrRk.js → cobol-Cq_E3Ld9.js} +2 -2
  13. package/dist/client/assets/{coffee-uHbL69mO.js → coffee-DpUX5Xcz.js} +2 -2
  14. package/dist/client/assets/{cpp-D3rb3O4A.js → cpp-BEjZmHLc.js} +2 -2
  15. package/dist/client/assets/{crystal-spyqFjYj.js → crystal-CycEJw4X.js} +2 -2
  16. package/dist/client/assets/{css-CbxXkRaq.js → css-y3Oj4fDi.js} +2 -2
  17. package/dist/client/assets/{edge-YESgrh6X.js → edge-DIFYHFsA.js} +2 -2
  18. package/dist/client/assets/{elixir-7069ioPL.js → elixir-raLzjUMQ.js} +2 -2
  19. package/dist/client/assets/{elm-Eb4zNBLt.js → elm-CZsXcOy1.js} +2 -2
  20. package/dist/client/assets/{erb-Ddb27xlO.js → erb-DhXjIste.js} +2 -2
  21. package/dist/client/assets/{fileCommentAnnotations-OW7TQ0uO.js → fileCommentAnnotations-CzUv-k6P.js} +2 -2
  22. package/dist/client/assets/{git-rebase-CdERns2w.js → git-rebase-CZvi6-AX.js} +2 -2
  23. package/dist/client/assets/{glimmer-js-C6s5Isxr.js → glimmer-js-N_UF0Pmi.js} +2 -2
  24. package/dist/client/assets/{glimmer-ts-BV7NBmEc.js → glimmer-ts-Cxd1tQNi.js} +2 -2
  25. package/dist/client/assets/{glsl-jd9QEV4q.js → glsl-B8RUupmi.js} +2 -2
  26. package/dist/client/assets/{graphql-CXqIl6Zm.js → graphql-Cz2mi8GF.js} +2 -2
  27. package/dist/client/assets/{hack-lLvPp6HR.js → hack-DD3q-ECT.js} +2 -2
  28. package/dist/client/assets/{haml-DfPUmRcz.js → haml-C75rIu1p.js} +2 -2
  29. package/dist/client/assets/{handlebars-QzjSM_We.js → handlebars-C1zz9h1i.js} +2 -2
  30. package/dist/client/assets/{html-derivative-CkX2Wmz3.js → html-derivative-HEAA-Z2a.js} +2 -2
  31. package/dist/client/assets/{html-BySpIsKh.js → html-mXOatteF.js} +2 -2
  32. package/dist/client/assets/{http-CD7dw1li.js → http-DO0ZHyk0.js} +2 -2
  33. package/dist/client/assets/{hurl-nzp7hSsy.js → hurl-DyDQ6Iuv.js} +2 -2
  34. package/dist/client/assets/index-4lXVitrP.js +663 -0
  35. package/dist/client/assets/index-C7UXI10J.css +1 -0
  36. package/dist/client/assets/{java-D2TcotRb.js → java-DicQ_x8H.js} +2 -2
  37. package/dist/client/assets/{javascript-CpW0WD7L.js → javascript-CTx-kiCR.js} +2 -2
  38. package/dist/client/assets/{jinja-BL1anCEN.js → jinja-ERQPZ9pQ.js} +2 -2
  39. package/dist/client/assets/{jison-B-sCtmJb.js → jison-BEedW5zW.js} +2 -2
  40. package/dist/client/assets/{json-BXeO84aE.js → json-MMdgCPnh.js} +2 -2
  41. package/dist/client/assets/{jsx-CgueyhKv.js → jsx-CJ--w_e-.js} +2 -2
  42. package/dist/client/assets/{julia-PMog-fIJ.js → julia-BvGAE4O0.js} +2 -2
  43. package/dist/client/assets/{just-Bi73ZAuY.js → just-BvBn61hL.js} +2 -2
  44. package/dist/client/assets/{latex-D6Hw5PyK.js → latex-P2_b6CEl.js} +2 -2
  45. package/dist/client/assets/{liquid-CuvsknsU.js → liquid-Dm2xzeBN.js} +2 -2
  46. package/dist/client/assets/{lua-6tqLQzzk.js → lua-DYQLFKMA.js} +2 -2
  47. package/dist/client/assets/{marko-Bv1DHr8G.js → marko-DCc0fplW.js} +2 -2
  48. package/dist/client/assets/{mdc-DIKkjN2a.js → mdc-BI6uqWRL.js} +2 -2
  49. package/dist/client/assets/{nginx-B2JFBlIu.js → nginx-ijGdX1bh.js} +2 -2
  50. package/dist/client/assets/{nim-D8qC29Zr.js → nim-CUp-JGxu.js} +2 -2
  51. package/dist/client/assets/{perl-De_VpaHg.js → perl-BKpwnNRr.js} +2 -2
  52. package/dist/client/assets/{php-zSI5z7ZS.js → php-DDStFT9W.js} +2 -2
  53. package/dist/client/assets/{pug-rUGxU82h.js → pug-HXcSxf00.js} +2 -2
  54. package/dist/client/assets/{qml-CXAY6cUl.js → qml-CbzgrBYo.js} +2 -2
  55. package/dist/client/assets/{r-Cm15VoHH.js → r-CgMrZP2h.js} +2 -2
  56. package/dist/client/assets/{razor-DkcxdUAy.js → razor-0ZAHbKMz.js} +2 -2
  57. package/dist/client/assets/{regexp-BOilP6p2.js → regexp-Bzi1hKAb.js} +2 -2
  58. package/dist/client/assets/{rst-BfN2oPCh.js → rst-qWyAhT77.js} +2 -2
  59. package/dist/client/assets/{ruby-B1jLvIIs.js → ruby-LCEp4zKA.js} +2 -2
  60. package/dist/client/assets/{sas-CF03ALyS.js → sas-BFhxcd3b.js} +2 -2
  61. package/dist/client/assets/{scss-BrFzdYUJ.js → scss-BK0-84uz.js} +2 -2
  62. package/dist/client/assets/{shellscript-B_6ownRV.js → shellscript-CyZVCH9y.js} +2 -2
  63. package/dist/client/assets/{shellsession-D9grZ02W.js → shellsession-BMyVGgke.js} +2 -2
  64. package/dist/client/assets/{soy-Ca44AVp-.js → soy-C5EqpU05.js} +2 -2
  65. package/dist/client/assets/{sql-CkHELsvP.js → sql-D51Kht_s.js} +2 -2
  66. package/dist/client/assets/{stata-C9ALGlol.js → stata-ClgcFk9O.js} +2 -2
  67. package/dist/client/assets/{surrealql-Cta1X2o7.js → surrealql-DcFIgIgS.js} +2 -2
  68. package/dist/client/assets/{svelte-BogBuioE.js → svelte-5uir_iV_.js} +2 -2
  69. package/dist/client/assets/{templ-C4v7sOsC.js → templ-IHhNUhu5.js} +2 -2
  70. package/dist/client/assets/{tex-KXY3LBOg.js → tex-DbjEQBr6.js} +2 -2
  71. package/dist/client/assets/textarea-C6kz4NLj.js +46 -0
  72. package/dist/client/assets/{ts-tags-BUzdov0d.js → ts-tags-xML8Swir.js} +2 -2
  73. package/dist/client/assets/{tsx-DCEZNbvU.js → tsx-BwMUW3gO.js} +2 -2
  74. package/dist/client/assets/{twig-lX5bLK2U.js → twig-BRlCEyLn.js} +2 -2
  75. package/dist/client/assets/{typescript-D0XyCzdv.js → typescript-DC1qlCSF.js} +2 -2
  76. package/dist/client/assets/{vue-BVUKhxXR.js → vue-Cta_ijHF.js} +2 -2
  77. package/dist/client/assets/{vue-html-BFZ9Hu9Q.js → vue-html-C6cjjUjR.js} +2 -2
  78. package/dist/client/assets/{vue-vine-DwK9p9S2.js → vue-vine-DMiSqDlT.js} +2 -2
  79. package/dist/client/assets/{xml-BZnktucc.js → xml-DJpzo_Kg.js} +2 -2
  80. package/dist/client/assets/{xsl-BQvXVv3K.js → xsl-DAqFroi4.js} +2 -2
  81. package/dist/client/assets/{yaml-CjmvH72q.js → yaml-Brab7tCG.js} +2 -2
  82. package/dist/client/index.html +3 -3
  83. package/package.json +1 -1
  84. package/dist/client/assets/PreviewPanel-CR9iyxF2.js +0 -2
  85. package/dist/client/assets/arrow-right-BG7cUHWK.js +0 -2
  86. package/dist/client/assets/index-C0FwegCm.css +0 -1
  87. package/dist/client/assets/index-CHboeMs4.js +0 -640
  88. package/dist/client/assets/textarea-DHdA8g53.js +0 -46
package/dist/bin.mjs CHANGED
@@ -233,7 +233,7 @@ const make$72 = () => {
233
233
  const layer$68 = Layer.sync(NetService, make$72);
234
234
  //#endregion
235
235
  //#region package.json
236
- var version = "0.0.50";
236
+ var version = "0.0.52";
237
237
  //#endregion
238
238
  //#region src/config.ts
239
239
  /**
@@ -4819,6 +4819,87 @@ const ThreadMetadataUpdatedPayload = Schema$1.Struct({
4819
4819
  name: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
4820
4820
  metadata: Schema$1.optional(UnknownRecordSchema)
4821
4821
  });
4822
+ /**
4823
+ * Per-source attribution for what is occupying the context window, as reported
4824
+ * by a provider that can answer the question. Only the Claude adapter fills this
4825
+ * in today; every field is optional so a provider can report the parts it knows.
4826
+ *
4827
+ * `isDeferred` / `isLoaded` are the interesting half. Providers defer most tool
4828
+ * definitions behind tool search, so a deferred entry's tokens are what it
4829
+ * *would* cost rather than what it costs right now, and presenting the two as
4830
+ * one number overstates usage.
4831
+ */
4832
+ const ContextWindowNamedCost = Schema$1.Struct({
4833
+ name: TrimmedNonEmptyStringSchema$1,
4834
+ tokens: NonNegativeInt
4835
+ });
4836
+ const ContextWindowDeferrableTool = Schema$1.Struct({
4837
+ name: TrimmedNonEmptyStringSchema$1,
4838
+ tokens: NonNegativeInt,
4839
+ isLoaded: Schema$1.optional(Schema$1.Boolean)
4840
+ });
4841
+ const ContextWindowBreakdown = Schema$1.Struct({
4842
+ /** The model the breakdown was measured against, which is not always the thread's current selection. */
4843
+ model: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
4844
+ /** Top-level buckets the provider itself divides the window into. */
4845
+ categories: Schema$1.optional(Schema$1.Array(Schema$1.Struct({
4846
+ name: TrimmedNonEmptyStringSchema$1,
4847
+ tokens: NonNegativeInt,
4848
+ isDeferred: Schema$1.optional(Schema$1.Boolean)
4849
+ }))),
4850
+ mcpTools: Schema$1.optional(Schema$1.Array(Schema$1.Struct({
4851
+ name: TrimmedNonEmptyStringSchema$1,
4852
+ serverName: TrimmedNonEmptyStringSchema$1,
4853
+ tokens: NonNegativeInt,
4854
+ isLoaded: Schema$1.optional(Schema$1.Boolean)
4855
+ }))),
4856
+ skills: Schema$1.optional(Schema$1.Struct({
4857
+ totalSkills: NonNegativeInt,
4858
+ includedSkills: NonNegativeInt,
4859
+ tokens: NonNegativeInt,
4860
+ entries: Schema$1.optional(Schema$1.Array(Schema$1.Struct({
4861
+ name: TrimmedNonEmptyStringSchema$1,
4862
+ source: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
4863
+ tokens: NonNegativeInt
4864
+ })))
4865
+ })),
4866
+ memoryFiles: Schema$1.optional(Schema$1.Array(Schema$1.Struct({
4867
+ path: TrimmedNonEmptyStringSchema$1,
4868
+ type: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
4869
+ tokens: NonNegativeInt
4870
+ }))),
4871
+ agents: Schema$1.optional(Schema$1.Array(Schema$1.Struct({
4872
+ agentType: TrimmedNonEmptyStringSchema$1,
4873
+ source: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
4874
+ tokens: NonNegativeInt
4875
+ }))),
4876
+ systemTools: Schema$1.optional(Schema$1.Array(ContextWindowNamedCost)),
4877
+ deferredBuiltinTools: Schema$1.optional(Schema$1.Array(ContextWindowDeferrableTool)),
4878
+ systemPromptSections: Schema$1.optional(Schema$1.Array(ContextWindowNamedCost)),
4879
+ slashCommands: Schema$1.optional(Schema$1.Struct({
4880
+ totalCommands: NonNegativeInt,
4881
+ includedCommands: NonNegativeInt,
4882
+ tokens: NonNegativeInt
4883
+ })),
4884
+ /** How the conversation itself divides up, as opposed to the prompt scaffolding above. */
4885
+ messages: Schema$1.optional(Schema$1.Struct({
4886
+ toolCallTokens: NonNegativeInt,
4887
+ toolResultTokens: NonNegativeInt,
4888
+ attachmentTokens: NonNegativeInt,
4889
+ assistantMessageTokens: NonNegativeInt,
4890
+ userMessageTokens: NonNegativeInt,
4891
+ redirectedContextTokens: NonNegativeInt,
4892
+ unattributedTokens: NonNegativeInt,
4893
+ toolCallsByType: Schema$1.optional(Schema$1.Array(Schema$1.Struct({
4894
+ name: TrimmedNonEmptyStringSchema$1,
4895
+ callTokens: NonNegativeInt,
4896
+ resultTokens: NonNegativeInt
4897
+ }))),
4898
+ attachmentsByType: Schema$1.optional(Schema$1.Array(ContextWindowNamedCost))
4899
+ })),
4900
+ /** Token count at which the provider compacts on its own, when it does. */
4901
+ autoCompactThreshold: Schema$1.optional(NonNegativeInt)
4902
+ });
4822
4903
  const ThreadTokenUsageSnapshot = Schema$1.Struct({
4823
4904
  usedTokens: NonNegativeInt,
4824
4905
  totalProcessedTokens: Schema$1.optional(NonNegativeInt),
@@ -4834,7 +4915,8 @@ const ThreadTokenUsageSnapshot = Schema$1.Struct({
4834
4915
  lastReasoningOutputTokens: Schema$1.optional(NonNegativeInt),
4835
4916
  toolUses: Schema$1.optional(NonNegativeInt),
4836
4917
  durationMs: Schema$1.optional(NonNegativeInt),
4837
- compactsAutomatically: Schema$1.optional(Schema$1.Boolean)
4918
+ compactsAutomatically: Schema$1.optional(Schema$1.Boolean),
4919
+ breakdown: Schema$1.optional(ContextWindowBreakdown)
4838
4920
  });
4839
4921
  const ThreadTokenUsageUpdatedPayload = Schema$1.Struct({ usage: ThreadTokenUsageSnapshot });
4840
4922
  const ThreadRealtimeStartedPayload = Schema$1.Struct({ realtimeSessionId: Schema$1.optional(TrimmedNonEmptyStringSchema$1) });
@@ -7235,6 +7317,59 @@ const TaskStreamEvent = Schema$1.Union([
7235
7317
  taskId: TaskId
7236
7318
  })
7237
7319
  ]);
7320
+ /**
7321
+ * Start an agent on a task.
7322
+ *
7323
+ * The input is only the task, deliberately. Everything else the thread needs —
7324
+ * which project, which model, what prompt — is resolved server-side from the
7325
+ * task's own project, because the caller that matters next is not a person
7326
+ * clicking a button but Phase 12's orchestrator, and a client that supplies the
7327
+ * model is a client that can start a task on a provider the user does not use.
7328
+ *
7329
+ * Worktrees are absent for a harder reason: `prepareWorktree` needs a base
7330
+ * branch, a task carries none, and nothing resolves one server-side. A thread
7331
+ * started from a task therefore runs in the project's own checkout.
7332
+ */
7333
+ const TaskStartThreadInput = Schema$1.Struct({ taskId: TaskIdField });
7334
+ /**
7335
+ * The started thread and the task as it now stands.
7336
+ *
7337
+ * Both are returned because both changed: the caller navigates to the thread,
7338
+ * and the board would otherwise show the old status until the change event
7339
+ * arrived.
7340
+ */
7341
+ const TaskStartThreadResult = Schema$1.Struct({
7342
+ task: Task,
7343
+ threadId: ThreadId
7344
+ });
7345
+ /**
7346
+ * A task cannot be started, and the reason is a property of the task or the
7347
+ * server rather than a failure.
7348
+ *
7349
+ * Each reason is a different thing for the user to fix, which is why this is a
7350
+ * union and not one message. `no-model` is the one worth explaining: a task
7351
+ * carries no model selection, so the thread runs on the project's default. The
7352
+ * server-side fallback that exists for first-run bootstrap is deliberately not
7353
+ * used here — it hardcodes a provider, so reaching for it would silently start
7354
+ * someone who works in Claude on Codex. Failing is the honest answer.
7355
+ */
7356
+ const TaskNotStartableReason = Schema$1.Literals([
7357
+ "no-project",
7358
+ "project-missing",
7359
+ "no-model"
7360
+ ]);
7361
+ var TaskNotStartableError = class extends Schema$1.TaggedErrorClass()("TaskNotStartableError", {
7362
+ taskId: TaskId,
7363
+ reason: TaskNotStartableReason
7364
+ }) {
7365
+ get message() {
7366
+ switch (this.reason) {
7367
+ case "no-project": return "This task has no project, so there is nowhere to run it. Set a project on the task first.";
7368
+ case "project-missing": return "This task's project is not registered on this server. Point it at a project that is.";
7369
+ case "no-model": return "This task's project has no default model. Choose one in the project's settings, then start the task again.";
7370
+ }
7371
+ }
7372
+ };
7238
7373
  /** Result shape for the board's list RPC. */
7239
7374
  const TaskListResult$1 = Schema$1.Struct({ tasks: Schema$1.Array(Task) });
7240
7375
  /** Result shape for every RPC that resolves to a single task. */
@@ -8004,6 +8139,7 @@ const WS_METHODS = {
8004
8139
  tasksCreate: "tasks.create",
8005
8140
  tasksUpdate: "tasks.update",
8006
8141
  tasksDelete: "tasks.delete",
8142
+ tasksStartThread: "tasks.startThread",
8007
8143
  hubGetSyncStatus: "hub.getSyncStatus",
8008
8144
  hubConnect: "hub.connect",
8009
8145
  hubDisconnect: "hub.disconnect",
@@ -8078,6 +8214,30 @@ const WsTasksDeleteRpc = Rpc.make(WS_METHODS.tasksDelete, {
8078
8214
  error: TaskRpcError
8079
8215
  });
8080
8216
  /**
8217
+ * Start an agent on a task.
8218
+ *
8219
+ * This is the one task RPC that is not CRUD: it creates a thread, seeds it from
8220
+ * the task, and links the two. It lives in the `tasks.*` namespace because the
8221
+ * task is what it reads and writes — the thread is the side effect, not the
8222
+ * subject — and because the caller always names a task and never a thread.
8223
+ *
8224
+ * The error union is wider than the other task methods for the same reason. A
8225
+ * start can fail because the task is not startable, which is a property of the
8226
+ * row, or because the turn could not be dispatched, which is the orchestration
8227
+ * engine's own failure and already has a type.
8228
+ */
8229
+ const WsTasksStartThreadRpc = Rpc.make(WS_METHODS.tasksStartThread, {
8230
+ payload: TaskStartThreadInput,
8231
+ success: TaskStartThreadResult,
8232
+ error: Schema$1.Union([
8233
+ TaskNotFoundError,
8234
+ TaskNotStartableError,
8235
+ TaskStoreError,
8236
+ OrchestrationDispatchCommandError,
8237
+ EnvironmentAuthorizationError
8238
+ ])
8239
+ });
8240
+ /**
8081
8241
  * Hub link and skill sync.
8082
8242
  *
8083
8243
  * Every one of these answers with the whole status rather than an
@@ -8590,7 +8750,7 @@ const WsSubscribeAuthAccessRpc = Rpc.make(WS_METHODS.subscribeAuthAccess, {
8590
8750
  error: Schema$1.Union([AuthAccessStreamError, EnvironmentAuthorizationError]),
8591
8751
  stream: true
8592
8752
  });
8593
- const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
8753
+ const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
8594
8754
  //#endregion
8595
8755
  //#region ../../packages/shared/src/oauthScope.ts
8596
8756
  const OAUTH_SCOPE_TOKEN = /^[\u0021\u0023-\u005b\u005d-\u007e]+$/u;
@@ -30964,11 +31124,30 @@ function isResolvableContextWindowActivity(activity) {
30964
31124
  * newer updates still stream through and supersede the retained rows on the
30965
31125
  * client.
30966
31126
  */
31127
+ function withoutContextWindowBreakdown$1(activity) {
31128
+ const payload = asRecord$1(activity.payload);
31129
+ if (!payload || payload.breakdown === void 0) return activity;
31130
+ const { breakdown: _breakdown, ...rest } = payload;
31131
+ return {
31132
+ ...activity,
31133
+ payload: rest
31134
+ };
31135
+ }
30967
31136
  function dropStaleContextWindowActivities(activities) {
30968
31137
  const latestIndexByTurn = /* @__PURE__ */ new Map();
30969
31138
  for (let index = 0; index < activities.length; index += 1) if (isResolvableContextWindowActivity(activities[index])) latestIndexByTurn.set(activities[index].turnId, index);
30970
31139
  if (latestIndexByTurn.size === 0) return activities;
30971
- return activities.filter((activity, index) => !isResolvableContextWindowActivity(activity) || latestIndexByTurn.get(activity.turnId) === index);
31140
+ const retainedIndexes = new Set(latestIndexByTurn.values());
31141
+ let breakdownIndex = null;
31142
+ for (const index of retainedIndexes) {
31143
+ if (asRecord$1(activities[index].payload)?.breakdown === void 0) continue;
31144
+ if (breakdownIndex === null || index > breakdownIndex) breakdownIndex = index;
31145
+ }
31146
+ return activities.flatMap((activity, index) => {
31147
+ if (!isResolvableContextWindowActivity(activity)) return [activity];
31148
+ if (latestIndexByTurn.get(activity.turnId) !== index) return [];
31149
+ return [index === breakdownIndex ? activity : withoutContextWindowBreakdown$1(activity)];
31150
+ });
30972
31151
  }
30973
31152
  function projectThreadDetailSnapshot(snapshot) {
30974
31153
  return {
@@ -31116,6 +31295,39 @@ const resolveTaskRepositoryKey = Effect.fn("taskBoard.resolveRepositoryKey")(fun
31116
31295
  return (yield* (yield* RepositoryIdentityResolver).resolve(project.value.workspaceRoot))?.canonicalKey ?? null;
31117
31296
  });
31118
31297
  /**
31298
+ * Everything that decides whether a task can be started, as one pure function.
31299
+ *
31300
+ * Kept out of the RPC handler because the three refusals are the whole of the
31301
+ * interesting behaviour and each is a different thing for the user to fix,
31302
+ * while the handler around them is two store calls and a dispatch. Phase 12's
31303
+ * orchestrator has to make the same three decisions before it may claim a task,
31304
+ * and it should reach the same verdicts by calling this rather than by reading
31305
+ * the handler and reimplementing it.
31306
+ *
31307
+ * The project is passed in as the repository returns it — including soft-deleted
31308
+ * rows, which is why `deletedAt` is checked here rather than assumed away.
31309
+ */
31310
+ const resolveTaskStart = (task, project) => {
31311
+ if (task.projectId === null) return {
31312
+ startable: false,
31313
+ reason: "no-project"
31314
+ };
31315
+ if (Option.isNone(project) || project.value.deletedAt !== null) return {
31316
+ startable: false,
31317
+ reason: "project-missing"
31318
+ };
31319
+ const model = project.value.defaultModelSelection;
31320
+ if (model === null) return {
31321
+ startable: false,
31322
+ reason: "no-model"
31323
+ };
31324
+ return {
31325
+ startable: true,
31326
+ projectId: task.projectId,
31327
+ model
31328
+ };
31329
+ };
31330
+ /**
31119
31331
  * Map a persistence failure to the caller-facing error.
31120
31332
  *
31121
31333
  * The underlying error carries SQL detail, which is noise to a client and, for
@@ -31127,6 +31339,54 @@ const toTaskStoreError = (operation) => (cause) => Effect.logWarning("task store
31127
31339
  cause
31128
31340
  }).pipe(Effect.andThen(Effect.fail(new TaskStoreError({ operation }))));
31129
31341
  //#endregion
31342
+ //#region ../../packages/shared/src/taskExecution.ts
31343
+ /**
31344
+ * The `auto` rendering: here is the task, do it.
31345
+ *
31346
+ * Two instructions carry their weight. The agent is told its thread is already
31347
+ * linked to the task, because otherwise its first useful move is to guess which
31348
+ * board row it is on. And it is told to leave `status` alone: the server moved
31349
+ * the task to `in_progress` when it started the thread, and where the work goes
31350
+ * after that is the user's call — the same rule the scoping prompt follows, and
31351
+ * the reason the board's columns still mean something.
31352
+ */
31353
+ const buildAutoPrompt = (task) => {
31354
+ const body = task.body.trim();
31355
+ return `You are picking up a task from the board. Do the work.
31356
+
31357
+ ## ${task.title}
31358
+
31359
+ ${body.length === 0 ? "_The task has no description. Read enough of the repository to work out what it means, and ask if it is genuinely ambiguous._" : body}
31360
+
31361
+ This thread is linked to task \`${task.taskId}\`, which is now In progress. \`task_current\` re-reads it if you need the fields again.
31362
+
31363
+ Record what you find with \`task_update\` as you go — a decision you made, a constraint you hit, something the task turned out to be wrong about. That is what makes the row worth reading afterwards. Leave \`status\` alone: moving work across the board is the user's call.
31364
+
31365
+ Start by reading the code the task concerns. If it turns out to be specified too poorly to act on, say so and stop rather than guessing at what was meant.`;
31366
+ };
31367
+ /**
31368
+ * Render a task into the prompt that seeds its thread.
31369
+ *
31370
+ * Exhaustive over the mode on purpose: adding a member to [TaskExecutionMode]
31371
+ * without a rendering should fail to compile rather than fall through to `auto`.
31372
+ */
31373
+ const buildTaskExecutionPrompt = (input) => {
31374
+ switch (input.mode) {
31375
+ case "auto": return buildAutoPrompt(input.task);
31376
+ }
31377
+ };
31378
+ const TASK_THREAD_TITLE_MAX_LENGTH = 60;
31379
+ /**
31380
+ * The thread's title, which is the task's own — a thread started from a task is
31381
+ * that task, and a derived-from-the-prompt title would read as a sentence of
31382
+ * instructions in the sidebar.
31383
+ */
31384
+ const buildTaskThreadTitle = (title) => {
31385
+ const compact = title.trim().replace(/\s+/gu, " ");
31386
+ if (compact.length === 0) return "Task";
31387
+ return compact.length > TASK_THREAD_TITLE_MAX_LENGTH ? `${compact.slice(0, TASK_THREAD_TITLE_MAX_LENGTH - 1).trimEnd()}…` : compact;
31388
+ };
31389
+ //#endregion
31130
31390
  //#region src/observability/RpcInstrumentation.ts
31131
31391
  const RPC_SPAN_PREFIX = "ws.rpc";
31132
31392
  const DEFAULT_RPC_SPAN_ATTRIBUTES = {
@@ -40853,6 +41113,7 @@ const RPC_REQUIRED_SCOPE = /* @__PURE__ */ new Map([
40853
41113
  [WS_METHODS.tasksCreate, AuthOrchestrationOperateScope],
40854
41114
  [WS_METHODS.tasksUpdate, AuthOrchestrationOperateScope],
40855
41115
  [WS_METHODS.tasksDelete, AuthOrchestrationOperateScope],
41116
+ [WS_METHODS.tasksStartThread, AuthOrchestrationOperateScope],
40856
41117
  [WS_METHODS.subscribeTasks, AuthOrchestrationReadScope],
40857
41118
  [WS_METHODS.hubGetSyncStatus, AuthOrchestrationReadScope],
40858
41119
  [WS_METHODS.hubConnect, AuthOrchestrationOperateScope],
@@ -40965,7 +41226,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
40965
41226
  const checkpointDiffQuery = yield* CheckpointDiffQuery;
40966
41227
  const keybindings = yield* Keybindings;
40967
41228
  const taskRepository = yield* TaskRepository;
40968
- yield* ProjectionProjectRepository;
41229
+ const projectionProjects = yield* ProjectionProjectRepository;
40969
41230
  const externalLauncher = yield* ExternalLauncher;
40970
41231
  const gitWorkflow = yield* GitWorkflowService;
40971
41232
  const review = yield* ReviewService;
@@ -41443,6 +41704,64 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
41443
41704
  return { task: patched.value };
41444
41705
  }), { "rpc.aggregate": "tasks" }),
41445
41706
  [WS_METHODS.tasksDelete]: ({ taskId }) => observeRpcEffect$1(WS_METHODS.tasksDelete, taskRepository.deleteById({ taskId }).pipe(Effect.catch(toTaskStoreError("tasks.delete")), Effect.as({})), { "rpc.aggregate": "tasks" }),
41707
+ [WS_METHODS.tasksStartThread]: ({ taskId }) => observeRpcEffect$1(WS_METHODS.tasksStartThread, Effect.gen(function* () {
41708
+ const found = yield* taskRepository.getById({ taskId }).pipe(Effect.catch(toTaskStoreError("tasks.startThread")));
41709
+ if (Option.isNone(found)) return yield* new TaskNotFoundError({ taskId });
41710
+ const task = found.value;
41711
+ const plan = resolveTaskStart(task, task.projectId === null ? Option.none() : yield* projectionProjects.getById({ projectId: task.projectId }).pipe(Effect.catch(toTaskStoreError("tasks.startThread.project"))));
41712
+ if (!plan.startable) return yield* new TaskNotStartableError({
41713
+ taskId,
41714
+ reason: plan.reason
41715
+ });
41716
+ const modelSelection = plan.model;
41717
+ const threadId = ThreadId.make(yield* crypto.randomUUIDv4.pipe(Effect.orDie));
41718
+ const createdAt = yield* nowIso$5;
41719
+ const threadTitle = buildTaskThreadTitle(task.title);
41720
+ const normalizedCommand = yield* normalizeDispatchCommand({
41721
+ type: "thread.turn.start",
41722
+ commandId: yield* serverCommandId("task-start-thread"),
41723
+ threadId,
41724
+ message: {
41725
+ messageId: MessageId.make(yield* crypto.randomUUIDv4.pipe(Effect.orDie)),
41726
+ role: "user",
41727
+ text: buildTaskExecutionPrompt({
41728
+ mode: "auto",
41729
+ task: {
41730
+ taskId,
41731
+ title: task.title,
41732
+ body: task.body
41733
+ }
41734
+ }),
41735
+ attachments: []
41736
+ },
41737
+ modelSelection,
41738
+ titleSeed: threadTitle,
41739
+ runtimeMode: DEFAULT_RUNTIME_MODE$2,
41740
+ interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
41741
+ bootstrap: { createThread: {
41742
+ projectId: plan.projectId,
41743
+ title: threadTitle,
41744
+ modelSelection,
41745
+ runtimeMode: DEFAULT_RUNTIME_MODE$2,
41746
+ interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
41747
+ branch: null,
41748
+ worktreePath: null,
41749
+ createdAt
41750
+ } },
41751
+ createdAt
41752
+ });
41753
+ yield* dispatchNormalizedCommand(normalizedCommand);
41754
+ const patched = yield* taskRepository.patch({
41755
+ taskId,
41756
+ threadId,
41757
+ status: "in_progress"
41758
+ }, yield* nowIso$5).pipe(Effect.catch(toTaskStoreError("tasks.startThread.link")));
41759
+ if (Option.isNone(patched)) return yield* new TaskNotFoundError({ taskId });
41760
+ return {
41761
+ task: patched.value,
41762
+ threadId
41763
+ };
41764
+ }), { "rpc.aggregate": "tasks" }),
41446
41765
  [WS_METHODS.subscribeTasks]: (_input) => observeRpcStreamEffect$1(WS_METHODS.subscribeTasks, Effect.succeed(taskRepository.streamWithSnapshot.pipe(Stream.catch((cause) => Stream.fromEffect(toTaskStoreError("tasks.subscribe")(cause))))), { "rpc.aggregate": "tasks" }),
41447
41766
  [WS_METHODS.hubGetSyncStatus]: (_input) => observeRpcEffect$1(WS_METHODS.hubGetSyncStatus, assetSync.status, { "rpc.aggregate": "hub" }),
41448
41767
  [WS_METHODS.hubConnect]: (input) => observeRpcEffect$1(WS_METHODS.hubConnect, hubLink.connect(input).pipe(Effect.mapError((cause) => new HubLinkError({ detail: cause.message })), Effect.andThen(assetSync.status)), { "rpc.aggregate": "hub" }),
@@ -45240,13 +45559,178 @@ function normalizeClaudeActiveTokenUsage(value, contextWindow, totalProcessedTok
45240
45559
  ...totalProcessedTokens !== void 0 ? { totalProcessedTokens } : {}
45241
45560
  });
45242
45561
  }
45562
+ /**
45563
+ * The contract's string fields are non-empty, and this payload is decoded on the
45564
+ * way out, so an entry the SDK reports with a blank name would fail the whole
45565
+ * event rather than lose one row. Drop those instead.
45566
+ */
45567
+ function trimmedName(value) {
45568
+ if (typeof value !== "string") return;
45569
+ const trimmed = value.trim();
45570
+ return trimmed.length > 0 ? trimmed : void 0;
45571
+ }
45572
+ function mapNamedCosts(entries) {
45573
+ if (!entries || entries.length === 0) return;
45574
+ const mapped = entries.flatMap((entry) => {
45575
+ const name = trimmedName(entry.name);
45576
+ const tokens = finiteNonNegativeInteger(entry.tokens);
45577
+ return name !== void 0 && tokens !== void 0 ? [{
45578
+ name,
45579
+ tokens
45580
+ }] : [];
45581
+ });
45582
+ return mapped.length > 0 ? mapped : void 0;
45583
+ }
45584
+ /**
45585
+ * Keeps the per-source attribution the SDK already computes on every turn. The
45586
+ * `gridRows` and `color` fields are dropped: they describe how the vendor CLI
45587
+ * paints its own meter, and this UI has its own.
45588
+ */
45589
+ function claudeContextWindowBreakdown(value) {
45590
+ const model = trimmedName(value.model);
45591
+ const categories = value.categories.flatMap((category) => {
45592
+ const name = trimmedName(category.name);
45593
+ const tokens = finiteNonNegativeInteger(category.tokens);
45594
+ if (name === void 0 || tokens === void 0) return [];
45595
+ return [{
45596
+ name,
45597
+ tokens,
45598
+ ...category.isDeferred !== void 0 ? { isDeferred: category.isDeferred } : {}
45599
+ }];
45600
+ });
45601
+ const mcpTools = value.mcpTools.flatMap((tool) => {
45602
+ const name = trimmedName(tool.name);
45603
+ const serverName = trimmedName(tool.serverName);
45604
+ const tokens = finiteNonNegativeInteger(tool.tokens);
45605
+ if (name === void 0 || serverName === void 0 || tokens === void 0) return [];
45606
+ return [{
45607
+ name,
45608
+ serverName,
45609
+ tokens,
45610
+ ...tool.isLoaded !== void 0 ? { isLoaded: tool.isLoaded } : {}
45611
+ }];
45612
+ });
45613
+ const memoryFiles = value.memoryFiles.flatMap((file) => {
45614
+ const path = trimmedName(file.path);
45615
+ const tokens = finiteNonNegativeInteger(file.tokens);
45616
+ if (path === void 0 || tokens === void 0) return [];
45617
+ const type = trimmedName(file.type);
45618
+ return [{
45619
+ path,
45620
+ tokens,
45621
+ ...type !== void 0 ? { type } : {}
45622
+ }];
45623
+ });
45624
+ const agents = value.agents.flatMap((agent) => {
45625
+ const agentType = trimmedName(agent.agentType);
45626
+ const tokens = finiteNonNegativeInteger(agent.tokens);
45627
+ if (agentType === void 0 || tokens === void 0) return [];
45628
+ const source = trimmedName(agent.source);
45629
+ return [{
45630
+ agentType,
45631
+ tokens,
45632
+ ...source !== void 0 ? { source } : {}
45633
+ }];
45634
+ });
45635
+ const deferredBuiltinTools = value.deferredBuiltinTools?.flatMap((tool) => {
45636
+ const name = trimmedName(tool.name);
45637
+ const tokens = finiteNonNegativeInteger(tool.tokens);
45638
+ return name !== void 0 && tokens !== void 0 ? [{
45639
+ name,
45640
+ tokens,
45641
+ isLoaded: tool.isLoaded
45642
+ }] : [];
45643
+ });
45644
+ const skillsSource = value.skills;
45645
+ const skillEntries = skillsSource?.skillFrontmatter.flatMap((skill) => {
45646
+ const name = trimmedName(skill.name);
45647
+ const tokens = finiteNonNegativeInteger(skill.tokens);
45648
+ if (name === void 0 || tokens === void 0) return [];
45649
+ const source = trimmedName(skill.source);
45650
+ return [{
45651
+ name,
45652
+ tokens,
45653
+ ...source !== void 0 ? { source } : {}
45654
+ }];
45655
+ });
45656
+ const skills = skillsSource === void 0 ? void 0 : {
45657
+ totalSkills: finiteNonNegativeInteger(skillsSource.totalSkills) ?? 0,
45658
+ includedSkills: finiteNonNegativeInteger(skillsSource.includedSkills) ?? 0,
45659
+ tokens: finiteNonNegativeInteger(skillsSource.tokens) ?? 0,
45660
+ ...skillEntries && skillEntries.length > 0 ? { entries: skillEntries } : {}
45661
+ };
45662
+ const slashCommandsSource = value.slashCommands;
45663
+ const slashCommands = slashCommandsSource === void 0 ? void 0 : {
45664
+ totalCommands: finiteNonNegativeInteger(slashCommandsSource.totalCommands) ?? 0,
45665
+ includedCommands: finiteNonNegativeInteger(slashCommandsSource.includedCommands) ?? 0,
45666
+ tokens: finiteNonNegativeInteger(slashCommandsSource.tokens) ?? 0
45667
+ };
45668
+ const messagesSource = value.messageBreakdown;
45669
+ const toolCallsByType = messagesSource?.toolCallsByType.flatMap((entry) => {
45670
+ const name = trimmedName(entry.name);
45671
+ const callTokens = finiteNonNegativeInteger(entry.callTokens);
45672
+ const resultTokens = finiteNonNegativeInteger(entry.resultTokens);
45673
+ return name !== void 0 && callTokens !== void 0 && resultTokens !== void 0 ? [{
45674
+ name,
45675
+ callTokens,
45676
+ resultTokens
45677
+ }] : [];
45678
+ });
45679
+ const attachmentsByType = mapNamedCosts(messagesSource?.attachmentsByType);
45680
+ const messages = messagesSource === void 0 ? void 0 : {
45681
+ toolCallTokens: finiteNonNegativeInteger(messagesSource.toolCallTokens) ?? 0,
45682
+ toolResultTokens: finiteNonNegativeInteger(messagesSource.toolResultTokens) ?? 0,
45683
+ attachmentTokens: finiteNonNegativeInteger(messagesSource.attachmentTokens) ?? 0,
45684
+ assistantMessageTokens: finiteNonNegativeInteger(messagesSource.assistantMessageTokens) ?? 0,
45685
+ userMessageTokens: finiteNonNegativeInteger(messagesSource.userMessageTokens) ?? 0,
45686
+ redirectedContextTokens: finiteNonNegativeInteger(messagesSource.redirectedContextTokens) ?? 0,
45687
+ unattributedTokens: finiteNonNegativeInteger(messagesSource.unattributedTokens) ?? 0,
45688
+ ...toolCallsByType && toolCallsByType.length > 0 ? { toolCallsByType } : {},
45689
+ ...attachmentsByType !== void 0 ? { attachmentsByType } : {}
45690
+ };
45691
+ const systemTools = mapNamedCosts(value.systemTools);
45692
+ const systemPromptSections = mapNamedCosts(value.systemPromptSections);
45693
+ const autoCompactThreshold = finiteNonNegativeInteger(value.autoCompactThreshold);
45694
+ const breakdown = {
45695
+ ...model !== void 0 ? { model } : {},
45696
+ ...categories.length > 0 ? { categories } : {},
45697
+ ...mcpTools.length > 0 ? { mcpTools } : {},
45698
+ ...skills !== void 0 ? { skills } : {},
45699
+ ...memoryFiles.length > 0 ? { memoryFiles } : {},
45700
+ ...agents.length > 0 ? { agents } : {},
45701
+ ...systemTools !== void 0 ? { systemTools } : {},
45702
+ ...deferredBuiltinTools && deferredBuiltinTools.length > 0 ? { deferredBuiltinTools } : {},
45703
+ ...systemPromptSections !== void 0 ? { systemPromptSections } : {},
45704
+ ...slashCommands !== void 0 ? { slashCommands } : {},
45705
+ ...messages !== void 0 ? { messages } : {},
45706
+ ...autoCompactThreshold !== void 0 ? { autoCompactThreshold } : {}
45707
+ };
45708
+ return Object.keys(breakdown).length > 0 ? breakdown : void 0;
45709
+ }
45710
+ /**
45711
+ * Drops the attribution from a snapshot that is being carried forward. The token
45712
+ * counts still describe the thread, but the breakdown was measured against a
45713
+ * turn that has since moved on. A stale breakdown presented as the current one
45714
+ * is worse than none, because nothing about it looks stale.
45715
+ */
45716
+ function withoutContextWindowBreakdown(usage) {
45717
+ if (!usage || usage.breakdown === void 0) return usage;
45718
+ const { breakdown: _breakdown, ...rest } = usage;
45719
+ return rest;
45720
+ }
45243
45721
  function normalizeClaudeContextUsageApiSnapshot(value, totalProcessedTokens) {
45244
- return makeClaudeTokenUsageSnapshot({
45722
+ const snapshot = makeClaudeTokenUsageSnapshot({
45245
45723
  activeTokens: value.totalTokens,
45246
45724
  contextWindow: value.maxTokens,
45247
45725
  ...totalProcessedTokens !== void 0 ? { totalProcessedTokens } : {},
45248
45726
  compactsAutomatically: value.isAutoCompactEnabled
45249
45727
  });
45728
+ if (!snapshot) return;
45729
+ const breakdown = claudeContextWindowBreakdown(value);
45730
+ return breakdown !== void 0 ? {
45731
+ ...snapshot,
45732
+ breakdown
45733
+ } : snapshot;
45250
45734
  }
45251
45735
  function compactBoundaryTokenUsageSnapshot(message, contextWindow, totalProcessedTokens) {
45252
45736
  const metadata = message.compact_metadata;
@@ -45965,15 +46449,28 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
45965
46449
  });
45966
46450
  });
45967
46451
  const queryCurrentContextUsage = Effect.fn("queryCurrentContextUsage")(function* (context, totalProcessedTokens) {
45968
- if (!context.query.getContextUsage) return;
46452
+ if (!context.query.getContextUsage) {
46453
+ yield* Effect.logWarning("claude.context-usage.unsupported", { threadId: context.session.threadId });
46454
+ return;
46455
+ }
45969
46456
  const usage = yield* Effect.promise(async () => {
45970
46457
  try {
45971
46458
  return await context.query.getContextUsage?.();
45972
- } catch {
45973
- return;
46459
+ } catch (cause) {
46460
+ return { failure: cause instanceof Error ? cause.message : String(cause) };
45974
46461
  }
45975
46462
  });
45976
- if (!usage) return;
46463
+ if (usage !== void 0 && "failure" in usage) {
46464
+ yield* Effect.logWarning("claude.context-usage.failed", {
46465
+ threadId: context.session.threadId,
46466
+ detail: usage.failure
46467
+ });
46468
+ return;
46469
+ }
46470
+ if (!usage) {
46471
+ yield* Effect.logWarning("claude.context-usage.empty", { threadId: context.session.threadId });
46472
+ return;
46473
+ }
45977
46474
  context.lastKnownContextWindow = usage.maxTokens;
45978
46475
  return normalizeClaudeContextUsageApiSnapshot(usage, totalProcessedTokens);
45979
46476
  });
@@ -46039,7 +46536,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
46039
46536
  const resultHasActiveUsage = resultUsageRecord !== void 0 && (hasResultUsageIteration || claudeUsageInputTokens(resultUsageRecord) + claudeUsageOutputTokens(resultUsageRecord) > 0);
46040
46537
  const resultTotalOnly = resultUsageRecord !== void 0 && !resultHasActiveUsage && claudeTotalProcessedTokens(resultUsageRecord) !== void 0;
46041
46538
  const resultIterationSnapshot = resultUsageRecord ? normalizeClaudeActiveTokenUsage(resultUsageRecord, maxTokens, accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens) : void 0;
46042
- const lastGoodUsage = context.lastKnownTokenUsage;
46539
+ const lastGoodUsage = withoutContextWindowBreakdown(context.lastKnownTokenUsage);
46043
46540
  const usageSnapshot = contextUsageSnapshot ?? (resultTotalOnly && lastGoodUsage ? {
46044
46541
  ...lastGoodUsage,
46045
46542
  ...typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0 ? { maxTokens } : {},