t3code-cli 0.10.0 → 0.12.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 (328) hide show
  1. package/README.md +75 -11
  2. package/dist/application.js +2 -2
  3. package/dist/auth.js +1 -1
  4. package/dist/bin.js +86754 -2675
  5. package/dist/cli.js +15 -2
  6. package/dist/config.js +120 -2
  7. package/dist/connection.js +2 -12
  8. package/dist/index.js +1 -1
  9. package/dist/node.js +6 -0
  10. package/dist/orchestration.js +2 -2
  11. package/dist/rpc.js +2 -2
  12. package/dist/runtime.js +2 -2
  13. package/dist/shared.js +43850 -38040
  14. package/dist/src/application/actions.d.ts +25 -0
  15. package/dist/src/application/index.d.ts +3 -2
  16. package/dist/src/application/layer.d.ts +99 -842
  17. package/dist/src/application/model-selection.d.ts +17 -2
  18. package/dist/src/application/models.d.ts +1 -87
  19. package/dist/src/application/project-commands.d.ts +31 -2
  20. package/dist/src/application/projects.d.ts +15 -137
  21. package/dist/src/application/service.d.ts +147 -5
  22. package/dist/src/application/shell-sequence.d.ts +5 -4
  23. package/dist/src/application/terminals.d.ts +66 -0
  24. package/dist/src/application/thread-commands.d.ts +48 -1
  25. package/dist/src/application/thread-update.d.ts +8 -0
  26. package/dist/src/application/thread-wait.d.ts +4 -6
  27. package/dist/src/application/threads.d.ts +36 -14
  28. package/dist/src/auth/error.d.ts +2 -1
  29. package/dist/src/auth/index.d.ts +1 -1
  30. package/dist/src/auth/layer.d.ts +34 -6
  31. package/dist/src/auth/local-base-dir.d.ts +5 -2
  32. package/dist/src/auth/local-origin.d.ts +3 -3
  33. package/dist/src/auth/local-token.d.ts +3 -3
  34. package/dist/src/auth/service.d.ts +15 -3
  35. package/dist/src/auth/type.d.ts +40 -1
  36. package/dist/src/cli/env/flag.d.ts +2 -0
  37. package/dist/src/cli/env/index.d.ts +2 -0
  38. package/dist/src/cli/env/selection-layer.d.ts +3 -0
  39. package/dist/src/cli/flags.d.ts +5 -0
  40. package/dist/src/cli/format/index.d.ts +1 -0
  41. package/dist/src/cli/format/output.d.ts +12 -0
  42. package/dist/src/cli/index.d.ts +4 -0
  43. package/dist/src/cli/runtime/index.d.ts +1 -0
  44. package/dist/src/cli/runtime/service.d.ts +16 -0
  45. package/dist/src/{scope → cli/scope}/resolve.d.ts +5 -4
  46. package/dist/src/config/config.d.ts +49 -0
  47. package/dist/src/config/credential/cipher-node.d.ts +3 -0
  48. package/dist/src/config/credential/cipher-web.d.ts +3 -0
  49. package/dist/src/config/credential/cipher.d.ts +29 -0
  50. package/dist/src/config/credential/env.d.ts +3 -0
  51. package/dist/src/config/credential/error.d.ts +8 -0
  52. package/dist/src/config/credential/index.d.ts +6 -0
  53. package/dist/src/config/credential/service.d.ts +34 -0
  54. package/dist/src/config/env/env.d.ts +55 -0
  55. package/dist/src/config/env/index.d.ts +2 -0
  56. package/dist/src/{layout/base-dir.d.ts → config/env/layout.d.ts} +0 -1
  57. package/dist/src/config/environment-name/index.d.ts +1 -0
  58. package/dist/src/config/environment-name/name.d.ts +10 -0
  59. package/dist/src/config/error.d.ts +4 -11
  60. package/dist/src/config/index.d.ts +10 -5
  61. package/dist/src/config/keystore/error.d.ts +8 -0
  62. package/dist/src/config/keystore/file.d.ts +9 -0
  63. package/dist/src/config/keystore/index.d.ts +4 -0
  64. package/dist/src/config/keystore/keyring-node.d.ts +4 -0
  65. package/dist/src/config/keystore/service.d.ts +33 -0
  66. package/dist/src/config/paths/index.d.ts +1 -0
  67. package/dist/src/config/paths/paths.d.ts +6 -0
  68. package/dist/src/config/persist/file-mode.d.ts +4 -0
  69. package/dist/src/config/persist/migration.d.ts +68 -0
  70. package/dist/src/config/persist/persist.d.ts +40 -0
  71. package/dist/src/config/persist/schema.d.ts +68 -0
  72. package/dist/src/config/resolve/resolve.d.ts +40 -0
  73. package/dist/src/config/selection/index.d.ts +1 -0
  74. package/dist/src/config/selection/resolve.d.ts +4 -0
  75. package/dist/src/config/selection/service.d.ts +10 -0
  76. package/dist/src/config/types.d.ts +36 -0
  77. package/dist/src/config/url/error.d.ts +10 -0
  78. package/dist/src/config/url/index.d.ts +2 -0
  79. package/dist/src/connection/index.d.ts +0 -1
  80. package/dist/src/contracts/index.d.ts +1 -1
  81. package/dist/src/domain/error.d.ts +27 -1
  82. package/dist/src/domain/helpers.d.ts +8 -2
  83. package/dist/src/domain/model-config.d.ts +30 -1
  84. package/dist/src/domain/thread-activities.d.ts +1 -1
  85. package/dist/src/domain/thread-lifecycle.d.ts +3 -2
  86. package/dist/src/index.d.ts +1 -2
  87. package/dist/src/{connection/node.d.ts → node/connection.d.ts} +1 -1
  88. package/dist/src/node/index.d.ts +1 -0
  89. package/dist/src/orchestration/index.d.ts +1 -1
  90. package/dist/src/orchestration/layer.d.ts +120 -829
  91. package/dist/src/orchestration/service.d.ts +2 -1
  92. package/dist/src/rpc/error.d.ts +5 -3
  93. package/dist/src/rpc/index.d.ts +5 -1
  94. package/dist/src/rpc/layer.d.ts +1166 -40
  95. package/dist/src/rpc/operation.d.ts +6280 -0
  96. package/dist/src/rpc/ws-group.d.ts +372 -27
  97. package/dist/src/runtime/index.d.ts +1 -2
  98. package/dist/src/runtime/layer.d.ts +12 -8
  99. package/dist/src/t3tools/index.d.ts +1 -1
  100. package/dist/t3tools.js +2 -2
  101. package/package.json +27 -19
  102. package/src/application/actions.test.ts +328 -0
  103. package/src/application/actions.ts +475 -0
  104. package/src/application/index.ts +32 -2
  105. package/src/application/layer.ts +43 -5
  106. package/src/application/model-selection.ts +70 -4
  107. package/src/application/models.ts +14 -14
  108. package/src/application/project-commands.ts +38 -5
  109. package/src/application/projects.ts +49 -20
  110. package/src/application/service.ts +275 -78
  111. package/src/application/shell-sequence.ts +6 -8
  112. package/src/application/terminals.ts +208 -0
  113. package/src/application/thread-commands.test.ts +43 -0
  114. package/src/application/thread-commands.ts +82 -1
  115. package/src/application/thread-update.ts +72 -0
  116. package/src/application/thread-wait.ts +47 -48
  117. package/src/application/threads.test.ts +172 -0
  118. package/src/application/threads.ts +128 -45
  119. package/src/auth/error.ts +2 -1
  120. package/src/auth/index.ts +7 -0
  121. package/src/auth/layer.test-utils.ts +34 -0
  122. package/src/auth/layer.ts +116 -34
  123. package/src/auth/local-base-dir.ts +13 -6
  124. package/src/auth/local-origin.ts +10 -7
  125. package/src/auth/local-token.ts +28 -23
  126. package/src/auth/service.test.ts +200 -0
  127. package/src/auth/service.ts +27 -3
  128. package/src/auth/transport.ts +2 -2
  129. package/src/auth/type.ts +47 -1
  130. package/src/bin.ts +26 -6
  131. package/src/cli/action-format.ts +110 -0
  132. package/src/cli/action.ts +398 -0
  133. package/src/cli/app.ts +8 -0
  134. package/src/cli/auth.ts +76 -23
  135. package/src/cli/env/flag.ts +8 -0
  136. package/src/cli/env/index.ts +2 -0
  137. package/src/cli/env/selection-layer.test.ts +49 -0
  138. package/src/cli/env/selection-layer.ts +27 -0
  139. package/src/cli/env.ts +107 -0
  140. package/src/cli/error.ts +26 -3
  141. package/src/cli/extra-args.test.ts +32 -0
  142. package/src/cli/extra-args.ts +22 -0
  143. package/src/cli/flags.ts +26 -1
  144. package/src/cli/format/auth.ts +92 -0
  145. package/src/cli/format/human.ts +131 -0
  146. package/src/cli/format/index.ts +12 -0
  147. package/src/cli/format/model.ts +29 -0
  148. package/src/cli/format/output.ts +51 -0
  149. package/src/cli/format/project.ts +32 -0
  150. package/src/cli/format/terminal.ts +87 -0
  151. package/src/cli/format/thread.test.ts +34 -0
  152. package/src/cli/format/thread.ts +185 -0
  153. package/src/cli/index.ts +20 -0
  154. package/src/cli/input/layer.ts +20 -0
  155. package/src/cli/input/service.ts +1 -0
  156. package/src/cli/interaction/confirm.ts +64 -0
  157. package/src/cli/interaction/self-action.ts +36 -0
  158. package/src/cli/message-input.ts +1 -1
  159. package/src/cli/model.ts +9 -5
  160. package/src/cli/project.ts +15 -8
  161. package/src/cli/projects/delete.ts +51 -0
  162. package/src/cli/require.ts +9 -7
  163. package/src/cli/runtime/index.ts +1 -0
  164. package/src/cli/runtime/service.ts +28 -0
  165. package/src/{scope → cli/scope}/resolve.ts +11 -9
  166. package/src/cli/terminal/attach.ts +29 -0
  167. package/src/cli/terminal/create.ts +55 -0
  168. package/src/cli/terminal/destroy.ts +62 -0
  169. package/src/cli/terminal/encoding.test.ts +63 -0
  170. package/src/cli/terminal/encoding.ts +23 -0
  171. package/src/cli/terminal/error.ts +14 -0
  172. package/src/cli/terminal/io-node-layer.ts +82 -0
  173. package/src/cli/terminal/io-service.ts +25 -0
  174. package/src/cli/terminal/list.ts +36 -0
  175. package/src/cli/terminal/read.test-utils.ts +48 -0
  176. package/src/cli/terminal/read.test.ts +35 -0
  177. package/src/cli/terminal/read.ts +99 -0
  178. package/src/cli/terminal/scope.ts +35 -0
  179. package/src/cli/terminal/shared.ts +250 -0
  180. package/src/cli/terminal/stream.ts +61 -0
  181. package/src/cli/terminal/wait.test.ts +148 -0
  182. package/src/cli/terminal/wait.ts +223 -0
  183. package/src/cli/terminal/write.test.ts +34 -0
  184. package/src/cli/terminal/write.ts +133 -0
  185. package/src/cli/terminal.ts +26 -0
  186. package/src/cli/thread.ts +8 -0
  187. package/src/cli/threads/approve.ts +11 -7
  188. package/src/cli/threads/archive.ts +23 -25
  189. package/src/cli/threads/callback.ts +6 -4
  190. package/src/cli/threads/delete.ts +67 -0
  191. package/src/cli/threads/interrupt.ts +57 -0
  192. package/src/cli/threads/list.test.ts +71 -0
  193. package/src/cli/threads/list.ts +25 -13
  194. package/src/cli/threads/messages.ts +11 -7
  195. package/src/cli/threads/respond.ts +11 -7
  196. package/src/cli/threads/send.ts +39 -9
  197. package/src/cli/threads/show.ts +11 -7
  198. package/src/cli/threads/start.ts +18 -13
  199. package/src/cli/threads/unarchive.ts +48 -0
  200. package/src/cli/threads/update.ts +155 -0
  201. package/src/cli/threads/wait.ts +11 -7
  202. package/src/cli/wait-events.ts +1 -1
  203. package/src/config/config.ts +260 -0
  204. package/src/config/credential/cipher-node.ts +40 -0
  205. package/src/config/credential/cipher-web.ts +82 -0
  206. package/src/config/credential/cipher.ts +39 -0
  207. package/src/config/credential/env.ts +13 -0
  208. package/src/config/credential/error.ts +9 -0
  209. package/src/config/credential/index.ts +6 -0
  210. package/src/config/credential/service.test-utils.ts +25 -0
  211. package/src/config/credential/service.test.ts +116 -0
  212. package/src/config/credential/service.ts +205 -0
  213. package/src/config/env/env.test-utils.ts +14 -0
  214. package/src/config/env/env.ts +81 -0
  215. package/src/config/env/index.ts +2 -0
  216. package/src/{layout/base-dir.ts → config/env/layout.ts} +0 -9
  217. package/src/config/environment-name/index.ts +7 -0
  218. package/src/config/environment-name/name.test.ts +66 -0
  219. package/src/config/environment-name/name.ts +49 -0
  220. package/src/config/error.ts +6 -8
  221. package/src/config/index.ts +16 -5
  222. package/src/config/keystore/error.ts +9 -0
  223. package/src/config/keystore/file.ts +96 -0
  224. package/src/config/keystore/index.ts +4 -0
  225. package/src/config/keystore/keyring-node.test.ts +12 -0
  226. package/src/config/keystore/keyring-node.ts +100 -0
  227. package/src/config/keystore/service.test-utils.ts +15 -0
  228. package/src/config/keystore/service.test.ts +18 -0
  229. package/src/config/keystore/service.ts +29 -0
  230. package/src/config/layer.test-utils.ts +45 -0
  231. package/src/config/layer.test.ts +209 -0
  232. package/src/config/paths/index.ts +1 -0
  233. package/src/config/paths/paths.ts +36 -0
  234. package/src/config/persist/file-mode.ts +21 -0
  235. package/src/config/persist/migration.test.ts +71 -0
  236. package/src/config/persist/migration.ts +82 -0
  237. package/src/config/persist/persist.test.ts +113 -0
  238. package/src/config/persist/persist.ts +65 -0
  239. package/src/config/persist/schema.ts +37 -0
  240. package/src/config/platform.test-utils.ts +20 -0
  241. package/src/config/resolve/resolve.test-utils.ts +20 -0
  242. package/src/config/resolve/resolve.test.ts +137 -0
  243. package/src/config/resolve/resolve.ts +104 -0
  244. package/src/config/selection/index.ts +1 -0
  245. package/src/config/selection/resolve.ts +14 -0
  246. package/src/config/selection/service.ts +29 -0
  247. package/src/config/temp-home.test-utils.ts +7 -0
  248. package/src/config/types.ts +49 -0
  249. package/src/config/url/error.ts +8 -0
  250. package/src/config/url/index.ts +7 -0
  251. package/src/config/url/url.test.ts +31 -0
  252. package/src/connection/index.ts +0 -1
  253. package/src/contracts/index.ts +1 -1
  254. package/src/domain/error.ts +39 -1
  255. package/src/domain/helpers.test.ts +1 -1
  256. package/src/domain/helpers.ts +1 -1
  257. package/src/domain/model-config.ts +5 -1
  258. package/src/domain/thread-activities.test.ts +1 -1
  259. package/src/domain/thread-activities.ts +1 -1
  260. package/src/domain/thread-lifecycle.test.ts +1 -1
  261. package/src/domain/thread-lifecycle.ts +15 -1
  262. package/src/effect.test-utils.ts +25 -0
  263. package/src/index.ts +1 -1
  264. package/src/{connection/node.ts → node/connection.ts} +1 -1
  265. package/src/node/index.ts +1 -0
  266. package/src/orchestration/index.ts +1 -1
  267. package/src/orchestration/layer.ts +34 -86
  268. package/src/orchestration/service.ts +5 -1
  269. package/src/rpc/error.ts +12 -2
  270. package/src/rpc/index.ts +5 -1
  271. package/src/rpc/layer.ts +1 -1
  272. package/src/rpc/operation.ts +83 -0
  273. package/src/rpc/ws-group.ts +25 -1
  274. package/src/runtime/index.ts +2 -1
  275. package/src/runtime/layer.test-utils.ts +32 -0
  276. package/src/runtime/layer.test.ts +66 -0
  277. package/src/runtime/layer.ts +22 -11
  278. package/src/t3tools/index.ts +1 -1
  279. package/src/types/marked-terminal.d.ts +11 -0
  280. package/dist/layout.js +0 -2
  281. package/dist/scope.js +0 -2
  282. package/dist/src/cli/output-format.d.ts +0 -9
  283. package/dist/src/config/layer.d.ts +0 -22
  284. package/dist/src/config/service.d.ts +0 -22
  285. package/dist/src/environment/layer.d.ts +0 -3
  286. package/dist/src/environment/service.d.ts +0 -12
  287. package/dist/src/layout/index.d.ts +0 -1
  288. package/dist/upstream-t3code/packages/contracts/src/auth.d.ts +0 -441
  289. package/dist/upstream-t3code/packages/contracts/src/baseSchemas.d.ts +0 -38
  290. package/dist/upstream-t3code/packages/contracts/src/desktopBootstrap.d.ts +0 -14
  291. package/dist/upstream-t3code/packages/contracts/src/editor.d.ts +0 -124
  292. package/dist/upstream-t3code/packages/contracts/src/environment.d.ts +0 -64
  293. package/dist/upstream-t3code/packages/contracts/src/environmentHttp.d.ts +0 -785
  294. package/dist/upstream-t3code/packages/contracts/src/filesystem.d.ts +0 -26
  295. package/dist/upstream-t3code/packages/contracts/src/git.d.ts +0 -500
  296. package/dist/upstream-t3code/packages/contracts/src/index.d.ts +0 -25
  297. package/dist/upstream-t3code/packages/contracts/src/ipc.d.ts +0 -496
  298. package/dist/upstream-t3code/packages/contracts/src/keybindings.d.ts +0 -133
  299. package/dist/upstream-t3code/packages/contracts/src/model.d.ts +0 -112
  300. package/dist/upstream-t3code/packages/contracts/src/orchestration.d.ts +0 -7338
  301. package/dist/upstream-t3code/packages/contracts/src/project.d.ts +0 -45
  302. package/dist/upstream-t3code/packages/contracts/src/provider.d.ts +0 -130
  303. package/dist/upstream-t3code/packages/contracts/src/providerInstance.d.ts +0 -99
  304. package/dist/upstream-t3code/packages/contracts/src/providerRuntime.d.ts +0 -4450
  305. package/dist/upstream-t3code/packages/contracts/src/relay.d.ts +0 -1262
  306. package/dist/upstream-t3code/packages/contracts/src/relayClient.d.ts +0 -48
  307. package/dist/upstream-t3code/packages/contracts/src/remoteAccess.d.ts +0 -45
  308. package/dist/upstream-t3code/packages/contracts/src/review.d.ts +0 -37
  309. package/dist/upstream-t3code/packages/contracts/src/rpc.d.ts +0 -8710
  310. package/dist/upstream-t3code/packages/contracts/src/server.d.ts +0 -2336
  311. package/dist/upstream-t3code/packages/contracts/src/settings.d.ts +0 -292
  312. package/dist/upstream-t3code/packages/contracts/src/sourceControl.d.ts +0 -177
  313. package/dist/upstream-t3code/packages/contracts/src/terminal.d.ts +0 -333
  314. package/dist/upstream-t3code/packages/contracts/src/vcs.d.ts +0 -148
  315. package/src/cli/auth-format.ts +0 -45
  316. package/src/cli/model-format.ts +0 -18
  317. package/src/cli/output-format.ts +0 -41
  318. package/src/cli/project-format.ts +0 -11
  319. package/src/cli/thread-format.ts +0 -121
  320. package/src/config/layer.ts +0 -105
  321. package/src/config/service.ts +0 -26
  322. package/src/environment/layer.ts +0 -12
  323. package/src/environment/service.ts +0 -13
  324. package/src/layout/index.ts +0 -1
  325. /package/dist/src/{scope → cli/scope}/index.d.ts +0 -0
  326. /package/dist/src/config/{url.d.ts → url/url.d.ts} +0 -0
  327. /package/src/{scope → cli/scope}/index.ts +0 -0
  328. /package/src/config/{url.ts → url/url.ts} +0 -0
package/src/bin.ts CHANGED
@@ -1,32 +1,47 @@
1
1
  #!/usr/bin/env node
2
+ import { homedir } from "node:os";
2
3
  import * as Effect from "effect/Effect";
3
4
  import * as Layer from "effect/Layer";
4
5
  import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
5
6
  import * as NodeServices from "@effect/platform-node/NodeServices";
6
7
  import { Command } from "effect/unstable/cli";
7
-
8
8
  import { createCliCommand } from "./cli/app.ts";
9
- import { NodeEnvironmentLive } from "./environment/layer.ts";
9
+ import * as CliSelection from "./cli/env/selection-layer.ts";
10
+ import * as CliRuntime from "./cli/runtime/service.ts";
11
+ import * as CredentialCipherNode from "./config/credential/cipher-node.ts";
12
+ import * as KeystoreKeyringNode from "./config/keystore/keyring-node.ts";
10
13
  import { T3InputLive } from "./cli/input/layer.ts";
11
14
  import { T3OutputLive } from "./cli/output/layer.ts";
15
+ import { NodeTerminalIoLive } from "./cli/terminal/io-node-layer.ts";
12
16
  import { T3Output } from "./cli/output/service.ts";
13
- import { AppLayer } from "./runtime/layer.ts";
17
+ import { BaseAppLayer } from "./runtime/layer.ts";
14
18
  import { T3VersionBundledLive, T3VersionPackageJsonLive } from "./version/layer.ts";
15
19
  import { T3Version } from "./version/service.ts";
16
20
 
17
21
  declare const T3CLI_VERSION: string | undefined;
18
22
 
23
+ if (process.env.HOME === undefined || process.env.HOME.trim().length === 0) {
24
+ process.env.HOME = homedir();
25
+ }
26
+
19
27
  const VersionLive =
20
28
  typeof T3CLI_VERSION === "string" ? T3VersionBundledLive : T3VersionPackageJsonLive;
21
29
 
22
- const PlatformLayer = Layer.mergeAll(NodeServices.layer, NodeEnvironmentLive);
30
+ const PlatformLayer = Layer.mergeAll(NodeServices.layer, CliRuntime.layer);
31
+
32
+ const CliAppLayer = BaseAppLayer.pipe(
33
+ Layer.provideMerge(CliSelection.layer),
34
+ Layer.provide(CredentialCipherNode.layerNode),
35
+ Layer.provide(KeystoreKeyringNode.layerNode),
36
+ );
23
37
 
24
38
  const CliLayer = Layer.mergeAll(
25
- AppLayer.pipe(Layer.provide(PlatformLayer)),
39
+ CliAppLayer.pipe(Layer.provide(PlatformLayer)),
26
40
  NodeServices.layer,
27
- NodeEnvironmentLive,
41
+ CliRuntime.layer,
28
42
  T3InputLive.pipe(Layer.provide(NodeServices.layer)),
29
43
  T3OutputLive.pipe(Layer.provide(NodeServices.layer)),
44
+ NodeTerminalIoLive,
30
45
  VersionLive.pipe(Layer.provide(NodeServices.layer)),
31
46
  );
32
47
 
@@ -34,6 +49,11 @@ const program = Effect.gen(function* () {
34
49
  const version = yield* T3Version;
35
50
  return yield* Command.run(createCliCommand(), { version: version.version });
36
51
  }).pipe(
52
+ Effect.catchTag("ShowHelp", (error) =>
53
+ Effect.sync(() => {
54
+ process.exitCode = error.errors.length > 0 ? 1 : 0;
55
+ }),
56
+ ),
37
57
  Effect.tapError((error) =>
38
58
  Effect.gen(function* () {
39
59
  const output = yield* T3Output;
@@ -0,0 +1,110 @@
1
+ import type {
2
+ OrchestrationProjectShell,
3
+ ProjectScript,
4
+ TerminalSessionSnapshot,
5
+ } from "@t3tools/contracts";
6
+
7
+ import { formatRecord, formatTable } from "./format/human.ts";
8
+
9
+ type ActionRow = {
10
+ readonly name: string;
11
+ readonly id: string;
12
+ readonly command: string;
13
+ readonly icon: string;
14
+ readonly setup: string;
15
+ readonly preview: string;
16
+ };
17
+
18
+ export function formatActionListHuman(input: {
19
+ readonly project: OrchestrationProjectShell;
20
+ readonly actions: ReadonlyArray<ProjectScript>;
21
+ }) {
22
+ if (input.actions.length === 0) {
23
+ return `no actions for ${input.project.title} (${input.project.id})\n`;
24
+ }
25
+ return `${formatActionTable(input.actions.map(toActionRow))}\n`;
26
+ }
27
+
28
+ export function formatActionAddedHuman(input: {
29
+ readonly project: OrchestrationProjectShell;
30
+ readonly action: ProjectScript;
31
+ readonly sequence: number;
32
+ }) {
33
+ return `action added\n${formatActionRecord(input)}`;
34
+ }
35
+
36
+ export function formatActionUpdatedHuman(input: {
37
+ readonly project: OrchestrationProjectShell;
38
+ readonly action: ProjectScript;
39
+ readonly sequence: number;
40
+ }) {
41
+ return `action updated\n${formatActionRecord(input)}`;
42
+ }
43
+
44
+ export function formatActionDeletedHuman(input: {
45
+ readonly project: OrchestrationProjectShell;
46
+ readonly action: ProjectScript;
47
+ readonly sequence: number;
48
+ }) {
49
+ return `action deleted\n${formatActionRecord(input)}`;
50
+ }
51
+
52
+ export function formatActionRunHuman(input: {
53
+ readonly project: OrchestrationProjectShell;
54
+ readonly action: ProjectScript;
55
+ readonly terminal: TerminalSessionSnapshot;
56
+ }) {
57
+ return `action running\n${formatRecord([
58
+ { field: "name", value: input.action.name },
59
+ { field: "id", value: input.action.id },
60
+ { field: "project", value: input.project.id },
61
+ { field: "terminal", value: input.terminal.terminalId },
62
+ { field: "cwd", value: input.terminal.cwd },
63
+ ])}`;
64
+ }
65
+
66
+ function formatActionTable(rows: ReadonlyArray<ActionRow>) {
67
+ return formatTable(
68
+ [
69
+ { header: "name", value: (row) => row.name, maxWidth: 28 },
70
+ { header: "id", value: (row) => row.id, maxWidth: 24 },
71
+ { header: "command", value: (row) => row.command, maxWidth: 48 },
72
+ { header: "icon", value: (row) => row.icon, maxWidth: 10 },
73
+ { header: "setup", value: (row) => row.setup, maxWidth: 5 },
74
+ { header: "preview", value: (row) => row.preview, maxWidth: 48 },
75
+ ],
76
+ rows,
77
+ );
78
+ }
79
+
80
+ function formatActionRecord(input: {
81
+ readonly project: OrchestrationProjectShell;
82
+ readonly action: ProjectScript;
83
+ readonly sequence: number;
84
+ }) {
85
+ return formatRecord([
86
+ { field: "name", value: input.action.name },
87
+ { field: "id", value: input.action.id },
88
+ { field: "project", value: input.project.id },
89
+ { field: "sequence", value: String(input.sequence) },
90
+ ]);
91
+ }
92
+
93
+ function toActionRow(action: ProjectScript): ActionRow {
94
+ return {
95
+ name: action.name,
96
+ id: action.id,
97
+ command: action.command,
98
+ icon: action.icon,
99
+ setup: action.runOnWorktreeCreate ? "yes" : "no",
100
+ preview: formatActionPreview(action),
101
+ };
102
+ }
103
+
104
+ function formatActionPreview(action: ProjectScript) {
105
+ const parts = [
106
+ action.previewUrl ?? null,
107
+ action.autoOpenPreview === true ? "auto open" : null,
108
+ ].filter((part): part is string => part !== null);
109
+ return parts.length > 0 ? parts.join("\n") : "-";
110
+ }
@@ -0,0 +1,398 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import { Command, Flag } from "effect/unstable/cli";
4
+
5
+ import { T3Application, type ProjectActionSelector } from "../application/service.ts";
6
+ import { loadT3CliEnv } from "../config/env/env.ts";
7
+ import {
8
+ formatActionAddedHuman,
9
+ formatActionDeletedHuman,
10
+ formatActionListHuman,
11
+ formatActionRunHuman,
12
+ formatActionUpdatedHuman,
13
+ } from "./action-format.ts";
14
+ import {
15
+ ConflictingUpdateFlagsError,
16
+ InvalidFlagCombinationError,
17
+ MissingUpdateFieldsError,
18
+ } from "./error.ts";
19
+ import { extraArgsConfig } from "./extra-args.ts";
20
+ import { formatFlag, projectFlag, threadFlag, yesFlag } from "./flags.ts";
21
+ import { resolveOutputFormat } from "./format/output.ts";
22
+ import { requireDestructiveConfirmation } from "./interaction/confirm.ts";
23
+ import { T3Output } from "./output/service.ts";
24
+ import { requireCommandProjectRef } from "./require.ts";
25
+ import { CliRuntime } from "./runtime/service.ts";
26
+ import { requireCommandThreadId } from "./terminal/scope.ts";
27
+ import { runAttachedTerminalSession, snapshotToTerminalAttachTarget } from "./terminal/shared.ts";
28
+
29
+ const actionIconChoices = ["play", "test", "lint", "configure", "build", "debug"] as const;
30
+
31
+ export function createActionCommand() {
32
+ return Command.make("action").pipe(
33
+ Command.withDescription("project-defined toolbar action commands"),
34
+ Command.withSubcommands([
35
+ listActionsCommand,
36
+ runActionCommand,
37
+ addActionCommand,
38
+ updateActionCommand,
39
+ deleteActionCommand,
40
+ ]),
41
+ );
42
+ }
43
+
44
+ const idFlag = Flag.string("id").pipe(Flag.optional);
45
+ const nameFlag = Flag.string("name").pipe(Flag.optional);
46
+ const commandFlag = Flag.string("command");
47
+ const optionalCommandFlag = Flag.string("command").pipe(Flag.optional);
48
+ const iconFlag = Flag.choice("icon", actionIconChoices).pipe(Flag.withDefault("play"));
49
+ const optionalIconFlag = Flag.choice("icon", actionIconChoices).pipe(Flag.optional);
50
+ const setupFlag = Flag.boolean("setup");
51
+ const optionalSetupFlag = Flag.boolean("setup").pipe(Flag.optional);
52
+ const noSetupFlag = Flag.boolean("no-setup").pipe(Flag.optional);
53
+ const previewUrlFlag = Flag.string("preview-url").pipe(Flag.optional);
54
+ const clearPreviewUrlFlag = Flag.boolean("clear-preview-url").pipe(Flag.optional);
55
+ const autoOpenPreviewFlag = Flag.boolean("auto-open-preview").pipe(Flag.optional);
56
+ const noAutoOpenPreviewFlag = Flag.boolean("no-auto-open-preview").pipe(Flag.optional);
57
+ const clearAutoOpenPreviewFlag = Flag.boolean("clear-auto-open-preview").pipe(Flag.optional);
58
+
59
+ const listActionsCommand = Command.make(
60
+ "list",
61
+ {
62
+ project: projectFlag,
63
+ format: formatFlag,
64
+ ...extraArgsConfig,
65
+ },
66
+ ({ project, format }) =>
67
+ Effect.gen(function* () {
68
+ const application = yield* T3Application;
69
+ const cliRuntime = yield* CliRuntime;
70
+ const t3CliEnv = yield* loadT3CliEnv;
71
+ const output = yield* T3Output;
72
+ const projectRef = yield* requireCommandProjectRef({
73
+ project,
74
+ });
75
+ const result = yield* application.listActions(projectRef);
76
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
77
+ if (resolvedFormat === "json") {
78
+ yield* output.printJson(result);
79
+ } else {
80
+ yield* output.writeStdout(formatActionListHuman(result));
81
+ }
82
+ }),
83
+ ).pipe(Command.withDescription("list project actions"));
84
+
85
+ const runActionCommand = Command.make(
86
+ "run",
87
+ {
88
+ thread: threadFlag,
89
+ id: idFlag,
90
+ name: nameFlag,
91
+ terminal: Flag.string("terminal").pipe(Flag.optional),
92
+ attach: Flag.boolean("attach"),
93
+ format: formatFlag,
94
+ ...extraArgsConfig,
95
+ },
96
+ ({ thread, id, name, terminal, attach, format }) =>
97
+ Effect.gen(function* () {
98
+ const application = yield* T3Application;
99
+ const cliRuntime = yield* CliRuntime;
100
+ const t3CliEnv = yield* loadT3CliEnv;
101
+ const output = yield* T3Output;
102
+ const threadId = yield* requireCommandThreadId({
103
+ thread,
104
+ });
105
+ const selector = yield* requireActionSelector({ id, name });
106
+ const terminalId = Option.getOrUndefined(terminal);
107
+ const result = yield* application.runAction({
108
+ threadId,
109
+ selector,
110
+ ...(terminalId !== undefined ? { terminalId } : {}),
111
+ });
112
+
113
+ if (attach) {
114
+ yield* runAttachedTerminalSession({
115
+ terminal: snapshotToTerminalAttachTarget(result.terminal),
116
+ });
117
+ } else {
118
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
119
+ if (resolvedFormat === "json") {
120
+ yield* output.printJson(result);
121
+ } else {
122
+ yield* output.printInfo(formatActionRunHuman(result));
123
+ }
124
+ }
125
+ }),
126
+ ).pipe(Command.withDescription("run a project action in a thread terminal"));
127
+
128
+ const addActionCommand = Command.make(
129
+ "add",
130
+ {
131
+ project: projectFlag,
132
+ name: Flag.string("name"),
133
+ command: commandFlag,
134
+ id: idFlag,
135
+ icon: iconFlag,
136
+ setup: setupFlag,
137
+ previewUrl: previewUrlFlag,
138
+ autoOpenPreview: Flag.boolean("auto-open-preview"),
139
+ format: formatFlag,
140
+ ...extraArgsConfig,
141
+ },
142
+ ({ project, name, command, id, icon, setup, previewUrl, autoOpenPreview, format }) =>
143
+ Effect.gen(function* () {
144
+ const application = yield* T3Application;
145
+ const cliRuntime = yield* CliRuntime;
146
+ const t3CliEnv = yield* loadT3CliEnv;
147
+ const output = yield* T3Output;
148
+ const projectRef = yield* requireCommandProjectRef({
149
+ project,
150
+ });
151
+ const idValue = Option.getOrUndefined(id);
152
+ const previewUrlValue = Option.getOrUndefined(previewUrl);
153
+ const result = yield* application.addAction({
154
+ projectRef,
155
+ name,
156
+ command,
157
+ icon,
158
+ ...(idValue !== undefined ? { id: idValue } : {}),
159
+ ...(setup ? { setup: true } : {}),
160
+ ...(previewUrlValue !== undefined ? { previewUrl: previewUrlValue } : {}),
161
+ ...(autoOpenPreview ? { autoOpenPreview: true } : {}),
162
+ });
163
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
164
+ if (resolvedFormat === "json") {
165
+ yield* output.printJson(result);
166
+ } else {
167
+ yield* output.printInfo(
168
+ formatActionAddedHuman({
169
+ project: result.project,
170
+ action: result.action,
171
+ sequence: result.dispatch.sequence,
172
+ }),
173
+ );
174
+ }
175
+ }),
176
+ ).pipe(Command.withDescription("add a project action"));
177
+
178
+ const updateActionCommand = Command.make(
179
+ "update",
180
+ {
181
+ project: projectFlag,
182
+ id: idFlag,
183
+ name: nameFlag,
184
+ setName: Flag.string("set-name").pipe(Flag.optional),
185
+ command: optionalCommandFlag,
186
+ icon: optionalIconFlag,
187
+ setup: optionalSetupFlag,
188
+ noSetup: noSetupFlag,
189
+ previewUrl: previewUrlFlag,
190
+ clearPreviewUrl: clearPreviewUrlFlag,
191
+ autoOpenPreview: autoOpenPreviewFlag,
192
+ noAutoOpenPreview: noAutoOpenPreviewFlag,
193
+ clearAutoOpenPreview: clearAutoOpenPreviewFlag,
194
+ format: formatFlag,
195
+ ...extraArgsConfig,
196
+ },
197
+ ({
198
+ project,
199
+ id,
200
+ name,
201
+ setName,
202
+ command,
203
+ icon,
204
+ setup,
205
+ noSetup,
206
+ previewUrl,
207
+ clearPreviewUrl,
208
+ autoOpenPreview,
209
+ noAutoOpenPreview,
210
+ clearAutoOpenPreview,
211
+ format,
212
+ }) =>
213
+ Effect.gen(function* () {
214
+ const application = yield* T3Application;
215
+ const cliRuntime = yield* CliRuntime;
216
+ const t3CliEnv = yield* loadT3CliEnv;
217
+ const output = yield* T3Output;
218
+ const projectRef = yield* requireCommandProjectRef({
219
+ project,
220
+ });
221
+ const selector = yield* requireActionSelector({ id, name });
222
+ const patch = yield* buildUpdatePatch({
223
+ setName,
224
+ command,
225
+ icon,
226
+ setup,
227
+ noSetup,
228
+ previewUrl,
229
+ clearPreviewUrl,
230
+ autoOpenPreview,
231
+ noAutoOpenPreview,
232
+ clearAutoOpenPreview,
233
+ });
234
+ const result = yield* application.updateAction({
235
+ projectRef,
236
+ selector,
237
+ ...patch,
238
+ });
239
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
240
+ if (resolvedFormat === "json") {
241
+ yield* output.printJson(result);
242
+ } else {
243
+ yield* output.printInfo(
244
+ formatActionUpdatedHuman({
245
+ project: result.project,
246
+ action: result.action,
247
+ sequence: result.dispatch.sequence,
248
+ }),
249
+ );
250
+ }
251
+ }),
252
+ ).pipe(Command.withDescription("update a project action"));
253
+
254
+ const deleteActionCommand = Command.make(
255
+ "delete",
256
+ {
257
+ project: projectFlag,
258
+ id: idFlag,
259
+ name: nameFlag,
260
+ yes: yesFlag,
261
+ format: formatFlag,
262
+ ...extraArgsConfig,
263
+ },
264
+ ({ project, id, name, yes, format }) =>
265
+ Effect.gen(function* () {
266
+ const application = yield* T3Application;
267
+ const cliRuntime = yield* CliRuntime;
268
+ const t3CliEnv = yield* loadT3CliEnv;
269
+ const output = yield* T3Output;
270
+ const projectRef = yield* requireCommandProjectRef({
271
+ project,
272
+ });
273
+ const selector = yield* requireActionSelector({ id, name });
274
+ const listed = yield* application.listActions(projectRef);
275
+ const selectorLabel =
276
+ selector.id !== undefined ? `id ${selector.id}` : `name ${selector.name.trim()}`;
277
+ yield* requireDestructiveConfirmation({
278
+ message: `Delete action selected by ${selectorLabel} from ${listed.project.title}?`,
279
+ yes,
280
+ cliRuntime,
281
+ t3CliEnv,
282
+ });
283
+ const result = yield* application.deleteAction({
284
+ projectRef,
285
+ selector,
286
+ });
287
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
288
+ if (resolvedFormat === "json") {
289
+ yield* output.printJson(result);
290
+ } else {
291
+ yield* output.printInfo(
292
+ formatActionDeletedHuman({
293
+ project: result.project,
294
+ action: result.action,
295
+ sequence: result.dispatch.sequence,
296
+ }),
297
+ );
298
+ }
299
+ }),
300
+ ).pipe(Command.withDescription("delete a project action"));
301
+
302
+ function requireActionSelector(input: {
303
+ readonly id: Option.Option<string>;
304
+ readonly name: Option.Option<string>;
305
+ }) {
306
+ return Effect.gen(function* () {
307
+ const id = Option.getOrUndefined(input.id);
308
+ const name = Option.getOrUndefined(input.name);
309
+ if ((id === undefined && name === undefined) || (id !== undefined && name !== undefined)) {
310
+ return yield* Effect.fail(
311
+ new InvalidFlagCombinationError({
312
+ message: "provide exactly one action selector: --id <id> or --name <name>",
313
+ }),
314
+ );
315
+ }
316
+ return id !== undefined
317
+ ? ({ id } satisfies ProjectActionSelector)
318
+ : ({ name: name! } satisfies ProjectActionSelector);
319
+ });
320
+ }
321
+
322
+ function buildUpdatePatch(input: {
323
+ readonly setName: Option.Option<string>;
324
+ readonly command: Option.Option<string>;
325
+ readonly icon: Option.Option<(typeof actionIconChoices)[number]>;
326
+ readonly setup: Option.Option<boolean>;
327
+ readonly noSetup: Option.Option<boolean>;
328
+ readonly previewUrl: Option.Option<string>;
329
+ readonly clearPreviewUrl: Option.Option<boolean>;
330
+ readonly autoOpenPreview: Option.Option<boolean>;
331
+ readonly noAutoOpenPreview: Option.Option<boolean>;
332
+ readonly clearAutoOpenPreview: Option.Option<boolean>;
333
+ }) {
334
+ return Effect.gen(function* () {
335
+ const setName = Option.getOrUndefined(input.setName);
336
+ const command = Option.getOrUndefined(input.command);
337
+ const icon = Option.getOrUndefined(input.icon);
338
+ const setup = Option.getOrUndefined(input.setup);
339
+ const noSetup = Option.getOrUndefined(input.noSetup);
340
+ const previewUrl = Option.getOrUndefined(input.previewUrl);
341
+ const clearPreviewUrl = Option.getOrUndefined(input.clearPreviewUrl);
342
+ const autoOpenPreview = Option.getOrUndefined(input.autoOpenPreview);
343
+ const noAutoOpenPreview = Option.getOrUndefined(input.noAutoOpenPreview);
344
+ const clearAutoOpenPreview = Option.getOrUndefined(input.clearAutoOpenPreview);
345
+
346
+ if (setup === true && noSetup === true) {
347
+ return yield* Effect.fail(
348
+ new ConflictingUpdateFlagsError({
349
+ message: "--setup and --no-setup are mutually exclusive",
350
+ }),
351
+ );
352
+ }
353
+ if (previewUrl !== undefined && clearPreviewUrl === true) {
354
+ return yield* Effect.fail(
355
+ new ConflictingUpdateFlagsError({
356
+ message: "--preview-url and --clear-preview-url are mutually exclusive",
357
+ }),
358
+ );
359
+ }
360
+ const autoOpenSetCount = [autoOpenPreview, noAutoOpenPreview, clearAutoOpenPreview].filter(
361
+ (value) => value === true,
362
+ ).length;
363
+ if (autoOpenSetCount > 1) {
364
+ return yield* Effect.fail(
365
+ new ConflictingUpdateFlagsError({
366
+ message:
367
+ "--auto-open-preview, --no-auto-open-preview, and --clear-auto-open-preview are mutually exclusive",
368
+ }),
369
+ );
370
+ }
371
+
372
+ const patch = {
373
+ ...(setName !== undefined ? { name: setName } : {}),
374
+ ...(command !== undefined ? { command } : {}),
375
+ ...(icon !== undefined ? { icon } : {}),
376
+ ...(setup === true ? { setup: true } : noSetup === true ? { setup: false } : {}),
377
+ ...(clearPreviewUrl === true
378
+ ? { previewUrl: null }
379
+ : previewUrl !== undefined
380
+ ? { previewUrl }
381
+ : {}),
382
+ ...(autoOpenPreview === true
383
+ ? { autoOpenPreview: true }
384
+ : noAutoOpenPreview === true || clearAutoOpenPreview === true
385
+ ? { autoOpenPreview: null }
386
+ : {}),
387
+ };
388
+ if (Object.keys(patch).length === 0) {
389
+ return yield* Effect.fail(
390
+ new MissingUpdateFieldsError({
391
+ message:
392
+ "at least one update field is required: --set-name, --command, --icon, --setup, --no-setup, --preview-url, --clear-preview-url, --auto-open-preview, --no-auto-open-preview, or --clear-auto-open-preview",
393
+ }),
394
+ );
395
+ }
396
+ return patch;
397
+ });
398
+ }
package/src/cli/app.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { Command } from "effect/unstable/cli";
2
2
 
3
+ import { createActionCommand } from "./action.ts";
3
4
  import { createAuthCommand } from "./auth.ts";
5
+ import { createEnvCommand } from "./env.ts";
6
+ import { cliEnvironmentSetting } from "./env/flag.ts";
7
+ import { createTerminalCommandGroup } from "./terminal.ts";
4
8
  import { createModelCommand } from "./model.ts";
5
9
  import { createProjectCommand } from "./project.ts";
6
10
  import { createThreadCommand } from "./thread.ts";
@@ -14,11 +18,15 @@ import { waitForThreadCommand } from "./threads/wait.ts";
14
18
  export function createCliCommand() {
15
19
  return Command.make("t3cli").pipe(
16
20
  Command.withDescription("non-interactive cli for running t3code server"),
21
+ Command.withGlobalFlags([cliEnvironmentSetting]),
17
22
  Command.withSubcommands([
23
+ createActionCommand(),
18
24
  createAuthCommand(),
25
+ createEnvCommand(),
19
26
  listThreadsCommand,
20
27
  createModelCommand(),
21
28
  createProjectCommand(),
29
+ createTerminalCommandGroup(),
22
30
  startThreadCommand,
23
31
  sendThreadCommand,
24
32
  showThreadCommand,