t3code-cli 0.14.2 → 0.15.0

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 (165) hide show
  1. package/README.md +36 -1
  2. package/dist/application.d.ts +2 -2
  3. package/dist/application.js +1 -1
  4. package/dist/auth.d.ts +1 -1
  5. package/dist/auth.js +1 -1
  6. package/dist/bin.js +935 -336
  7. package/dist/cli.d.ts +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/client-runtime/authorization.d.ts +1 -1
  10. package/dist/client-runtime/authorization.js +1 -1
  11. package/dist/client-runtime/connection.d.ts +1 -1
  12. package/dist/client-runtime/connection.js +1 -1
  13. package/dist/client-runtime/environment.d.ts +3 -1
  14. package/dist/client-runtime/environment.js +1 -1
  15. package/dist/client-runtime/errors.js +1 -1
  16. package/dist/client-runtime/operations/projects.d.ts +1 -1
  17. package/dist/client-runtime/operations.d.ts +1 -1
  18. package/dist/client-runtime/platform.d.ts +1 -1
  19. package/dist/client-runtime/platform.js +1 -1
  20. package/dist/client-runtime/relay.d.ts +9 -2
  21. package/dist/client-runtime/relay.js +12 -2
  22. package/dist/client-runtime/rpc.d.ts +2 -2
  23. package/dist/client-runtime/rpc.js +2 -2
  24. package/dist/client-runtime/state/assets.d.ts +1 -1
  25. package/dist/client-runtime/state/assets.js +1 -1
  26. package/dist/client-runtime/state/auth.d.ts +1 -1
  27. package/dist/client-runtime/state/auth.js +1 -1
  28. package/dist/client-runtime/state/connections.js +1 -1
  29. package/dist/client-runtime/state/entities.d.ts +1 -1
  30. package/dist/client-runtime/state/filesystem.d.ts +1 -1
  31. package/dist/client-runtime/state/filesystem.js +1 -1
  32. package/dist/client-runtime/state/git.d.ts +2 -1
  33. package/dist/client-runtime/state/git.js +1 -1
  34. package/dist/client-runtime/state/models.d.ts +1 -1
  35. package/dist/client-runtime/state/models.js +1 -1
  36. package/dist/client-runtime/state/orchestration.d.ts +1 -1
  37. package/dist/client-runtime/state/orchestration.js +1 -1
  38. package/dist/client-runtime/state/presentation.d.ts +7 -1
  39. package/dist/client-runtime/state/presentation.js +1 -1
  40. package/dist/client-runtime/state/preview.d.ts +5 -2
  41. package/dist/client-runtime/state/preview.js +3 -2
  42. package/dist/client-runtime/state/project-grouping.d.ts +1 -1
  43. package/dist/client-runtime/state/project-grouping.js +1 -1
  44. package/dist/client-runtime/state/projects.d.ts +1 -1
  45. package/dist/client-runtime/state/pull-requests.d.ts +478 -0
  46. package/dist/client-runtime/state/pull-requests.js +172 -0
  47. package/dist/client-runtime/state/relay.d.ts +1 -1
  48. package/dist/client-runtime/state/relay.js +1 -1
  49. package/dist/client-runtime/state/review.d.ts +1 -1
  50. package/dist/client-runtime/state/review.js +1 -1
  51. package/dist/client-runtime/state/runtime.d.ts +2 -2
  52. package/dist/client-runtime/state/runtime.js +2 -2
  53. package/dist/client-runtime/state/server.d.ts +13 -1
  54. package/dist/client-runtime/state/server.js +1 -1
  55. package/dist/client-runtime/state/session.d.ts +13 -1
  56. package/dist/client-runtime/state/session.js +1 -1
  57. package/dist/client-runtime/state/shell.d.ts +7 -1
  58. package/dist/client-runtime/state/shell.js +1 -1
  59. package/dist/client-runtime/state/source-control.d.ts +1 -1
  60. package/dist/client-runtime/state/source-control.js +1 -1
  61. package/dist/client-runtime/state/subagentRuntime.d.ts +1 -1
  62. package/dist/client-runtime/state/terminal.d.ts +1 -1
  63. package/dist/client-runtime/state/terminal.js +1 -1
  64. package/dist/client-runtime/state/thread-search.d.ts +1 -1
  65. package/dist/client-runtime/state/thread-search.js +1 -1
  66. package/dist/client-runtime/state/thread-settled.d.ts +11 -8
  67. package/dist/client-runtime/state/thread-settled.js +2 -229
  68. package/dist/client-runtime/state/thread-sort.d.ts +1 -1
  69. package/dist/client-runtime/state/thread-sort.js +1 -1
  70. package/dist/client-runtime/state/threads.d.ts +1 -1
  71. package/dist/client-runtime/state/threads.js +1 -1
  72. package/dist/client-runtime/state/vcs.d.ts +1 -1
  73. package/dist/client-runtime/state/vcs.js +1 -1
  74. package/dist/config.d.ts +1 -1
  75. package/dist/config.js +1 -1
  76. package/dist/connection.d.ts +1 -1
  77. package/dist/connection.js +1 -1
  78. package/dist/contracts.d.ts +1 -1
  79. package/dist/contracts.js +1 -1
  80. package/dist/index.d.ts +1 -1
  81. package/dist/index.js +1 -1
  82. package/dist/node.d.ts +1 -1
  83. package/dist/node.js +1 -1
  84. package/dist/orchestration.d.ts +12 -6
  85. package/dist/orchestration.js +2 -2
  86. package/dist/preview.d.ts +1 -1
  87. package/dist/rpc.d.ts +4 -9
  88. package/dist/rpc.js +1 -1
  89. package/dist/runtime.d.ts +1 -1
  90. package/dist/shared/DrainableWorker.js +1 -1
  91. package/dist/shared/KeyedCoalescingWorker.js +1 -1
  92. package/dist/shared/Net.d.ts +6 -0
  93. package/dist/shared/Net.js +2 -1
  94. package/dist/shared/advertisedEndpoint.d.ts +1 -1
  95. package/dist/shared/advertisedEndpoint.js +1 -1
  96. package/dist/shared/agentAwareness.d.ts +1 -1
  97. package/dist/shared/backgroundActivitySettings.d.ts +1 -1
  98. package/dist/shared/connectAuth.d.ts +23 -4
  99. package/dist/shared/connectAuth.js +40 -7
  100. package/dist/shared/devHome.js +1 -1
  101. package/dist/shared/dpop.js +1 -1
  102. package/dist/shared/git.d.ts +1 -1
  103. package/dist/shared/httpObservability.js +1 -1
  104. package/dist/shared/httpReadiness.js +1 -1
  105. package/dist/shared/keybindings.d.ts +1 -1
  106. package/dist/shared/model.d.ts +1 -1
  107. package/dist/shared/oauthScope.js +1 -1
  108. package/dist/shared/observability.js +1 -1
  109. package/dist/shared/preview.js +1 -1
  110. package/dist/shared/previewViewport.d.ts +1 -1
  111. package/dist/shared/previewViewport.js +1 -1
  112. package/dist/shared/projectScripts.d.ts +1 -1
  113. package/dist/shared/relayAuth.js +1 -1
  114. package/dist/shared/relayClient.d.ts +1 -1
  115. package/dist/shared/relayClient.js +1 -1
  116. package/dist/shared/relayJwt.js +1 -1
  117. package/dist/shared/relayTracing.js +1 -1
  118. package/dist/shared/relayUrl.js +1 -1
  119. package/dist/shared/remote.js +1 -1
  120. package/dist/shared/schemaYaml.js +1 -1
  121. package/dist/shared/serverSettings.d.ts +1 -1
  122. package/dist/shared/serverSettings.js +1 -1
  123. package/dist/shared/shell.js +1 -1
  124. package/dist/shared/sourceControl.d.ts +1 -1
  125. package/dist/shared/t3ProjectFile.d.ts +1 -1
  126. package/dist/shared/t3ProjectFile.js +1 -1
  127. package/dist/shared/terminalLabels.d.ts +1 -1
  128. package/dist/shared/threadEnvMode.d.ts +1 -1
  129. package/dist/shared/toolActivity.d.ts +1 -1
  130. package/dist/shared/usageFormat.d.ts +16 -3
  131. package/dist/shared/usageFormat.js +92 -6
  132. package/dist/shared/usageMerge.d.ts +13 -2
  133. package/dist/shared/usageMerge.js +23 -0
  134. package/dist/shared.d.ts +3470 -378
  135. package/dist/shared.js +2434 -617
  136. package/dist/t3tools.d.ts +2 -2
  137. package/dist/t3tools.js +2 -2
  138. package/package.json +2 -2
  139. package/src/application/error.ts +2 -2
  140. package/src/application/index.ts +1 -0
  141. package/src/application/service.ts +38 -4
  142. package/src/application/thread-commands.ts +78 -0
  143. package/src/application/threads.ts +113 -16
  144. package/src/cli/app.ts +2 -0
  145. package/src/cli/ask-lifecycle.ts +331 -0
  146. package/src/cli/ask.ts +390 -0
  147. package/src/cli/error.ts +70 -0
  148. package/src/cli/format/thread.ts +26 -6
  149. package/src/cli/thread.ts +12 -0
  150. package/src/cli/threads/messages.ts +33 -3
  151. package/src/cli/threads/pin.ts +46 -0
  152. package/src/cli/threads/send.ts +5 -1
  153. package/src/cli/threads/settle.ts +46 -0
  154. package/src/cli/threads/snooze.ts +117 -0
  155. package/src/cli/threads/start.ts +6 -1
  156. package/src/cli/threads/unpin.ts +48 -0
  157. package/src/cli/threads/unsettle.ts +48 -0
  158. package/src/cli/threads/unsnooze.ts +48 -0
  159. package/src/connection/prepared.ts +12 -2
  160. package/src/orchestration/error.ts +10 -0
  161. package/src/orchestration/index.ts +1 -0
  162. package/src/orchestration/layer.ts +72 -0
  163. package/src/orchestration/service.ts +11 -3
  164. package/src/rpc/ws-group.ts +1 -0
  165. package/src/runtime/layer.ts +9 -4
package/dist/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as __toESM, i as __require, t as __commonJSMin } from "./rolldown-runtime.js";
3
- import { $D as ExitCode, $E as red, $O as isSink, $T as loadT3CliEnv, AA as fail$1, AD as TaggedErrorClass, AE as getParamMetadata, AO as fromQueue, Aj as none, BA as succeed$2, BE as float, BO as runFold, BT as threadFlag, Bj as hasProperty, Bk as gen, Bs as CliPath, CD as Literal, CE as withDescription$1, CO as decodeText, DE as argumentKind, Dj as isSome, Dk as catch_, EE as log, EO as filter, Ej as isNone, Ek as catchTags, FD as decodeUnknownEffect, FE as optional$1, FO as merge, FT as modelFlags, Fk as fnUntraced, GA as isDone, GD as Crypto, GE as text, GO as succeed$5, GT as canRenderLiveTerminal, Gk as map, HA as MinimumLogLevel, HD as optionalKey, HE as password, HO as runHead, HT as waitFormatFlag, Hj as isNotUndefined, Hk as interrupt, Hs as threadStatus, Hw as cliEnvironmentSetting, IA as effect, IE as string$1, IT as projectFlag, Ik as forEach, Is as layerNode, JA as succeed$4, JD as fromWritable, JE as blackBright, JO as transduce, Jj as identity$1, Jk as matchEffect, Jw as ProjectLookupError, KA as make$13, KD as make$7, KE as toggle, Kj as isUndefined, Kk as mapError, Kw as resolveThreadId, LA as mergeAll, LD as decodeUnknownSync, LE as variadic$1, LT as projectPathFlag, ME as isFlagParam, MO as map$1, MT as envNameFlag, NE as isParam, NT as forceFlag, Nk as flatMap, Ns as layerNode$1, OD as String$1, OE as extractSingleParams, Ok as effectify, PE as mapEffect$1, PT as formatFlag, Pk as fn, QD as ChildProcessSpawner, QE as magenta, QO as drain, Qk as orDie, Qw as T3Config, RA as provide, RD as fromJsonString, RE as confirm, RO as run$2, RT as replaceFlag, Rs as layer$13, SE as withDefault, Sj as getOrElse, Sk as callback, TE as error, TO as empty, Tj as getOrUndefined, Tk as catchTag, UA as _await, UE as run$3, UO as runLast, UT as worktreeFlag, Uj as isNullish, Uw as T3Auth, VA as sync$1, VE as integer, VO as runForEach, VT as threadFormatFlag, Vj as isNotNull, Vk as ignore, Vs as latestAssistantMessage, WA as doneUnsafe, WD as value$2, WE as select, WT as yesFlag, Ww as resolveCommandProjectRef, XD as make$5, XE as cyanBright, XO as get$1, XT as isInteractiveHumanTerminal, Xj as pipeArguments, Xw as CliRuntime, YD as fdName, YE as bold, YO as unwrap, YT as isAgentEnvironment, Yj as pipe, Yw as ThreadSessionError, ZA as succeed$1, ZD as parseFdName, ZE as green, ZO as make$10, ZT as resolveOutputFormat, Zw as layer$12, _D as Terminal, _E as boolean, _O as WatchBackend, _j as make$12, aA as scoped, aD as isTrueValue, ak as offerUnsafe, bA as void_, bE as optional$2, bj as fromNullishOr, bk as as, cA as succeed, cD as ShowHelp, cE as Wizard, cj as isSuccess, dD as isCliError, dE as getHelpForCommandPath, dk as BadArgument, eA as provide$1, eD as white, eO as ProcessId, fE as TypeId$3, fO as Path$1, fk as badArgument, gA as try_, gD as QuitError, gE as parseConfig, gO as Size, gj as empty$1, gk as addFinalizer, hA as tryPromise, hE as toImpl, hO as FileTypeId, hj as Service, hk as acquireRelease, iA as runFork, iD as isFalseValue, ij as fail$2, ik as offer, jE as getUnderlyingSingleOrThrow, jO as isStream, jj as some, jk as fail, kD as Struct, kO as fromIterable, kj as match, lA as suspend, lD as UnknownSubcommand, lE as getGlobalFlagsForCommandPath, lj as succeed$3, lk as take, mA as timeoutOrElse, mE as makeCommand, mO as FileSystem, mj as Reference, mk as makeRunMain, nA as provideService, nD as getTypeName, nO as makeHandle, nS as ProviderUserInputAnswers, nk as failCauseUnsafe, oA as serviceOption, oE as BuiltIns, ok as poll, pE as checkForDuplicateFlags, pO as TypeId$2, pk as systemError, qA as makeUnsafe, qD as fromReadable, qE as annotate, qO as tap, qj as dual, qk as match$1, qw as resolveWorktreePath, rA as result$1, rD as isBoolean, rk as make$9, sD as InvalidValue, sE as LogLevel, sj as isResult, sk as shutdown, tA as provideContext, tD as getChoiceKeys, tE as T3Application, tO as make$6, tk as endUnsafe, uA as sync, uD as UnrecognizedOption, uE as getGlobalFlagsForCommandTree, uk as unbounded, vD as isQuitError, vE as choice, vO as make$8, vj as flatMap$1, vk as andThen, wE as Formatter, wk as catchFilter, xE as string$2, xj as fromUndefinedOr, xk as asVoid, yA as uninterruptible, yD as make$11, yE as integer$1, yO as callback$1, zA as provideMerge, zE as date, zO as runDrain, zT as selfActionForceFlag, zk as forkScoped, zn as BaseAppLayer } from "./shared.js";
3
+ import { $A as runHead, $E as resolveThreadId, $M as succeed$2, $O as toggle, $j as ignore, $k as value$2, AA as callback$1, AN as Service, AO as withDescription$1, Aj as andThen, Ak as DurationFromString, BA as fromIterable, BD as forceFlag, BN as getOrUndefined, BO as isParam, Bj as effectify, CA as Path$1, CM as sync, CN as format, CO as parseConfig, Cj as BadArgument, Ck as QuitError, DA as Size, DM as timeoutOrElse, DO as optional$2, Dj as acquireRelease, EA as FileTypeId, EO as integer$1, Ej as makeRunMain, Ek as make$11, FN as fromNullishOr, FO as extractSingleParams, GD as replaceFlag, GN as none, GO as confirm, Gj as flatMap, Gk as decodeUnknownOption, HA as isStream, HD as modelFlags, HN as isSome, HO as optional$1, IA as empty, IN as fromUndefinedOr, Ij as catchFilter, Is as layerNode$1, JD as threadFormatFlag, JO as integer, Jj as forEach, KA as merge, KD as selfActionForceFlag, KN as some, KO as date, Kj as fn, Kk as decodeUnknownSync, LA as filter, LN as getOrElse, LO as getParamMetadata, Lj as catchTag, Lk as String$1, MM as uninterruptible, MN as make$12, MO as error, Mj as as, Mk as Literal, NM as void_, NN as flatMap$1, NO as log, Nj as asVoid, OA as WatchBackend, OM as tryPromise, ON as toMillis, OO as string$2, Oj as addFinalizer, Ok as DateTimeUtcFromString, PA as decodeText, PO as argumentKind, Pj as callback, QA as runForEach, QD as canRenderLiveTerminal, QM as provideMerge, QO as text, Qj as gen, RO as getUnderlyingSingleOrThrow, Rj as catchTags, Rk as Struct, SM as suspend, SN as succeed$3, SO as toImpl, Sj as unbounded, TA as FileSystem, TO as choice, Tj as systemError, Tk as isQuitError, UA as map$1, UD as projectFlag, UM as fail$1, UO as string$1, Uj as fail, VA as fromQueue, VD as formatFlag, VN as isNone, VO as mapEffect$1, Vs as layer$13, WD as projectPathFlag, WN as match, WO as variadic$1, Wk as decodeUnknownEffect, XA as runDrain, XD as worktreeFlag, XM as mergeAll, XO as run$3, Xs as resolveSnoozePresets, YA as run$2, YD as waitFormatFlag, YM as effect, YO as password, ZA as runFold, ZD as yesFlag, ZE as resolveCommandProjectRef, ZM as provide, ZO as select, Zj as forkScoped, Zk as optionalKey, _M as runFork, _N as fail$2, _O as getGlobalFlagsForCommandTree, _j as offerUnsafe, _k as UnrecognizedOption, aA as make$5, aD as T3Config, aM as match$1, aN as make$13, ac as derivePendingUserInputs, aj as tap, ak as magenta, bN as isResult, bO as checkForDuplicateFlags, cA as ExitCode, cO as T3Application, cP as dual, cc as threadStatus, cj as get$1, ck as getChoiceKeys, dA as makeHandle, dM as orDie, dP as pipeArguments, dj as isSink, dk as isFalseValue, dw as ProviderUserInputAnswers, eA as Crypto, eD as resolveWorktreePath, eM as interrupt, eN as sync$1, eO as humanJsonNdjsonFormatChoices, ej as runLast, ek as annotate, fk as isTrueValue, gM as result$1, gO as getGlobalFlagsForCommandPath, gj as offer, gk as UnknownSubcommand, hM as provideService, hO as Wizard, hj as make$9, hk as ShowHelp, iA as fdName, iD as layer$12, iM as mapError, iN as isDone, iO as resolveOutputFormat, iP as isNullish, ic as derivePendingApprovals, ij as takeUntil, ik as green, jN as empty$1, jO as Formatter, kA as make$8, kM as try_, kN as Reference, kO as withDefault, lA as ProcessId, lM as onInterrupt, lP as identity$1, lj as make$10, lk as getTypeName, mM as provideContext, mO as LogLevel, mj as failCauseUnsafe, mk as InvalidValue, nA as fromReadable, nD as ThreadSessionError, nN as _await, nO as isAgentEnvironment, nP as isNotNull, nc as cliEnvironmentSetting, nj as succeed$5, nk as bold, oA as parseFdName, oM as matchEffect, oN as makeUnsafe, oO as loadT3CliEnv, oc as isThreadActive, oj as transduce, ok as red, pM as provide$1, pO as BuiltIns, pj as endUnsafe, qD as threadFlag, qO as float, qj as fnUntraced, qk as fromJsonString, rA as fromWritable, rD as CliRuntime, rM as map, rN as doneUnsafe, rO as isInteractiveHumanTerminal, rP as isNotUndefined, rc as T3Auth, rk as cyanBright, sA as ChildProcessSpawner, sN as succeed$4, sP as isUndefined, sc as latestAssistantMessage, sj as unwrap, sk as white, tA as make$7, tD as ProjectLookupError, tN as MinimumLogLevel, tP as hasProperty, tc as CliPath, tk as blackBright, uA as make$6, uN as succeed$1, uP as pipe, uj as drain, uk as isBoolean, vA as formatIso, vM as scoped, vO as getHelpForCommandPath, vj as poll, vk as isCliError, wA as TypeId$2, wO as boolean, wj as badArgument, wk as Terminal, xM as succeed, xN as isSuccess, xO as makeCommand, xj as take, yA as nowAsDate, yM as serviceOption, yO as TypeId$3, yj as shutdown, zD as envNameFlag, zO as isFlagParam, zj as catch_, zk as TaggedErrorClass, zn as BaseAppLayer, zs as layerNode } from "./shared.js";
4
4
  import * as OS from "node:os";
5
5
  import os, { homedir } from "node:os";
6
6
  import * as NodeChildProcess from "node:child_process";
@@ -86369,9 +86369,46 @@ var SelfActionError = class extends TaggedErrorClass()("SelfActionError", {
86369
86369
  }) {};
86370
86370
  var DestructiveConfirmationRequiredError = class extends TaggedErrorClass()("DestructiveConfirmationRequiredError", { message: String$1 }) {};
86371
86371
  var InvalidFlagCombinationError = class extends TaggedErrorClass()("InvalidFlagCombinationError", { message: String$1 }) {};
86372
+ var InvalidAskTimeoutError = class extends TaggedErrorClass()("InvalidAskTimeoutError", {
86373
+ message: String$1,
86374
+ value: String$1
86375
+ }) {};
86376
+ var AskThreadArchivedError = class extends TaggedErrorClass()("AskThreadArchivedError", {
86377
+ message: String$1,
86378
+ threadId: String$1
86379
+ }) {};
86380
+ var AskThreadBusyError = class extends TaggedErrorClass()("AskThreadBusyError", {
86381
+ message: String$1,
86382
+ threadId: String$1
86383
+ }) {};
86384
+ var AskThreadPendingRequestError = class extends TaggedErrorClass()("AskThreadPendingRequestError", {
86385
+ message: String$1,
86386
+ threadId: String$1
86387
+ }) {};
86388
+ var AskProjectMismatchError = class extends TaggedErrorClass()("AskProjectMismatchError", {
86389
+ message: String$1,
86390
+ threadId: String$1,
86391
+ projectId: String$1
86392
+ }) {};
86393
+ var AskNoAnswerError = class extends TaggedErrorClass()("AskNoAnswerError", {
86394
+ message: String$1,
86395
+ threadId: String$1
86396
+ }) {};
86397
+ var AskTimeoutError = class extends TaggedErrorClass()("AskTimeoutError", {
86398
+ message: String$1,
86399
+ timeout: String$1
86400
+ }) {};
86372
86401
  var MissingRequestError = class extends TaggedErrorClass()("MissingRequestError", { message: String$1 }) {};
86373
86402
  var MissingUpdateFieldsError = class extends TaggedErrorClass()("MissingUpdateFieldsError", { message: String$1 }) {};
86374
86403
  var ConflictingUpdateFlagsError = class extends TaggedErrorClass()("ConflictingUpdateFlagsError", { message: String$1 }) {};
86404
+ var InvalidSnoozeUntilError = class extends TaggedErrorClass()("InvalidSnoozeUntilError", {
86405
+ message: String$1,
86406
+ value: String$1
86407
+ }) {};
86408
+ var UnavailableSnoozePresetError = class extends TaggedErrorClass()("UnavailableSnoozePresetError", {
86409
+ message: String$1,
86410
+ preset: String$1
86411
+ }) {};
86375
86412
  const extraArgsConfig = { extraArgs: string("extra").pipe(variadic(), mapEffect((extra) => extra.length === 0 ? void_ : fail(new InvalidValue({
86376
86413
  option: "extra",
86377
86414
  value: extra[0] ?? "",
@@ -87116,6 +87153,719 @@ function buildUpdatePatch(input) {
87116
87153
  });
87117
87154
  }
87118
87155
  //#endregion
87156
+ //#region src/cli/format/thread.ts
87157
+ function formatThreadShowJson(thread) {
87158
+ return {
87159
+ id: thread.id,
87160
+ projectId: thread.projectId,
87161
+ title: thread.title,
87162
+ status: thread.status,
87163
+ session: thread.session,
87164
+ latestTurn: thread.latestTurn,
87165
+ modelSelection: thread.modelSelection,
87166
+ runtimeMode: thread.runtimeMode,
87167
+ interactionMode: thread.interactionMode,
87168
+ branch: thread.branch,
87169
+ worktreePath: thread.worktreePath,
87170
+ archivedAt: thread.archivedAt,
87171
+ createdAt: thread.createdAt,
87172
+ updatedAt: thread.updatedAt,
87173
+ messageCount: thread.messageCount,
87174
+ hasPendingApprovals: thread.hasPendingApprovals,
87175
+ hasPendingUserInput: thread.hasPendingUserInput,
87176
+ hasActionableProposedPlan: thread.hasActionableProposedPlan,
87177
+ pendingApprovals: thread.pendingApprovals,
87178
+ pendingUserInputs: thread.pendingUserInputs
87179
+ };
87180
+ }
87181
+ function formatThreadShowHuman(thread) {
87182
+ const sections = [formatRecord([
87183
+ {
87184
+ field: "title",
87185
+ value: thread.title
87186
+ },
87187
+ {
87188
+ field: "id",
87189
+ value: thread.id
87190
+ },
87191
+ {
87192
+ field: "project",
87193
+ value: thread.projectId
87194
+ },
87195
+ {
87196
+ field: "status",
87197
+ value: thread.status
87198
+ },
87199
+ {
87200
+ field: "model",
87201
+ value: `${thread.modelSelection.instanceId}/${thread.modelSelection.model}`
87202
+ },
87203
+ {
87204
+ field: "runtime",
87205
+ value: thread.runtimeMode
87206
+ },
87207
+ {
87208
+ field: "interaction",
87209
+ value: thread.interactionMode
87210
+ },
87211
+ ...thread.branch !== null ? [{
87212
+ field: "branch",
87213
+ value: thread.branch
87214
+ }] : [],
87215
+ ...thread.worktreePath !== null ? [{
87216
+ field: "worktree",
87217
+ value: thread.worktreePath
87218
+ }] : [],
87219
+ ...thread.archivedAt !== null ? [{
87220
+ field: "archived",
87221
+ value: thread.archivedAt
87222
+ }] : [],
87223
+ {
87224
+ field: "messages",
87225
+ value: String(thread.messageCount)
87226
+ },
87227
+ {
87228
+ field: "updated",
87229
+ value: thread.updatedAt
87230
+ }
87231
+ ])];
87232
+ if (thread.pendingApprovals.length > 0) sections.push(`\npending approvals\n${formatTable([
87233
+ {
87234
+ header: "request",
87235
+ value: (approval) => approval.requestId,
87236
+ maxWidth: 40
87237
+ },
87238
+ {
87239
+ header: "kind",
87240
+ value: (approval) => approval.requestKind,
87241
+ maxWidth: 16
87242
+ },
87243
+ {
87244
+ header: "created",
87245
+ value: (approval) => approval.createdAt,
87246
+ maxWidth: 28
87247
+ },
87248
+ {
87249
+ header: "detail",
87250
+ value: (approval) => approval.detail ?? "-",
87251
+ maxWidth: 72
87252
+ }
87253
+ ], thread.pendingApprovals)}`);
87254
+ if (thread.pendingUserInputs.length > 0) sections.push(`\npending user inputs\n${formatTable([
87255
+ {
87256
+ header: "request",
87257
+ value: (input) => input.requestId,
87258
+ maxWidth: 40
87259
+ },
87260
+ {
87261
+ header: "questions",
87262
+ value: (input) => String(input.questions.length),
87263
+ maxWidth: 9
87264
+ },
87265
+ {
87266
+ header: "created",
87267
+ value: (input) => input.createdAt,
87268
+ maxWidth: 28
87269
+ },
87270
+ {
87271
+ header: "prompt",
87272
+ value: (input) => input.questions.map((question) => question.question).join("\n"),
87273
+ maxWidth: 72
87274
+ }
87275
+ ], thread.pendingUserInputs)}`);
87276
+ return `${sections.join("\n")}\n`;
87277
+ }
87278
+ function formatThreadsHuman(threads) {
87279
+ if (threads.length === 0) return "no threads\n";
87280
+ return `${formatTable([
87281
+ {
87282
+ header: "title",
87283
+ value: (thread) => thread.title,
87284
+ maxWidth: 36
87285
+ },
87286
+ {
87287
+ header: "id",
87288
+ value: (thread) => thread.id,
87289
+ maxWidth: 40
87290
+ },
87291
+ {
87292
+ header: "status",
87293
+ value: (thread) => threadStatus(thread),
87294
+ maxWidth: 18
87295
+ },
87296
+ {
87297
+ header: "updated",
87298
+ value: (thread) => thread.updatedAt,
87299
+ maxWidth: 28
87300
+ },
87301
+ {
87302
+ header: "flags",
87303
+ value: formatThreadFlags,
87304
+ maxWidth: 34
87305
+ }
87306
+ ], threads)}\n`;
87307
+ }
87308
+ function formatThreadSearchHuman(matches) {
87309
+ if (matches.length === 0) return "no matches\n";
87310
+ return `${matches.map((match) => formatRecord([
87311
+ {
87312
+ field: "thread",
87313
+ value: match.threadTitle ?? "-"
87314
+ },
87315
+ {
87316
+ field: "thread id",
87317
+ value: match.threadId
87318
+ },
87319
+ {
87320
+ field: "project",
87321
+ value: match.projectTitle ?? "-"
87322
+ },
87323
+ {
87324
+ field: "project id",
87325
+ value: match.projectId
87326
+ },
87327
+ {
87328
+ field: "workspace",
87329
+ value: match.workspaceRoot ?? "-"
87330
+ },
87331
+ {
87332
+ field: "branch",
87333
+ value: match.branch ?? "-"
87334
+ },
87335
+ {
87336
+ field: "worktree",
87337
+ value: match.worktreePath ?? "-"
87338
+ },
87339
+ {
87340
+ field: "source",
87341
+ value: match.source
87342
+ },
87343
+ {
87344
+ field: "created",
87345
+ value: match.messageCreatedAt ?? "-"
87346
+ },
87347
+ {
87348
+ field: "snippet",
87349
+ value: match.snippet
87350
+ }
87351
+ ])).join("\n\n")}\n`;
87352
+ }
87353
+ function formatThreadDeletedHuman(input) {
87354
+ return `thread deleted: ${input.threadId} (sequence ${input.dispatch.sequence})`;
87355
+ }
87356
+ function formatThreadStartedHuman(input) {
87357
+ return `thread started\n${formatRecord([
87358
+ {
87359
+ field: "title",
87360
+ value: input.thread.title
87361
+ },
87362
+ {
87363
+ field: "id",
87364
+ value: input.thread.id
87365
+ },
87366
+ {
87367
+ field: "status",
87368
+ value: threadStatus(input.thread)
87369
+ },
87370
+ {
87371
+ field: "sequence",
87372
+ value: String(input.sequence)
87373
+ }
87374
+ ])}`;
87375
+ }
87376
+ function formatThreadMessagesHuman(snapshot, limit) {
87377
+ const transcript = formatChatTranscript(limit === 0 ? snapshot.thread.messages : snapshot.thread.messages.slice(-limit));
87378
+ return snapshot.page?.hasMore === true && snapshot.page.beforeCursor !== null ? `${transcript}\nearlier turns available\nbefore cursor: ${snapshot.page.beforeCursor}\n` : transcript;
87379
+ }
87380
+ function formatWaitDoneHuman(thread) {
87381
+ const latest = latestAssistantMessage(thread);
87382
+ return `status: ${threadStatus(thread)}\n${latest !== void 0 ? `\n${formatChatTranscript([latest])}` : ""}`;
87383
+ }
87384
+ function formatThreadMessagesJson(snapshot, full) {
87385
+ return full ? {
87386
+ ...snapshot,
87387
+ page: snapshot.page ?? null
87388
+ } : {
87389
+ snapshotSequence: snapshot.snapshotSequence,
87390
+ thread: stripThreadMessages(snapshot.thread),
87391
+ messages: snapshot.thread.messages,
87392
+ page: snapshot.page ?? null
87393
+ };
87394
+ }
87395
+ function formatWaitEventNdjson(event) {
87396
+ if (event.type !== "thread" && event.type !== "done") return event;
87397
+ const compactThread = stripThreadHeavy(event.thread);
87398
+ return event.type === "done" ? {
87399
+ type: "done",
87400
+ thread: compactThread,
87401
+ latestAssistantMessage: latestAssistantMessage(event.thread) ?? null
87402
+ } : {
87403
+ type: "thread",
87404
+ thread: compactThread,
87405
+ messageCount: event.thread.messages.length
87406
+ };
87407
+ }
87408
+ function stripThreadMessages(thread) {
87409
+ const { messages: _messages, ...rest } = thread;
87410
+ return rest;
87411
+ }
87412
+ function formatThreadFlags(thread) {
87413
+ const flags = [
87414
+ thread.archivedAt !== null ? "archived" : null,
87415
+ thread.hasPendingApprovals ? "approval" : null,
87416
+ thread.hasPendingUserInput ? "input" : null,
87417
+ thread.hasActionableProposedPlan ? "plan" : null
87418
+ ].filter((flag) => flag !== null);
87419
+ return flags.length > 0 ? flags.join(", ") : "-";
87420
+ }
87421
+ function stripThreadHeavy(thread) {
87422
+ const { messages: _messages, activities: _activities, proposedPlans: _proposedPlans, checkpoints: _checkpoints, ...rest } = thread;
87423
+ return rest;
87424
+ }
87425
+ //#endregion
87426
+ //#region src/cli/ask-lifecycle.ts
87427
+ const archivePolicyChoices = [
87428
+ "never",
87429
+ "always",
87430
+ "on-success",
87431
+ "on-failure"
87432
+ ];
87433
+ function resolveAskFormat(format, cliRuntime, t3CliEnv) {
87434
+ if (format !== "auto") return format;
87435
+ return isInteractiveHumanTerminal(cliRuntime, t3CliEnv) ? "human" : "json";
87436
+ }
87437
+ function ensureAskTargetAvailable(thread) {
87438
+ if (thread.archivedAt !== null) return fail(new AskThreadArchivedError({
87439
+ message: `thread is archived: ${thread.id}`,
87440
+ threadId: thread.id
87441
+ }));
87442
+ if (thread.hasPendingApprovals || thread.hasPendingUserInput) return fail(new AskThreadPendingRequestError({
87443
+ message: `thread has a pending approval or user-input request: ${thread.id}`,
87444
+ threadId: thread.id
87445
+ }));
87446
+ return void_;
87447
+ }
87448
+ function waitForAskThread(application, output, input) {
87449
+ let lastStatus = "";
87450
+ let turnComplete = false;
87451
+ const observeAskThread = (thread) => {
87452
+ const observation = inspectAskTurn(thread, input.messageId, input.state.askTurnId);
87453
+ input.state.askTurnId = observation.turnId;
87454
+ if (observation.status === "failed") return fail(new ThreadSessionError({
87455
+ threadId: input.threadId,
87456
+ message: observation.message
87457
+ }));
87458
+ turnComplete = observation.status === "complete";
87459
+ return void_;
87460
+ };
87461
+ return gen(function* () {
87462
+ if (input.format === "human") yield* output.writeStderr(`waiting for ${input.threadId}...\n`);
87463
+ const event = getOrUndefined(yield* application.watchThread(input.threadId).pipe(tap((event) => gen(function* () {
87464
+ if (event.type === "thread" || event.type === "done") yield* observeAskThread(event.thread);
87465
+ else if (event.type === "status") {
87466
+ const thread = (yield* application.getThreadMessages({ threadId: input.threadId })).thread;
87467
+ yield* observeAskThread(thread);
87468
+ if (!turnComplete) yield* ensureNoPendingRequest({
87469
+ id: thread.id,
87470
+ hasPendingApprovals: derivePendingApprovals(thread.activities).length > 0,
87471
+ hasPendingUserInput: derivePendingUserInputs(thread.activities).length > 0
87472
+ });
87473
+ }
87474
+ if (input.format === "ndjson") {
87475
+ yield* output.printNdjson(formatWaitEventNdjson(event));
87476
+ return;
87477
+ }
87478
+ if (input.format === "human" && event.type === "status" && event.status !== lastStatus) {
87479
+ lastStatus = event.status;
87480
+ yield* output.writeStderr(`${input.threadId}: ${event.status}\n`);
87481
+ }
87482
+ })), takeUntil((event) => turnComplete || event.type === "done"), runLast));
87483
+ if (!turnComplete && event?.type !== "done") return yield* fail(new ThreadSessionError({
87484
+ message: `thread wait ended without a terminal event: ${input.threadId}`,
87485
+ threadId: input.threadId
87486
+ }));
87487
+ return yield* void_;
87488
+ });
87489
+ }
87490
+ function selectAskAnswer(thread, messageId, turnId) {
87491
+ const userIndex = thread.messages.findIndex((message) => message.id === messageId && message.role === "user");
87492
+ if (userIndex === -1) return;
87493
+ const following = thread.messages.slice(userIndex + 1);
87494
+ const nextUserIndex = following.findIndex((message) => message.role === "user");
87495
+ return (nextUserIndex === -1 ? following : following.slice(0, nextUserIndex)).filter((message) => message.role === "assistant" && !message.streaming && message.text.trim().length > 0 && (turnId === null || message.turnId === turnId)).at(-1);
87496
+ }
87497
+ function inspectAskTurn(thread, messageId, knownTurnId) {
87498
+ const userIndex = thread.messages.findIndex((message) => message.id === messageId && message.role === "user");
87499
+ const userMessage = userIndex === -1 ? void 0 : thread.messages[userIndex];
87500
+ if (userMessage === void 0) return {
87501
+ status: "waiting",
87502
+ turnId: knownTurnId
87503
+ };
87504
+ const following = thread.messages.slice(userIndex + 1);
87505
+ const nextUserIndex = following.findIndex((message) => message.role === "user");
87506
+ const messageTurnId = (nextUserIndex === -1 ? following : following.slice(0, nextUserIndex)).findLast((message) => message.role === "assistant" && message.turnId !== null)?.turnId ?? null;
87507
+ const latestTurn = thread.latestTurn;
87508
+ const requestedTurnId = latestTurn?.requestedAt === userMessage.createdAt ? latestTurn.turnId : null;
87509
+ const turnId = knownTurnId ?? requestedTurnId ?? messageTurnId ?? thread.session?.activeTurnId ?? null;
87510
+ if (turnId === null) return {
87511
+ status: nextUserIndex === -1 ? "waiting" : "complete",
87512
+ turnId
87513
+ };
87514
+ const askIsLatest = latestTurn?.turnId === turnId;
87515
+ if (askIsLatest && (latestTurn.state === "error" || thread.session?.status === "error")) return {
87516
+ status: "failed",
87517
+ turnId,
87518
+ message: thread.session?.lastError ?? "thread ended with error"
87519
+ };
87520
+ const sessionRunning = thread.session?.status === "starting" || thread.session?.status === "running";
87521
+ return {
87522
+ status: nextUserIndex !== -1 || askIsLatest && (latestTurn.state !== "running" || thread.session?.activeTurnId !== turnId && !sessionRunning) ? "complete" : "waiting",
87523
+ turnId
87524
+ };
87525
+ }
87526
+ function finalizeArchive(application, output, state, succeeded) {
87527
+ if (state.archiveResult !== void 0) return succeed(state.archiveResult);
87528
+ const shouldArchive = state.archivePolicy === "always" || state.archivePolicy === "on-success" && succeeded || state.archivePolicy === "on-failure" && !succeeded;
87529
+ if (!state.createdThread && !state.dispatched || state.threadId === void 0 || !shouldArchive) {
87530
+ const result = {
87531
+ policy: state.archivePolicy,
87532
+ status: "skipped"
87533
+ };
87534
+ state.archiveResult = result;
87535
+ return succeed(result);
87536
+ }
87537
+ const threadId = state.threadId;
87538
+ return application.archiveThread(threadId).pipe(matchEffect({
87539
+ onFailure: (error) => gen(function* () {
87540
+ const result = {
87541
+ policy: state.archivePolicy,
87542
+ status: "failed",
87543
+ error: error.message
87544
+ };
87545
+ state.archiveResult = result;
87546
+ yield* output.writeStderr(`warning: failed to archive thread ${threadId}: ${error.message}\n`).pipe(ignore);
87547
+ return result;
87548
+ }),
87549
+ onSuccess: (dispatch) => {
87550
+ const result = {
87551
+ policy: state.archivePolicy,
87552
+ status: "archived",
87553
+ sequence: dispatch.sequence
87554
+ };
87555
+ state.archiveResult = result;
87556
+ return succeed(result);
87557
+ }
87558
+ }));
87559
+ }
87560
+ function cleanupInterruptedAsk(application, output, state) {
87561
+ if (state.threadId === void 0) return void_;
87562
+ const threadId = state.threadId;
87563
+ return gen(function* () {
87564
+ if (state.dispatched && state.askTurnId !== null) yield* application.interruptThreadTurn(threadId, state.askTurnId).pipe(matchEffect({
87565
+ onFailure: (error) => output.writeStderr(`warning: failed to interrupt thread ${threadId}: ${error.message}\n`).pipe(ignore),
87566
+ onSuccess: () => void_
87567
+ }));
87568
+ yield* finalizeArchive(application, output, state, false);
87569
+ }).pipe(asVoid);
87570
+ }
87571
+ function ensureTrailingNewline(text) {
87572
+ return text.endsWith("\n") ? text : `${text}\n`;
87573
+ }
87574
+ function ensureNoPendingRequest(thread) {
87575
+ if (!thread.hasPendingApprovals && !thread.hasPendingUserInput) return void_;
87576
+ return fail(new AskThreadPendingRequestError({
87577
+ message: `thread requested approval or user input instead of answering: ${thread.id}`,
87578
+ threadId: thread.id
87579
+ }));
87580
+ }
87581
+ //#endregion
87582
+ //#region src/cli/input/service.ts
87583
+ var T3Input = class extends Service()("t3cli/T3Input") {};
87584
+ //#endregion
87585
+ //#region src/cli/interaction/self-action.ts
87586
+ const requireSelfActionConfirmation = fn("requireSelfActionConfirmation")(function* (input) {
87587
+ if (input.force) return;
87588
+ if (!isAgentEnvironment(input.t3CliEnv)) return;
87589
+ const callerThreadId = input.t3CliEnv.scope.t3codeThreadId;
87590
+ if (callerThreadId === void 0 || callerThreadId.length === 0) return;
87591
+ if (input.threadId !== callerThreadId) return;
87592
+ yield* fail(new SelfActionError({
87593
+ threadId: input.threadId,
87594
+ message: `cannot ${input.action} thread ${input.threadId}: command targets the calling thread. Pass --force to confirm.`
87595
+ }));
87596
+ });
87597
+ //#endregion
87598
+ //#region src/cli/message-input.ts
87599
+ function readInitialMessage(input) {
87600
+ if (input.message !== void 0 && input.message.length > 0 && input.fromStdin) return fail(new MessageInputError({ message: "pass message argument or --stdin, not both" }));
87601
+ if (input.fromStdin) return input.readStdin();
87602
+ if (input.message === void 0 || input.message.length === 0) return fail(new MessageInputError({ message: "message required unless --stdin is used" }));
87603
+ return succeed(input.message);
87604
+ }
87605
+ function readJsonAnswers(input) {
87606
+ if (input.answers !== void 0 && input.answers.length > 0 && input.fromStdin) return fail(new MessageInputError({ message: "pass --answers or --stdin, not both" }));
87607
+ if (input.fromStdin) return input.readStdin().pipe(flatMap(parseJsonAnswers));
87608
+ if (input.answers === void 0 || input.answers.length === 0) return fail(new MessageInputError({ message: "answers required unless --stdin is used" }));
87609
+ return parseJsonAnswers(input.answers);
87610
+ }
87611
+ function parseJsonAnswers(text) {
87612
+ try {
87613
+ const parsed = JSON.parse(text);
87614
+ return succeed(decodeUnknownSync(ProviderUserInputAnswers)(parsed));
87615
+ } catch {
87616
+ return fail(new MessageInputError({ message: "invalid JSON in answers" }));
87617
+ }
87618
+ }
87619
+ //#endregion
87620
+ //#region src/cli/model-options.ts
87621
+ function buildModelOptions(input) {
87622
+ const options = /* @__PURE__ */ new Map();
87623
+ const optionRecord = getOrUndefined(input.option);
87624
+ if (optionRecord !== void 0) for (const [id, value] of Object.entries(optionRecord)) options.set(id, {
87625
+ id,
87626
+ value: parseModelOptionValue(value)
87627
+ });
87628
+ setStringOption(options, "reasoningEffort", getOrUndefined(input.reasoningEffort));
87629
+ setStringOption(options, "effort", getOrUndefined(input.effort));
87630
+ setBooleanOption(options, "fastMode", getOrUndefined(input.fastMode));
87631
+ setBooleanOption(options, "thinking", getOrUndefined(input.thinking));
87632
+ return [...options.values()];
87633
+ }
87634
+ function parseModelOptionValue(value) {
87635
+ const normalized = value.trim().toLowerCase();
87636
+ if (normalized === "true") return true;
87637
+ if (normalized === "false") return false;
87638
+ return value;
87639
+ }
87640
+ function setStringOption(options, id, value) {
87641
+ if (value !== void 0 && value.length > 0) options.set(id, {
87642
+ id,
87643
+ value
87644
+ });
87645
+ }
87646
+ function setBooleanOption(options, id, value) {
87647
+ if (value !== void 0) options.set(id, {
87648
+ id,
87649
+ value
87650
+ });
87651
+ }
87652
+ //#endregion
87653
+ //#region src/cli/ask.ts
87654
+ const askThreadFlag = string$2("thread").pipe(withDescription$1("Existing thread id; T3CODE_THREAD_ID is not used"), optional$2);
87655
+ const archivePolicyFlag = choice("archive", archivePolicyChoices).pipe(withDescription$1("Archive policy (default: on-success for created threads, never for existing threads)"), optional$2);
87656
+ const timeoutFlag = string$2("timeout").pipe(withDescription$1("Response timeout, such as 30s, 5m, or 1h"), optional$2);
87657
+ const askFormatFlag = choice("format", humanJsonNdjsonFormatChoices).pipe(withDefault("human"));
87658
+ const askCommand = make("ask", {
87659
+ project: projectFlag,
87660
+ thread: askThreadFlag,
87661
+ force: selfActionForceFlag,
87662
+ message: string("message").pipe(optional),
87663
+ stdin: boolean("stdin"),
87664
+ title: string$2("title").pipe(optional$2),
87665
+ worktree: worktreeFlag,
87666
+ provider: string$2("provider").pipe(optional$2),
87667
+ model: string$2("model").pipe(optional$2),
87668
+ ...modelFlags,
87669
+ archive: archivePolicyFlag,
87670
+ timeout: timeoutFlag,
87671
+ format: askFormatFlag,
87672
+ ...extraArgsConfig
87673
+ }, ({ project, thread, force, message, stdin, title, worktree, provider, model, option, reasoningEffort, effort, fastMode, thinking, archive, timeout, format: format$1 }) => gen(function* () {
87674
+ const explicitThreadId = getOrUndefined(thread);
87675
+ const created = explicitThreadId === void 0;
87676
+ const titleValue = getOrUndefined(title);
87677
+ const providerValue = getOrUndefined(provider);
87678
+ const modelValue = getOrUndefined(model);
87679
+ const createOnlyFlags = [
87680
+ isSome(title) ? "--title" : null,
87681
+ isSome(worktree) ? "--worktree" : null,
87682
+ isSome(provider) ? "--provider" : null,
87683
+ isSome(model) ? "--model" : null
87684
+ ].filter((flag) => flag !== null);
87685
+ if (!created && createOnlyFlags.length > 0) return yield* fail(new InvalidFlagCombinationError({ message: `${createOnlyFlags.join(", ")} cannot be used with --thread` }));
87686
+ if (created && force) return yield* fail(new InvalidFlagCombinationError({ message: "--force can only be used with --thread" }));
87687
+ const timeoutValue = getOrUndefined(timeout);
87688
+ const timeoutDuration = timeoutValue === void 0 ? void 0 : yield* parseAskTimeout(timeoutValue);
87689
+ const archivePolicy = getOrElse(archive, () => created ? "on-success" : "never");
87690
+ const application = yield* T3Application;
87691
+ const cliRuntime = yield* CliRuntime;
87692
+ const t3CliEnv = yield* loadT3CliEnv;
87693
+ const input = yield* T3Input;
87694
+ const output = yield* T3Output;
87695
+ const resolvedFormat = resolveAskFormat(format$1, cliRuntime, t3CliEnv);
87696
+ const options = buildModelOptions({
87697
+ option,
87698
+ reasoningEffort,
87699
+ effort,
87700
+ fastMode,
87701
+ thinking
87702
+ });
87703
+ const state = {
87704
+ archivePolicy,
87705
+ threadId: explicitThreadId,
87706
+ createdThread: false,
87707
+ dispatched: false,
87708
+ askTurnId: null,
87709
+ archiveResult: void 0
87710
+ };
87711
+ const responseWithCleanup = gen(function* () {
87712
+ const text = yield* readInitialMessage({
87713
+ message: getOrUndefined(message),
87714
+ fromStdin: stdin,
87715
+ readStdin: input.readStdin
87716
+ });
87717
+ let dispatch;
87718
+ let askMessageId;
87719
+ if (explicitThreadId === void 0) {
87720
+ const projectRef = yield* requireCommandProjectRef({ project });
87721
+ const resolvedProject = yield* application.resolveProject(projectRef);
87722
+ const worktreePath = resolveWorktreePath({
87723
+ value: getOrUndefined(worktree),
87724
+ scope: t3CliEnv.scope
87725
+ });
87726
+ const result = yield* application.startThread({
87727
+ message: text,
87728
+ projectRef: resolvedProject.id,
87729
+ ...titleValue !== void 0 ? { title: titleValue } : {},
87730
+ ...worktreePath !== void 0 ? { worktreePath } : {},
87731
+ ...providerValue !== void 0 ? { provider: providerValue } : {},
87732
+ ...modelValue !== void 0 ? { model: modelValue } : {},
87733
+ ...options.length > 0 ? { options } : {}
87734
+ }, {
87735
+ until: "dispatch",
87736
+ onThreadCreated: (threadId) => sync(() => {
87737
+ state.threadId = threadId;
87738
+ state.createdThread = true;
87739
+ })
87740
+ });
87741
+ state.dispatched = true;
87742
+ dispatch = result.dispatch;
87743
+ askMessageId = result.messageId;
87744
+ } else {
87745
+ const summary = yield* application.getThreadSummary(explicitThreadId);
87746
+ yield* ensureAskTargetAvailable(summary);
87747
+ const projectRef = getOrUndefined(project);
87748
+ if (projectRef !== void 0) {
87749
+ const resolvedProject = yield* application.resolveProject(projectRef);
87750
+ if (summary.projectId !== resolvedProject.id) return yield* fail(new AskProjectMismatchError({
87751
+ message: `thread ${explicitThreadId} belongs to project ${summary.projectId}, not ${resolvedProject.id}`,
87752
+ threadId: explicitThreadId,
87753
+ projectId: resolvedProject.id
87754
+ }));
87755
+ }
87756
+ yield* requireSelfActionConfirmation({
87757
+ threadId: explicitThreadId,
87758
+ force,
87759
+ cliRuntime,
87760
+ t3CliEnv,
87761
+ action: "ask"
87762
+ });
87763
+ const targetThread = (yield* application.getThreadMessages({ threadId: explicitThreadId })).thread;
87764
+ if (isThreadActive(targetThread)) return yield* fail(new AskThreadBusyError({
87765
+ message: `thread is busy: ${explicitThreadId}`,
87766
+ threadId: explicitThreadId
87767
+ }));
87768
+ const result = yield* application.sendThread({
87769
+ threadId: explicitThreadId,
87770
+ message: text,
87771
+ ...options.length > 0 ? { options } : {}
87772
+ }, { until: "dispatch" });
87773
+ state.dispatched = true;
87774
+ dispatch = result.dispatch;
87775
+ askMessageId = result.messageId;
87776
+ }
87777
+ const threadId = state.threadId;
87778
+ if (threadId === void 0) return yield* fail(new AskNoAnswerError({
87779
+ message: "ask did not resolve a thread id",
87780
+ threadId: "unknown"
87781
+ }));
87782
+ if (resolvedFormat === "ndjson") yield* output.printNdjson({
87783
+ type: "dispatch",
87784
+ sequence: dispatch.sequence
87785
+ });
87786
+ yield* application.awaitShellSequence(dispatch.sequence);
87787
+ yield* waitForAskThread(application, output, {
87788
+ threadId,
87789
+ format: resolvedFormat,
87790
+ messageId: askMessageId,
87791
+ state
87792
+ });
87793
+ const finalSnapshot = yield* application.getThreadMessages({ threadId });
87794
+ const observation = inspectAskTurn(finalSnapshot.thread, askMessageId, state.askTurnId);
87795
+ if (observation.status === "failed") return yield* fail(new ThreadSessionError({
87796
+ threadId,
87797
+ message: observation.message
87798
+ }));
87799
+ const answer = selectAskAnswer(finalSnapshot.thread, askMessageId, observation.turnId);
87800
+ if (answer === void 0) return yield* fail(new AskNoAnswerError({
87801
+ message: `thread completed without a new final answer: ${threadId}`,
87802
+ threadId
87803
+ }));
87804
+ return {
87805
+ answer: answer.text,
87806
+ threadId,
87807
+ turnId: answer.turnId,
87808
+ created,
87809
+ dispatch
87810
+ };
87811
+ }).pipe(onInterrupt(() => cleanupInterruptedAsk(application, output, state)));
87812
+ return yield* (timeoutDuration === void 0 ? responseWithCleanup : responseWithCleanup.pipe(timeoutOrElse({
87813
+ duration: timeoutDuration,
87814
+ orElse: () => fail(new AskTimeoutError({
87815
+ message: `ask timed out after ${timeoutValue ?? format(timeoutDuration)}`,
87816
+ timeout: timeoutValue ?? format(timeoutDuration)
87817
+ }))
87818
+ }))).pipe(matchEffect({
87819
+ onFailure: (error) => finalizeArchive(application, output, state, false).pipe(flatMap(() => fail(error))),
87820
+ onSuccess: (result) => gen(function* () {
87821
+ const archiveResult = yield* finalizeArchive(application, output, state, true);
87822
+ const formatted = {
87823
+ answer: result.answer,
87824
+ threadId: result.threadId,
87825
+ turnId: result.turnId,
87826
+ created: result.created,
87827
+ dispatch: result.dispatch,
87828
+ archive: archiveResult
87829
+ };
87830
+ if (resolvedFormat === "json") return yield* output.printJson(formatted);
87831
+ if (resolvedFormat === "ndjson") return yield* output.printNdjson({
87832
+ type: "result",
87833
+ ...formatted
87834
+ });
87835
+ return yield* output.writeStdout(ensureTrailingNewline(result.answer));
87836
+ })
87837
+ }));
87838
+ })).pipe(withDescription("ask a project or existing thread and wait for one answer"));
87839
+ function parseAskTimeout(value) {
87840
+ const trimmed = value.trim();
87841
+ const shorthand = /^([0-9]+(?:\.[0-9]+)?)(ms|s|m|h|d|w)$/.exec(trimmed);
87842
+ let input = trimmed;
87843
+ if (shorthand !== null) {
87844
+ const amount = shorthand[1];
87845
+ const unit = shorthand[2];
87846
+ const expandedUnit = unit === void 0 ? void 0 : {
87847
+ ms: "millis",
87848
+ s: "seconds",
87849
+ m: "minutes",
87850
+ h: "hours",
87851
+ d: "days",
87852
+ w: "weeks"
87853
+ }[unit];
87854
+ if (amount !== void 0 && expandedUnit !== void 0) input = `${amount} ${expandedUnit}`;
87855
+ }
87856
+ const parsed = decodeUnknownOption(DurationFromString)(input);
87857
+ if (isNone(parsed)) return fail(new InvalidAskTimeoutError({
87858
+ message: `invalid timeout: ${value}`,
87859
+ value
87860
+ }));
87861
+ const millis = toMillis(parsed.value);
87862
+ if (!Number.isFinite(millis) || millis <= 0) return fail(new InvalidAskTimeoutError({
87863
+ message: `timeout must be a positive finite duration: ${value}`,
87864
+ value
87865
+ }));
87866
+ return succeed(parsed.value);
87867
+ }
87868
+ //#endregion
87119
87869
  //#region src/cli/format/auth.ts
87120
87870
  function formatAuthPaired(result) {
87121
87871
  return `paired\n${formatRecord([
@@ -87775,9 +88525,6 @@ function formatWaitHuman(input) {
87775
88525
  return details.length > 0 ? `terminal ${input.status}: ${input.terminalId} (${input.threadId}) ${details}` : `terminal ${input.status}: ${input.terminalId} (${input.threadId})`;
87776
88526
  }
87777
88527
  //#endregion
87778
- //#region src/cli/input/service.ts
87779
- var T3Input = class extends Service()("t3cli/T3Input") {};
87780
- //#endregion
87781
88528
  //#region src/cli/terminal/write.ts
87782
88529
  const writeTerminalCommand = make("write", {
87783
88530
  thread: threadFlag,
@@ -88038,270 +88785,6 @@ const addCommand = make("add", {
88038
88785
  else yield* output.printInfo(formatProjectAddedHuman(result.project));
88039
88786
  })).pipe(withDescription("add project"));
88040
88787
  //#endregion
88041
- //#region src/cli/format/thread.ts
88042
- function formatThreadShowJson(thread) {
88043
- return {
88044
- id: thread.id,
88045
- projectId: thread.projectId,
88046
- title: thread.title,
88047
- status: thread.status,
88048
- session: thread.session,
88049
- latestTurn: thread.latestTurn,
88050
- modelSelection: thread.modelSelection,
88051
- runtimeMode: thread.runtimeMode,
88052
- interactionMode: thread.interactionMode,
88053
- branch: thread.branch,
88054
- worktreePath: thread.worktreePath,
88055
- archivedAt: thread.archivedAt,
88056
- createdAt: thread.createdAt,
88057
- updatedAt: thread.updatedAt,
88058
- messageCount: thread.messageCount,
88059
- hasPendingApprovals: thread.hasPendingApprovals,
88060
- hasPendingUserInput: thread.hasPendingUserInput,
88061
- hasActionableProposedPlan: thread.hasActionableProposedPlan,
88062
- pendingApprovals: thread.pendingApprovals,
88063
- pendingUserInputs: thread.pendingUserInputs
88064
- };
88065
- }
88066
- function formatThreadShowHuman(thread) {
88067
- const sections = [formatRecord([
88068
- {
88069
- field: "title",
88070
- value: thread.title
88071
- },
88072
- {
88073
- field: "id",
88074
- value: thread.id
88075
- },
88076
- {
88077
- field: "project",
88078
- value: thread.projectId
88079
- },
88080
- {
88081
- field: "status",
88082
- value: thread.status
88083
- },
88084
- {
88085
- field: "model",
88086
- value: `${thread.modelSelection.instanceId}/${thread.modelSelection.model}`
88087
- },
88088
- {
88089
- field: "runtime",
88090
- value: thread.runtimeMode
88091
- },
88092
- {
88093
- field: "interaction",
88094
- value: thread.interactionMode
88095
- },
88096
- ...thread.branch !== null ? [{
88097
- field: "branch",
88098
- value: thread.branch
88099
- }] : [],
88100
- ...thread.worktreePath !== null ? [{
88101
- field: "worktree",
88102
- value: thread.worktreePath
88103
- }] : [],
88104
- ...thread.archivedAt !== null ? [{
88105
- field: "archived",
88106
- value: thread.archivedAt
88107
- }] : [],
88108
- {
88109
- field: "messages",
88110
- value: String(thread.messageCount)
88111
- },
88112
- {
88113
- field: "updated",
88114
- value: thread.updatedAt
88115
- }
88116
- ])];
88117
- if (thread.pendingApprovals.length > 0) sections.push(`\npending approvals\n${formatTable([
88118
- {
88119
- header: "request",
88120
- value: (approval) => approval.requestId,
88121
- maxWidth: 40
88122
- },
88123
- {
88124
- header: "kind",
88125
- value: (approval) => approval.requestKind,
88126
- maxWidth: 16
88127
- },
88128
- {
88129
- header: "created",
88130
- value: (approval) => approval.createdAt,
88131
- maxWidth: 28
88132
- },
88133
- {
88134
- header: "detail",
88135
- value: (approval) => approval.detail ?? "-",
88136
- maxWidth: 72
88137
- }
88138
- ], thread.pendingApprovals)}`);
88139
- if (thread.pendingUserInputs.length > 0) sections.push(`\npending user inputs\n${formatTable([
88140
- {
88141
- header: "request",
88142
- value: (input) => input.requestId,
88143
- maxWidth: 40
88144
- },
88145
- {
88146
- header: "questions",
88147
- value: (input) => String(input.questions.length),
88148
- maxWidth: 9
88149
- },
88150
- {
88151
- header: "created",
88152
- value: (input) => input.createdAt,
88153
- maxWidth: 28
88154
- },
88155
- {
88156
- header: "prompt",
88157
- value: (input) => input.questions.map((question) => question.question).join("\n"),
88158
- maxWidth: 72
88159
- }
88160
- ], thread.pendingUserInputs)}`);
88161
- return `${sections.join("\n")}\n`;
88162
- }
88163
- function formatThreadsHuman(threads) {
88164
- if (threads.length === 0) return "no threads\n";
88165
- return `${formatTable([
88166
- {
88167
- header: "title",
88168
- value: (thread) => thread.title,
88169
- maxWidth: 36
88170
- },
88171
- {
88172
- header: "id",
88173
- value: (thread) => thread.id,
88174
- maxWidth: 40
88175
- },
88176
- {
88177
- header: "status",
88178
- value: (thread) => threadStatus(thread),
88179
- maxWidth: 18
88180
- },
88181
- {
88182
- header: "updated",
88183
- value: (thread) => thread.updatedAt,
88184
- maxWidth: 28
88185
- },
88186
- {
88187
- header: "flags",
88188
- value: formatThreadFlags,
88189
- maxWidth: 34
88190
- }
88191
- ], threads)}\n`;
88192
- }
88193
- function formatThreadSearchHuman(matches) {
88194
- if (matches.length === 0) return "no matches\n";
88195
- return `${matches.map((match) => formatRecord([
88196
- {
88197
- field: "thread",
88198
- value: match.threadTitle ?? "-"
88199
- },
88200
- {
88201
- field: "thread id",
88202
- value: match.threadId
88203
- },
88204
- {
88205
- field: "project",
88206
- value: match.projectTitle ?? "-"
88207
- },
88208
- {
88209
- field: "project id",
88210
- value: match.projectId
88211
- },
88212
- {
88213
- field: "workspace",
88214
- value: match.workspaceRoot ?? "-"
88215
- },
88216
- {
88217
- field: "branch",
88218
- value: match.branch ?? "-"
88219
- },
88220
- {
88221
- field: "worktree",
88222
- value: match.worktreePath ?? "-"
88223
- },
88224
- {
88225
- field: "source",
88226
- value: match.source
88227
- },
88228
- {
88229
- field: "created",
88230
- value: match.messageCreatedAt ?? "-"
88231
- },
88232
- {
88233
- field: "snippet",
88234
- value: match.snippet
88235
- }
88236
- ])).join("\n\n")}\n`;
88237
- }
88238
- function formatThreadDeletedHuman(input) {
88239
- return `thread deleted: ${input.threadId} (sequence ${input.dispatch.sequence})`;
88240
- }
88241
- function formatThreadStartedHuman(input) {
88242
- return `thread started\n${formatRecord([
88243
- {
88244
- field: "title",
88245
- value: input.thread.title
88246
- },
88247
- {
88248
- field: "id",
88249
- value: input.thread.id
88250
- },
88251
- {
88252
- field: "status",
88253
- value: threadStatus(input.thread)
88254
- },
88255
- {
88256
- field: "sequence",
88257
- value: String(input.sequence)
88258
- }
88259
- ])}`;
88260
- }
88261
- function formatThreadMessagesHuman(thread, limit) {
88262
- return formatChatTranscript(limit === 0 ? thread.messages : thread.messages.slice(-limit));
88263
- }
88264
- function formatWaitDoneHuman(thread) {
88265
- const latest = latestAssistantMessage(thread);
88266
- return `status: ${threadStatus(thread)}\n${latest !== void 0 ? `\n${formatChatTranscript([latest])}` : ""}`;
88267
- }
88268
- function formatThreadMessagesJson(thread, full) {
88269
- return full ? thread : {
88270
- thread: stripThreadMessages(thread),
88271
- messages: thread.messages
88272
- };
88273
- }
88274
- function formatWaitEventNdjson(event) {
88275
- if (event.type !== "thread" && event.type !== "done") return event;
88276
- const compactThread = stripThreadHeavy(event.thread);
88277
- return event.type === "done" ? {
88278
- type: "done",
88279
- thread: compactThread,
88280
- latestAssistantMessage: latestAssistantMessage(event.thread) ?? null
88281
- } : {
88282
- type: "thread",
88283
- thread: compactThread,
88284
- messageCount: event.thread.messages.length
88285
- };
88286
- }
88287
- function stripThreadMessages(thread) {
88288
- const { messages: _messages, ...rest } = thread;
88289
- return rest;
88290
- }
88291
- function formatThreadFlags(thread) {
88292
- const flags = [
88293
- thread.archivedAt !== null ? "archived" : null,
88294
- thread.hasPendingApprovals ? "approval" : null,
88295
- thread.hasPendingUserInput ? "input" : null,
88296
- thread.hasActionableProposedPlan ? "plan" : null
88297
- ].filter((flag) => flag !== null);
88298
- return flags.length > 0 ? flags.join(", ") : "-";
88299
- }
88300
- function stripThreadHeavy(thread) {
88301
- const { messages: _messages, activities: _activities, proposedPlans: _proposedPlans, checkpoints: _checkpoints, ...rest } = thread;
88302
- return rest;
88303
- }
88304
- //#endregion
88305
88788
  //#region src/cli/search.ts
88306
88789
  const searchThreadsCommand = make("search", {
88307
88790
  query: string("query"),
@@ -88361,19 +88844,6 @@ const approveThreadCommand = make("approve", {
88361
88844
  return yield* output.printInfo(`approval submitted: ${result.requestId} (sequence ${result.dispatch.sequence})`);
88362
88845
  })).pipe(withDescription("respond to a pending approval request"));
88363
88846
  //#endregion
88364
- //#region src/cli/interaction/self-action.ts
88365
- const requireSelfActionConfirmation = fn("requireSelfActionConfirmation")(function* (input) {
88366
- if (input.force) return;
88367
- if (!isAgentEnvironment(input.t3CliEnv)) return;
88368
- const callerThreadId = input.t3CliEnv.scope.t3codeThreadId;
88369
- if (callerThreadId === void 0 || callerThreadId.length === 0) return;
88370
- if (input.threadId !== callerThreadId) return;
88371
- yield* fail(new SelfActionError({
88372
- threadId: input.threadId,
88373
- message: `cannot ${input.action} thread ${input.threadId}: command targets the calling thread. Pass --force to confirm.`
88374
- }));
88375
- });
88376
- //#endregion
88377
88847
  //#region src/cli/threads/archive.ts
88378
88848
  const archiveThreadCommand = make("archive", {
88379
88849
  thread: threadFlag,
@@ -88525,27 +88995,26 @@ const interruptThreadCommand = make("interrupt", {
88525
88995
  return yield* output.printInfo(`thread interrupted: ${threadId} (sequence ${dispatch.sequence})`);
88526
88996
  })).pipe(withDescription("interrupt running thread turn"));
88527
88997
  //#endregion
88528
- //#region src/cli/message-input.ts
88529
- function readInitialMessage(input) {
88530
- if (input.message !== void 0 && input.message.length > 0 && input.fromStdin) return fail(new MessageInputError({ message: "pass message argument or --stdin, not both" }));
88531
- if (input.fromStdin) return input.readStdin();
88532
- if (input.message === void 0 || input.message.length === 0) return fail(new MessageInputError({ message: "message required unless --stdin is used" }));
88533
- return succeed(input.message);
88534
- }
88535
- function readJsonAnswers(input) {
88536
- if (input.answers !== void 0 && input.answers.length > 0 && input.fromStdin) return fail(new MessageInputError({ message: "pass --answers or --stdin, not both" }));
88537
- if (input.fromStdin) return input.readStdin().pipe(flatMap(parseJsonAnswers));
88538
- if (input.answers === void 0 || input.answers.length === 0) return fail(new MessageInputError({ message: "answers required unless --stdin is used" }));
88539
- return parseJsonAnswers(input.answers);
88540
- }
88541
- function parseJsonAnswers(text) {
88542
- try {
88543
- const parsed = JSON.parse(text);
88544
- return succeed(decodeUnknownSync(ProviderUserInputAnswers)(parsed));
88545
- } catch {
88546
- return fail(new MessageInputError({ message: "invalid JSON in answers" }));
88547
- }
88548
- }
88998
+ //#region src/cli/threads/pin.ts
88999
+ const pinThreadCommand = make("pin", {
89000
+ thread: threadFlag,
89001
+ format: formatFlag,
89002
+ ...extraArgsConfig
89003
+ }, ({ thread, format }) => gen(function* () {
89004
+ const application = yield* T3Application;
89005
+ const cliRuntime = yield* CliRuntime;
89006
+ const t3CliEnv = yield* loadT3CliEnv;
89007
+ const output = yield* T3Output;
89008
+ const threadId = resolveThreadId({
89009
+ value: getOrUndefined(thread),
89010
+ scope: t3CliEnv.scope
89011
+ });
89012
+ if (threadId === void 0) return yield* fail(new MissingThreadError({ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID" }));
89013
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
89014
+ const dispatch = yield* application.pinThread(threadId);
89015
+ if (resolvedFormat === "json") return yield* output.printJson(dispatch);
89016
+ return yield* output.printInfo(`thread pinned: ${threadId} (sequence ${dispatch.sequence})`);
89017
+ })).pipe(withDescription("pin thread"));
88549
89018
  const respondThreadCommand = make("respond", {
88550
89019
  thread: threadFlag,
88551
89020
  request: string$2("request").pipe(withDescription$1("Pending user-input request id"), optional$2),
@@ -88581,6 +89050,74 @@ const respondThreadCommand = make("respond", {
88581
89050
  return yield* output.printInfo(`user input submitted: ${result.requestId} (sequence ${result.dispatch.sequence})`);
88582
89051
  })).pipe(withDescription("respond to a pending user-input request"));
88583
89052
  //#endregion
89053
+ //#region src/cli/threads/settle.ts
89054
+ const settleThreadCommand = make("settle", {
89055
+ thread: threadFlag,
89056
+ format: formatFlag,
89057
+ ...extraArgsConfig
89058
+ }, ({ thread, format }) => gen(function* () {
89059
+ const application = yield* T3Application;
89060
+ const cliRuntime = yield* CliRuntime;
89061
+ const t3CliEnv = yield* loadT3CliEnv;
89062
+ const output = yield* T3Output;
89063
+ const threadId = resolveThreadId({
89064
+ value: getOrUndefined(thread),
89065
+ scope: t3CliEnv.scope
89066
+ });
89067
+ if (threadId === void 0) return yield* fail(new MissingThreadError({ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID" }));
89068
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
89069
+ const dispatch = yield* application.settleThread(threadId);
89070
+ if (resolvedFormat === "json") return yield* output.printJson(dispatch);
89071
+ return yield* output.printInfo(`thread settled: ${threadId} (sequence ${dispatch.sequence})`);
89072
+ })).pipe(withDescription("settle thread"));
89073
+ const snoozeThreadCommand = make("snooze", {
89074
+ thread: threadFlag,
89075
+ until: string$2("until").pipe(optional$2),
89076
+ preset: choice("preset", [
89077
+ "hour",
89078
+ "evening",
89079
+ "tomorrow",
89080
+ "next-week"
89081
+ ]).pipe(optional$2),
89082
+ format: formatFlag,
89083
+ ...extraArgsConfig
89084
+ }, ({ thread, until, preset, format }) => gen(function* () {
89085
+ const application = yield* T3Application;
89086
+ const cliRuntime = yield* CliRuntime;
89087
+ const t3CliEnv = yield* loadT3CliEnv;
89088
+ const output = yield* T3Output;
89089
+ const threadId = resolveThreadId({
89090
+ value: getOrUndefined(thread),
89091
+ scope: t3CliEnv.scope
89092
+ });
89093
+ if (threadId === void 0) return yield* fail(new MissingThreadError({ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID" }));
89094
+ const untilValue = getOrUndefined(until);
89095
+ const presetValue = getOrUndefined(preset);
89096
+ if (untilValue !== void 0 && presetValue !== void 0) return yield* fail(new InvalidFlagCombinationError({ message: "exactly one of --until or --preset is required" }));
89097
+ let snoozedUntil;
89098
+ if (untilValue !== void 0) snoozedUntil = yield* decodeUnknownEffect(DateTimeUtcFromString)(untilValue).pipe(map(formatIso), mapError(() => new InvalidSnoozeUntilError({
89099
+ message: `invalid ISO-8601 snooze time: ${untilValue}`,
89100
+ value: untilValue
89101
+ })));
89102
+ else if (presetValue !== void 0) snoozedUntil = yield* resolveSnoozePreset(presetValue);
89103
+ else return yield* fail(new InvalidFlagCombinationError({ message: "exactly one of --until or --preset is required" }));
89104
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
89105
+ const dispatch = yield* application.snoozeThread({
89106
+ threadId,
89107
+ snoozedUntil
89108
+ });
89109
+ if (resolvedFormat === "json") return yield* output.printJson(dispatch);
89110
+ return yield* output.printInfo(`thread snoozed: ${threadId} until ${snoozedUntil} (sequence ${dispatch.sequence})`);
89111
+ })).pipe(withDescription("snooze thread"));
89112
+ const resolveSnoozePreset = fn("resolveSnoozePreset")(function* (presetId) {
89113
+ const preset = resolveSnoozePresets(yield* nowAsDate).find((candidate) => candidate.id === presetId);
89114
+ if (preset === void 0) return yield* fail(new UnavailableSnoozePresetError({
89115
+ message: `snooze preset is not available at this time: ${presetId}`,
89116
+ preset: presetId
89117
+ }));
89118
+ return preset.snoozedUntil;
89119
+ });
89120
+ //#endregion
88584
89121
  //#region src/cli/threads/unarchive.ts
88585
89122
  const unarchiveThreadCommand = make("unarchive", {
88586
89123
  thread: threadFlag,
@@ -88602,38 +89139,68 @@ const unarchiveThreadCommand = make("unarchive", {
88602
89139
  return yield* output.printInfo(`thread unarchived: ${threadId} (sequence ${dispatch.sequence})`);
88603
89140
  })).pipe(withDescription("unarchive thread"));
88604
89141
  //#endregion
88605
- //#region src/cli/model-options.ts
88606
- function buildModelOptions(input) {
88607
- const options = /* @__PURE__ */ new Map();
88608
- const optionRecord = getOrUndefined(input.option);
88609
- if (optionRecord !== void 0) for (const [id, value] of Object.entries(optionRecord)) options.set(id, {
88610
- id,
88611
- value: parseModelOptionValue(value)
89142
+ //#region src/cli/threads/unpin.ts
89143
+ const unpinThreadCommand = make("unpin", {
89144
+ thread: threadFlag,
89145
+ format: formatFlag,
89146
+ ...extraArgsConfig
89147
+ }, ({ thread, format }) => gen(function* () {
89148
+ const application = yield* T3Application;
89149
+ const cliRuntime = yield* CliRuntime;
89150
+ const t3CliEnv = yield* loadT3CliEnv;
89151
+ const output = yield* T3Output;
89152
+ const threadId = resolveThreadId({
89153
+ value: getOrUndefined(thread),
89154
+ scope: t3CliEnv.scope
88612
89155
  });
88613
- setStringOption(options, "reasoningEffort", getOrUndefined(input.reasoningEffort));
88614
- setStringOption(options, "effort", getOrUndefined(input.effort));
88615
- setBooleanOption(options, "fastMode", getOrUndefined(input.fastMode));
88616
- setBooleanOption(options, "thinking", getOrUndefined(input.thinking));
88617
- return [...options.values()];
88618
- }
88619
- function parseModelOptionValue(value) {
88620
- const normalized = value.trim().toLowerCase();
88621
- if (normalized === "true") return true;
88622
- if (normalized === "false") return false;
88623
- return value;
88624
- }
88625
- function setStringOption(options, id, value) {
88626
- if (value !== void 0 && value.length > 0) options.set(id, {
88627
- id,
88628
- value
89156
+ if (threadId === void 0) return yield* fail(new MissingThreadError({ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID" }));
89157
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
89158
+ const dispatch = yield* application.unpinThread(threadId);
89159
+ if (resolvedFormat === "json") return yield* output.printJson(dispatch);
89160
+ return yield* output.printInfo(`thread unpinned: ${threadId} (sequence ${dispatch.sequence})`);
89161
+ })).pipe(withDescription("unpin thread"));
89162
+ //#endregion
89163
+ //#region src/cli/threads/unsnooze.ts
89164
+ const unsnoozeThreadCommand = make("unsnooze", {
89165
+ thread: threadFlag,
89166
+ format: formatFlag,
89167
+ ...extraArgsConfig
89168
+ }, ({ thread, format }) => gen(function* () {
89169
+ const application = yield* T3Application;
89170
+ const cliRuntime = yield* CliRuntime;
89171
+ const t3CliEnv = yield* loadT3CliEnv;
89172
+ const output = yield* T3Output;
89173
+ const threadId = resolveThreadId({
89174
+ value: getOrUndefined(thread),
89175
+ scope: t3CliEnv.scope
88629
89176
  });
88630
- }
88631
- function setBooleanOption(options, id, value) {
88632
- if (value !== void 0) options.set(id, {
88633
- id,
88634
- value
89177
+ if (threadId === void 0) return yield* fail(new MissingThreadError({ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID" }));
89178
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
89179
+ const dispatch = yield* application.unsnoozeThread(threadId);
89180
+ if (resolvedFormat === "json") return yield* output.printJson(dispatch);
89181
+ return yield* output.printInfo(`thread unsnoozed: ${threadId} (sequence ${dispatch.sequence})`);
89182
+ })).pipe(withDescription("unsnooze thread"));
89183
+ //#endregion
89184
+ //#region src/cli/threads/unsettle.ts
89185
+ const unsettleThreadCommand = make("unsettle", {
89186
+ thread: threadFlag,
89187
+ format: formatFlag,
89188
+ ...extraArgsConfig
89189
+ }, ({ thread, format }) => gen(function* () {
89190
+ const application = yield* T3Application;
89191
+ const cliRuntime = yield* CliRuntime;
89192
+ const t3CliEnv = yield* loadT3CliEnv;
89193
+ const output = yield* T3Output;
89194
+ const threadId = resolveThreadId({
89195
+ value: getOrUndefined(thread),
89196
+ scope: t3CliEnv.scope
88635
89197
  });
88636
- }
89198
+ if (threadId === void 0) return yield* fail(new MissingThreadError({ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID" }));
89199
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
89200
+ const dispatch = yield* application.unsettleThread(threadId);
89201
+ if (resolvedFormat === "json") return yield* output.printJson(dispatch);
89202
+ return yield* output.printInfo(`thread unsettled: ${threadId} (sequence ${dispatch.sequence})`);
89203
+ })).pipe(withDescription("unsettle thread"));
88637
89204
  //#endregion
88638
89205
  //#region src/cli/threads/update.ts
88639
89206
  const updateThreadCommand = make("update", {
@@ -88708,6 +89275,12 @@ function createThreadCommand() {
88708
89275
  respondThreadCommand,
88709
89276
  archiveThreadCommand,
88710
89277
  interruptThreadCommand,
89278
+ settleThreadCommand,
89279
+ unsettleThreadCommand,
89280
+ snoozeThreadCommand,
89281
+ unsnoozeThreadCommand,
89282
+ pinThreadCommand,
89283
+ unpinThreadCommand,
88711
89284
  unarchiveThreadCommand,
88712
89285
  updateThreadCommand,
88713
89286
  deleteThreadCommand,
@@ -88863,7 +89436,11 @@ const sendThreadCommand = make("send", {
88863
89436
  return yield* void_;
88864
89437
  }
88865
89438
  const result = yield* application.sendThread(input, { until: "visible" });
88866
- if (resolvedFormat === "json") return yield* output.printJson(result);
89439
+ if (resolvedFormat === "json") return yield* output.printJson({
89440
+ dispatch: result.dispatch,
89441
+ threadId: result.threadId,
89442
+ thread: result.thread
89443
+ });
88867
89444
  return yield* output.printInfo(`message sent: ${result.threadId}`);
88868
89445
  })).pipe(withDescription("send message to existing thread"));
88869
89446
  //#endregion
@@ -88968,7 +89545,12 @@ const startThreadCommand = make("start", {
88968
89545
  return;
88969
89546
  }
88970
89547
  const result = yield* application.startThread(input, { until: "visible" });
88971
- if (resolvedFormat === "json") yield* output.printJson(result);
89548
+ if (resolvedFormat === "json") yield* output.printJson({
89549
+ dispatch: result.dispatch,
89550
+ project: result.project,
89551
+ threadId: result.threadId,
89552
+ thread: result.thread
89553
+ });
88972
89554
  else yield* output.printInfo(formatThreadStartedHuman({
88973
89555
  thread: result.thread,
88974
89556
  sequence: result.dispatch.sequence
@@ -88979,14 +89561,24 @@ const startThreadCommand = make("start", {
88979
89561
  const getThreadTranscriptCommand = make("transcript", {
88980
89562
  thread: threadFlag,
88981
89563
  limit: integer$1("limit").pipe(withDefault(20)),
89564
+ turnLimit: integer$1("turn-limit").pipe(optional$2),
89565
+ beforeCursor: string$2("before-cursor").pipe(optional$2),
89566
+ all: boolean("all"),
88982
89567
  full: boolean("full"),
88983
89568
  format: formatFlag,
88984
89569
  ...extraArgsConfig
88985
- }, ({ thread, limit, full, format }) => gen(function* () {
89570
+ }, ({ thread, limit, turnLimit, beforeCursor, all, full, format }) => gen(function* () {
88986
89571
  if (limit < 0) return yield* fail(new InvalidLimitError({
88987
89572
  message: `invalid limit: ${limit}`,
88988
89573
  value: String(limit)
88989
89574
  }));
89575
+ const turnLimitValue = getOrUndefined(turnLimit);
89576
+ const beforeCursorValue = getOrUndefined(beforeCursor);
89577
+ if (turnLimitValue !== void 0 && turnLimitValue <= 0) return yield* fail(new InvalidLimitError({
89578
+ message: `invalid turn limit: ${turnLimitValue}`,
89579
+ value: String(turnLimitValue)
89580
+ }));
89581
+ if (all && (turnLimitValue !== void 0 || beforeCursorValue !== void 0)) return yield* fail(new InvalidFlagCombinationError({ message: "--all cannot be combined with --turn-limit or --before-cursor" }));
88990
89582
  const application = yield* T3Application;
88991
89583
  const cliRuntime = yield* CliRuntime;
88992
89584
  const t3CliEnv = yield* loadT3CliEnv;
@@ -88997,7 +89589,13 @@ const getThreadTranscriptCommand = make("transcript", {
88997
89589
  });
88998
89590
  if (threadId === void 0) return yield* fail(new MissingThreadError({ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID" }));
88999
89591
  const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
89000
- const detail = yield* application.getThreadMessages(threadId);
89592
+ const detail = yield* application.getThreadMessages({
89593
+ threadId,
89594
+ ...!all ? { window: {
89595
+ turnLimit: turnLimitValue ?? (beforeCursorValue === void 0 ? 10 : 20),
89596
+ ...beforeCursorValue !== void 0 ? { beforeCursor: beforeCursorValue } : {}
89597
+ } } : {}
89598
+ });
89001
89599
  if (resolvedFormat === "json") return yield* output.printJson(formatThreadMessagesJson(detail, full));
89002
89600
  return yield* output.writeStdout(formatThreadMessagesHuman(detail, limit));
89003
89601
  })).pipe(withDescription("get latest thread transcript"));
@@ -89028,6 +89626,7 @@ const waitForThreadCommand = make("wait", {
89028
89626
  function createCliCommand() {
89029
89627
  return make("t3cli").pipe(withDescription("non-interactive cli for running t3code server"), withGlobalFlags([cliEnvironmentSetting]), withSubcommands([
89030
89628
  createActionCommand(),
89629
+ askCommand,
89031
89630
  createAuthCommand(),
89032
89631
  createEnvCommand(),
89033
89632
  listThreadsCommand,
@@ -89175,7 +89774,7 @@ var T3Version = class extends Service()("t3cli/T3Version") {};
89175
89774
  //#endregion
89176
89775
  //#region src/version/layer.ts
89177
89776
  const PackageJsonSchema = fromJsonString(Struct({ version: String$1 }));
89178
- const T3VersionBundledLive = sync$1(T3Version, () => ({ version: "0.14.2" }));
89777
+ const T3VersionBundledLive = sync$1(T3Version, () => ({ version: "0.15.0" }));
89179
89778
  effect(T3Version, gen(function* () {
89180
89779
  const packageJson = yield* (yield* FileSystem).readFileString(fileURLToPath(new URL("../../package.json", import.meta.url)));
89181
89780
  return { version: (yield* decodeUnknownEffect(PackageJsonSchema)(packageJson)).version };