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
@@ -0,0 +1,46 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import { Command } from "effect/unstable/cli";
4
+
5
+ import { T3Application } from "../../application/service.ts";
6
+ import { loadT3CliEnv } from "../../config/env/env.ts";
7
+ import { MissingThreadError } from "../error.ts";
8
+ import { extraArgsConfig } from "../extra-args.ts";
9
+ import { formatFlag, threadFlag } from "../flags.ts";
10
+ import { resolveOutputFormat } from "../format/output.ts";
11
+ import { T3Output } from "../output/service.ts";
12
+ import { CliRuntime } from "../runtime/service.ts";
13
+ import { resolveThreadId } from "../scope/index.ts";
14
+
15
+ export const settleThreadCommand = Command.make(
16
+ "settle",
17
+ {
18
+ thread: threadFlag,
19
+ format: formatFlag,
20
+ ...extraArgsConfig,
21
+ },
22
+ ({ thread, format }) =>
23
+ Effect.gen(function* () {
24
+ const application = yield* T3Application;
25
+ const cliRuntime = yield* CliRuntime;
26
+ const t3CliEnv = yield* loadT3CliEnv;
27
+ const output = yield* T3Output;
28
+ const threadId = resolveThreadId({
29
+ value: Option.getOrUndefined(thread),
30
+ scope: t3CliEnv.scope,
31
+ });
32
+ if (threadId === undefined) {
33
+ return yield* Effect.fail(
34
+ new MissingThreadError({
35
+ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID",
36
+ }),
37
+ );
38
+ }
39
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
40
+ const dispatch = yield* application.settleThread(threadId);
41
+ if (resolvedFormat === "json") {
42
+ return yield* output.printJson(dispatch);
43
+ }
44
+ return yield* output.printInfo(`thread settled: ${threadId} (sequence ${dispatch.sequence})`);
45
+ }),
46
+ ).pipe(Command.withDescription("settle thread"));
@@ -0,0 +1,117 @@
1
+ import * as DateTime from "effect/DateTime";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Option from "effect/Option";
4
+ import * as Schema from "effect/Schema";
5
+ import { Command, Flag } from "effect/unstable/cli";
6
+ import {
7
+ resolveSnoozePresets,
8
+ type SnoozePresetId,
9
+ } from "@t3tools/client-runtime/state/thread-settled";
10
+
11
+ import { T3Application } from "../../application/service.ts";
12
+ import { loadT3CliEnv } from "../../config/env/env.ts";
13
+ import {
14
+ InvalidFlagCombinationError,
15
+ InvalidSnoozeUntilError,
16
+ MissingThreadError,
17
+ UnavailableSnoozePresetError,
18
+ } from "../error.ts";
19
+ import { extraArgsConfig } from "../extra-args.ts";
20
+ import { formatFlag, threadFlag } from "../flags.ts";
21
+ import { resolveOutputFormat } from "../format/output.ts";
22
+ import { T3Output } from "../output/service.ts";
23
+ import { CliRuntime } from "../runtime/service.ts";
24
+ import { resolveThreadId } from "../scope/index.ts";
25
+
26
+ const snoozePresetChoices = [
27
+ "hour",
28
+ "evening",
29
+ "tomorrow",
30
+ "next-week",
31
+ ] as const satisfies ReadonlyArray<SnoozePresetId>;
32
+
33
+ export const snoozeThreadCommand = Command.make(
34
+ "snooze",
35
+ {
36
+ thread: threadFlag,
37
+ until: Flag.string("until").pipe(Flag.optional),
38
+ preset: Flag.choice("preset", snoozePresetChoices).pipe(Flag.optional),
39
+ format: formatFlag,
40
+ ...extraArgsConfig,
41
+ },
42
+ ({ thread, until, preset, format }) =>
43
+ Effect.gen(function* () {
44
+ const application = yield* T3Application;
45
+ const cliRuntime = yield* CliRuntime;
46
+ const t3CliEnv = yield* loadT3CliEnv;
47
+ const output = yield* T3Output;
48
+ const threadId = resolveThreadId({
49
+ value: Option.getOrUndefined(thread),
50
+ scope: t3CliEnv.scope,
51
+ });
52
+ if (threadId === undefined) {
53
+ return yield* Effect.fail(
54
+ new MissingThreadError({
55
+ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID",
56
+ }),
57
+ );
58
+ }
59
+
60
+ const untilValue = Option.getOrUndefined(until);
61
+ const presetValue = Option.getOrUndefined(preset);
62
+ if (untilValue !== undefined && presetValue !== undefined) {
63
+ return yield* Effect.fail(
64
+ new InvalidFlagCombinationError({
65
+ message: "exactly one of --until or --preset is required",
66
+ }),
67
+ );
68
+ }
69
+
70
+ let snoozedUntil: string;
71
+ if (untilValue !== undefined) {
72
+ snoozedUntil = yield* Schema.decodeUnknownEffect(Schema.DateTimeUtcFromString)(
73
+ untilValue,
74
+ ).pipe(
75
+ Effect.map(DateTime.formatIso),
76
+ Effect.mapError(
77
+ () =>
78
+ new InvalidSnoozeUntilError({
79
+ message: `invalid ISO-8601 snooze time: ${untilValue}`,
80
+ value: untilValue,
81
+ }),
82
+ ),
83
+ );
84
+ } else if (presetValue !== undefined) {
85
+ snoozedUntil = yield* resolveSnoozePreset(presetValue);
86
+ } else {
87
+ return yield* Effect.fail(
88
+ new InvalidFlagCombinationError({
89
+ message: "exactly one of --until or --preset is required",
90
+ }),
91
+ );
92
+ }
93
+
94
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
95
+ const dispatch = yield* application.snoozeThread({ threadId, snoozedUntil });
96
+ if (resolvedFormat === "json") {
97
+ return yield* output.printJson(dispatch);
98
+ }
99
+ return yield* output.printInfo(
100
+ `thread snoozed: ${threadId} until ${snoozedUntil} (sequence ${dispatch.sequence})`,
101
+ );
102
+ }),
103
+ ).pipe(Command.withDescription("snooze thread"));
104
+
105
+ const resolveSnoozePreset = Effect.fn("resolveSnoozePreset")(function* (presetId: SnoozePresetId) {
106
+ const now = yield* DateTime.nowAsDate;
107
+ const preset = resolveSnoozePresets(now).find((candidate) => candidate.id === presetId);
108
+ if (preset === undefined) {
109
+ return yield* Effect.fail(
110
+ new UnavailableSnoozePresetError({
111
+ message: `snooze preset is not available at this time: ${presetId}`,
112
+ preset: presetId,
113
+ }),
114
+ );
115
+ }
116
+ return preset.snoozedUntil;
117
+ });
@@ -129,7 +129,12 @@ export const startThreadCommand = Command.make(
129
129
 
130
130
  const result = yield* application.startThread(input, { until: "visible" });
131
131
  if (resolvedFormat === "json") {
132
- yield* output.printJson(result);
132
+ yield* output.printJson({
133
+ dispatch: result.dispatch,
134
+ project: result.project,
135
+ threadId: result.threadId,
136
+ thread: result.thread,
137
+ });
133
138
  } else {
134
139
  yield* output.printInfo(
135
140
  formatThreadStartedHuman({
@@ -0,0 +1,48 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import { Command } from "effect/unstable/cli";
4
+
5
+ import { T3Application } from "../../application/service.ts";
6
+ import { loadT3CliEnv } from "../../config/env/env.ts";
7
+ import { MissingThreadError } from "../error.ts";
8
+ import { extraArgsConfig } from "../extra-args.ts";
9
+ import { formatFlag, threadFlag } from "../flags.ts";
10
+ import { resolveOutputFormat } from "../format/output.ts";
11
+ import { T3Output } from "../output/service.ts";
12
+ import { CliRuntime } from "../runtime/service.ts";
13
+ import { resolveThreadId } from "../scope/index.ts";
14
+
15
+ export const unpinThreadCommand = Command.make(
16
+ "unpin",
17
+ {
18
+ thread: threadFlag,
19
+ format: formatFlag,
20
+ ...extraArgsConfig,
21
+ },
22
+ ({ thread, format }) =>
23
+ Effect.gen(function* () {
24
+ const application = yield* T3Application;
25
+ const cliRuntime = yield* CliRuntime;
26
+ const t3CliEnv = yield* loadT3CliEnv;
27
+ const output = yield* T3Output;
28
+ const threadId = resolveThreadId({
29
+ value: Option.getOrUndefined(thread),
30
+ scope: t3CliEnv.scope,
31
+ });
32
+ if (threadId === undefined) {
33
+ return yield* Effect.fail(
34
+ new MissingThreadError({
35
+ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID",
36
+ }),
37
+ );
38
+ }
39
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
40
+ const dispatch = yield* application.unpinThread(threadId);
41
+ if (resolvedFormat === "json") {
42
+ return yield* output.printJson(dispatch);
43
+ }
44
+ return yield* output.printInfo(
45
+ `thread unpinned: ${threadId} (sequence ${dispatch.sequence})`,
46
+ );
47
+ }),
48
+ ).pipe(Command.withDescription("unpin thread"));
@@ -0,0 +1,48 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import { Command } from "effect/unstable/cli";
4
+
5
+ import { T3Application } from "../../application/service.ts";
6
+ import { loadT3CliEnv } from "../../config/env/env.ts";
7
+ import { MissingThreadError } from "../error.ts";
8
+ import { extraArgsConfig } from "../extra-args.ts";
9
+ import { formatFlag, threadFlag } from "../flags.ts";
10
+ import { resolveOutputFormat } from "../format/output.ts";
11
+ import { T3Output } from "../output/service.ts";
12
+ import { CliRuntime } from "../runtime/service.ts";
13
+ import { resolveThreadId } from "../scope/index.ts";
14
+
15
+ export const unsettleThreadCommand = Command.make(
16
+ "unsettle",
17
+ {
18
+ thread: threadFlag,
19
+ format: formatFlag,
20
+ ...extraArgsConfig,
21
+ },
22
+ ({ thread, format }) =>
23
+ Effect.gen(function* () {
24
+ const application = yield* T3Application;
25
+ const cliRuntime = yield* CliRuntime;
26
+ const t3CliEnv = yield* loadT3CliEnv;
27
+ const output = yield* T3Output;
28
+ const threadId = resolveThreadId({
29
+ value: Option.getOrUndefined(thread),
30
+ scope: t3CliEnv.scope,
31
+ });
32
+ if (threadId === undefined) {
33
+ return yield* Effect.fail(
34
+ new MissingThreadError({
35
+ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID",
36
+ }),
37
+ );
38
+ }
39
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
40
+ const dispatch = yield* application.unsettleThread(threadId);
41
+ if (resolvedFormat === "json") {
42
+ return yield* output.printJson(dispatch);
43
+ }
44
+ return yield* output.printInfo(
45
+ `thread unsettled: ${threadId} (sequence ${dispatch.sequence})`,
46
+ );
47
+ }),
48
+ ).pipe(Command.withDescription("unsettle thread"));
@@ -0,0 +1,48 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import { Command } from "effect/unstable/cli";
4
+
5
+ import { T3Application } from "../../application/service.ts";
6
+ import { loadT3CliEnv } from "../../config/env/env.ts";
7
+ import { MissingThreadError } from "../error.ts";
8
+ import { extraArgsConfig } from "../extra-args.ts";
9
+ import { formatFlag, threadFlag } from "../flags.ts";
10
+ import { resolveOutputFormat } from "../format/output.ts";
11
+ import { T3Output } from "../output/service.ts";
12
+ import { CliRuntime } from "../runtime/service.ts";
13
+ import { resolveThreadId } from "../scope/index.ts";
14
+
15
+ export const unsnoozeThreadCommand = Command.make(
16
+ "unsnooze",
17
+ {
18
+ thread: threadFlag,
19
+ format: formatFlag,
20
+ ...extraArgsConfig,
21
+ },
22
+ ({ thread, format }) =>
23
+ Effect.gen(function* () {
24
+ const application = yield* T3Application;
25
+ const cliRuntime = yield* CliRuntime;
26
+ const t3CliEnv = yield* loadT3CliEnv;
27
+ const output = yield* T3Output;
28
+ const threadId = resolveThreadId({
29
+ value: Option.getOrUndefined(thread),
30
+ scope: t3CliEnv.scope,
31
+ });
32
+ if (threadId === undefined) {
33
+ return yield* Effect.fail(
34
+ new MissingThreadError({
35
+ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID",
36
+ }),
37
+ );
38
+ }
39
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
40
+ const dispatch = yield* application.unsnoozeThread(threadId);
41
+ if (resolvedFormat === "json") {
42
+ return yield* output.printJson(dispatch);
43
+ }
44
+ return yield* output.printInfo(
45
+ `thread unsnoozed: ${threadId} (sequence ${dispatch.sequence})`,
46
+ );
47
+ }),
48
+ ).pipe(Command.withDescription("unsnooze thread"));
@@ -16,10 +16,20 @@ import { T3CodeConnectionError } from "./error.ts";
16
16
  import { T3CodeConnectionProvider } from "./service.ts";
17
17
  import type { T3CodeConnection } from "./type.ts";
18
18
 
19
+ export interface T3PreparedConnection extends PreparedConnection {
20
+ readonly httpAuthorization: {
21
+ readonly _tag: "Bearer";
22
+ readonly token: string;
23
+ };
24
+ }
25
+
19
26
  export class T3PreparedConnectionProvider extends Context.Service<
20
27
  T3PreparedConnectionProvider,
21
28
  {
22
- readonly get: Effect.Effect<PreparedConnection, ConnectionAttemptError | T3CodeConnectionError>;
29
+ readonly get: Effect.Effect<
30
+ T3PreparedConnection,
31
+ ConnectionAttemptError | T3CodeConnectionError
32
+ >;
23
33
  }
24
34
  >()("t3cli/T3PreparedConnectionProvider") {}
25
35
 
@@ -59,7 +69,7 @@ const makePreparedConnection = Effect.fn("makePreparedConnection")(function* (
59
69
  label: descriptor.label,
60
70
  connectionId: descriptor.environmentId,
61
71
  }),
62
- } satisfies PreparedConnection;
72
+ } satisfies T3PreparedConnection;
63
73
  });
64
74
 
65
75
  const makeT3PreparedConnectionProvider = Effect.fn("makeT3PreparedConnectionProvider")(
@@ -0,0 +1,10 @@
1
+ import * as Schema from "effect/Schema";
2
+
3
+ export class ThreadSnapshotRequestError extends Schema.TaggedErrorClass<ThreadSnapshotRequestError>()(
4
+ "ThreadSnapshotRequestError",
5
+ {
6
+ message: Schema.String,
7
+ threadId: Schema.String,
8
+ cause: Schema.Defect(),
9
+ },
10
+ ) {}
@@ -4,4 +4,5 @@ export {
4
4
  type Orchestration,
5
5
  type OrchestrationError,
6
6
  } from "./service.ts";
7
+ export { ThreadSnapshotRequestError } from "./error.ts";
7
8
  export { makeT3Orchestration, T3OrchestrationLive } from "./layer.ts";
@@ -3,6 +3,7 @@ import * as Layer from "effect/Layer";
3
3
  import * as Option from "effect/Option";
4
4
  import * as Sink from "effect/Sink";
5
5
  import * as Stream from "effect/Stream";
6
+ import { HttpClient } from "effect/unstable/http";
6
7
  import {
7
8
  ORCHESTRATION_WS_METHODS,
8
9
  ThreadId,
@@ -12,14 +13,25 @@ import {
12
13
  type OrchestrationShellStreamItem,
13
14
  type OrchestrationThreadStreamItem,
14
15
  } from "@t3tools/contracts";
16
+ import { environmentEndpointUrl } from "@t3tools/client-runtime/environment";
17
+ import {
18
+ executeEnvironmentHttpRequest,
19
+ makeEnvironmentHttpApiClient,
20
+ } from "@t3tools/client-runtime/rpc";
15
21
  import { applyShellStreamEvent } from "@t3tools/client-runtime/state/shell";
16
22
 
23
+ import { T3PreparedConnectionProvider } from "../connection/prepared.ts";
17
24
  import { RpcError } from "../rpc/error.ts";
18
25
  import { T3RpcOperations } from "../rpc/operation.ts";
26
+ import { ThreadSnapshotRequestError } from "./error.ts";
19
27
  import { T3Orchestration, type OpenThread, type Orchestration } from "./service.ts";
20
28
 
29
+ const THREAD_SNAPSHOT_TIMEOUT_MS = 30_000;
30
+
21
31
  export const makeT3Orchestration = Effect.fn("makeT3Orchestration")(function* () {
22
32
  const rpc = yield* T3RpcOperations;
33
+ const preparedConnectionProvider = yield* T3PreparedConnectionProvider;
34
+ const httpClient = yield* HttpClient.HttpClient;
23
35
 
24
36
  const watchShellSnapshots: Orchestration["watchShellSnapshots"] = () =>
25
37
  rpc
@@ -133,6 +145,65 @@ export const makeT3Orchestration = Effect.fn("makeT3Orchestration")(function* ()
133
145
  }
134
146
  return value.snapshot.thread;
135
147
  });
148
+ const getThreadDetailSnapshot: Orchestration["getThreadDetailSnapshot"] = Effect.fn(
149
+ "T3OrchestrationLive.getThreadDetailSnapshot",
150
+ )(function* (input) {
151
+ const paginationSupported =
152
+ input.window === undefined
153
+ ? true
154
+ : (yield* getServerConfig()).threadSnapshotPagination === true;
155
+ const window = paginationSupported ? input.window : undefined;
156
+ const prepared = yield* preparedConnectionProvider.get.pipe(
157
+ Effect.mapError(
158
+ (cause) =>
159
+ new ThreadSnapshotRequestError({
160
+ message: "failed to prepare the thread snapshot request",
161
+ threadId: input.threadId,
162
+ cause,
163
+ }),
164
+ ),
165
+ );
166
+ const threadId = ThreadId.make(input.threadId);
167
+ const requestUrl = environmentEndpointUrl(
168
+ prepared.httpBaseUrl,
169
+ `/api/orchestration/threads/${threadId}`,
170
+ );
171
+ const client = yield* makeEnvironmentHttpApiClient(prepared.httpBaseUrl).pipe(
172
+ Effect.provideService(HttpClient.HttpClient, httpClient),
173
+ Effect.mapError(
174
+ (cause) =>
175
+ new ThreadSnapshotRequestError({
176
+ message: "failed to create the thread snapshot client",
177
+ threadId: input.threadId,
178
+ cause,
179
+ }),
180
+ ),
181
+ );
182
+ return yield* executeEnvironmentHttpRequest(
183
+ requestUrl,
184
+ THREAD_SNAPSHOT_TIMEOUT_MS,
185
+ client.orchestration.threadSnapshot({
186
+ params: { threadId },
187
+ payload: {
188
+ ...(window !== undefined ? { turnLimit: window.turnLimit } : {}),
189
+ ...(window?.beforeCursor !== undefined ? { beforeCursor: window.beforeCursor } : {}),
190
+ },
191
+ headers: {
192
+ authorization: `Bearer ${prepared.httpAuthorization.token}`,
193
+ },
194
+ }),
195
+ ).pipe(
196
+ Effect.provideService(HttpClient.HttpClient, httpClient),
197
+ Effect.mapError(
198
+ (cause) =>
199
+ new ThreadSnapshotRequestError({
200
+ message: "failed to load the thread snapshot",
201
+ threadId: input.threadId,
202
+ cause,
203
+ }),
204
+ ),
205
+ );
206
+ });
136
207
  const openThread = Effect.fn("T3OrchestrationLive.openThread")(function* (threadId: string) {
137
208
  return yield* watchThreadItems(threadId).pipe(
138
209
  Stream.peel(Sink.head<OrchestrationThreadStreamItem>()),
@@ -167,6 +238,7 @@ export const makeT3Orchestration = Effect.fn("makeT3Orchestration")(function* ()
167
238
  getArchivedShellSnapshot,
168
239
  searchThreads,
169
240
  getThreadSnapshot,
241
+ getThreadDetailSnapshot,
170
242
  watchShellSnapshots,
171
243
  watchShellSequence,
172
244
  watchThreadItems,
@@ -10,22 +10,26 @@ import type {
10
10
  OrchestrationSearchThreadsInput,
11
11
  OrchestrationSearchThreadsResult,
12
12
  OrchestrationThread,
13
+ OrchestrationThreadDetailSnapshot,
14
+ OrchestrationThreadDetailWindow,
13
15
  OrchestrationThreadStreamItem,
14
16
  ServerProviders,
15
17
  } from "@t3tools/contracts";
16
18
 
19
+ import type { ThreadSnapshotRequestError } from "./error.ts";
17
20
  import type { RpcError } from "../rpc/error.ts";
18
21
 
19
- export type OrchestrationError = RpcError;
22
+ export type OrchestrationError = RpcError | ThreadSnapshotRequestError;
20
23
 
21
24
  export type OpenThread = {
22
25
  readonly snapshot: OrchestrationThread;
23
26
  readonly events: Stream.Stream<OrchestrationEvent, OrchestrationError>;
24
27
  };
25
28
 
26
- export type ServerConfigForCli = {
29
+ export interface ServerConfigForCli {
27
30
  readonly providers: ServerProviders;
28
- };
31
+ readonly threadSnapshotPagination?: boolean;
32
+ }
29
33
 
30
34
  export type Orchestration = {
31
35
  readonly dispatch: (
@@ -43,6 +47,10 @@ export type Orchestration = {
43
47
  readonly getThreadSnapshot: (
44
48
  threadId: string,
45
49
  ) => Effect.Effect<OrchestrationThread, OrchestrationError>;
50
+ readonly getThreadDetailSnapshot: (input: {
51
+ readonly threadId: string;
52
+ readonly window?: OrchestrationThreadDetailWindow;
53
+ }) => Effect.Effect<OrchestrationThreadDetailSnapshot, OrchestrationError>;
46
54
  readonly watchShellSnapshots: () => Stream.Stream<
47
55
  OrchestrationShellSnapshot,
48
56
  OrchestrationError,
@@ -31,6 +31,7 @@ export const CliServerConfig = Schema.Struct({
31
31
  }),
32
32
  }),
33
33
  providers: ServerProviders,
34
+ threadSnapshotPagination: Schema.optionalKey(Schema.Boolean),
34
35
  });
35
36
  export type CliServerConfig = typeof CliServerConfig.Type;
36
37
 
@@ -63,18 +63,23 @@ const T3ConfigConnectionProviderLayer = Layer.effect(
63
63
  }),
64
64
  ).pipe(Layer.provide(T3ConfigLayer));
65
65
 
66
+ const T3PreparedConnectionLayer = T3PreparedConnectionProviderLive.pipe(
67
+ Layer.provide(Layer.mergeAll(T3ConfigConnectionProviderLayer, NodeHttpClient.layerUndici)),
68
+ );
66
69
  const T3RpcLayer = T3RpcLive.pipe(
67
70
  Layer.provide(
68
71
  Layer.mergeAll(
69
- T3PreparedConnectionProviderLive.pipe(
70
- Layer.provide(Layer.mergeAll(T3ConfigConnectionProviderLayer, NodeHttpClient.layerUndici)),
71
- ),
72
+ T3PreparedConnectionLayer,
72
73
  T3RpcSessionFactoryLive.pipe(Layer.provide(NodeSocket.layerWebSocketConstructor)),
73
74
  ),
74
75
  ),
75
76
  );
76
77
  const T3RpcOperationsLayer = T3RpcOperationsLive.pipe(Layer.provide(T3RpcLayer));
77
- export const T3OrchestrationLayer = T3OrchestrationLive.pipe(Layer.provide(T3RpcOperationsLayer));
78
+ export const T3OrchestrationLayer = T3OrchestrationLive.pipe(
79
+ Layer.provide(
80
+ Layer.mergeAll(T3RpcOperationsLayer, T3PreparedConnectionLayer, NodeHttpClient.layerUndici),
81
+ ),
82
+ );
78
83
  export const T3PreviewAutomationLayer = T3PreviewAutomationLive.pipe(
79
84
  Layer.provide(T3RpcOperationsLayer),
80
85
  );