t3code-cli 0.11.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 (317) hide show
  1. package/README.md +42 -10
  2. package/dist/application.js +2 -2
  3. package/dist/auth.js +1 -1
  4. package/dist/bin.js +85526 -2662
  5. package/dist/cli.js +15 -2
  6. package/dist/config.js +120 -2
  7. package/dist/connection.js +2 -2
  8. package/dist/index.js +1 -1
  9. package/dist/node.js +6 -2
  10. package/dist/orchestration.js +2 -2
  11. package/dist/rpc.js +1 -1
  12. package/dist/runtime.js +2 -2
  13. package/dist/shared.js +42956 -38119
  14. package/dist/src/application/actions.d.ts +25 -0
  15. package/dist/src/application/index.d.ts +3 -3
  16. package/dist/src/application/layer.d.ts +51 -35
  17. package/dist/src/application/model-selection.d.ts +2 -2
  18. package/dist/src/application/models.d.ts +1 -1
  19. package/dist/src/application/project-commands.d.ts +22 -2
  20. package/dist/src/application/projects.d.ts +7 -7
  21. package/dist/src/application/service.d.ts +65 -2
  22. package/dist/src/application/shell-sequence.d.ts +11 -0
  23. package/dist/src/application/terminals.d.ts +2 -2
  24. package/dist/src/application/thread-commands.d.ts +1 -1
  25. package/dist/src/application/thread-wait.d.ts +9 -0
  26. package/dist/src/application/threads.d.ts +56 -5
  27. package/dist/src/auth/error.d.ts +2 -1
  28. package/dist/src/auth/index.d.ts +1 -1
  29. package/dist/src/auth/layer.d.ts +34 -6
  30. package/dist/src/auth/local-base-dir.d.ts +5 -2
  31. package/dist/src/auth/local-origin.d.ts +3 -3
  32. package/dist/src/auth/local-token.d.ts +3 -3
  33. package/dist/src/auth/service.d.ts +15 -3
  34. package/dist/src/auth/type.d.ts +40 -1
  35. package/dist/src/cli/env/flag.d.ts +2 -0
  36. package/dist/src/cli/env/index.d.ts +2 -0
  37. package/dist/src/cli/env/selection-layer.d.ts +3 -0
  38. package/dist/src/cli/flags.d.ts +2 -0
  39. package/dist/src/cli/format/index.d.ts +1 -0
  40. package/dist/src/cli/format/output.d.ts +12 -0
  41. package/dist/src/cli/index.d.ts +4 -0
  42. package/dist/src/cli/runtime/index.d.ts +1 -0
  43. package/dist/src/cli/runtime/service.d.ts +16 -0
  44. package/dist/src/{scope → cli/scope}/resolve.d.ts +5 -4
  45. package/dist/src/config/config.d.ts +49 -0
  46. package/dist/src/config/credential/cipher-node.d.ts +3 -0
  47. package/dist/src/config/credential/cipher-web.d.ts +3 -0
  48. package/dist/src/config/credential/cipher.d.ts +29 -0
  49. package/dist/src/config/credential/env.d.ts +3 -0
  50. package/dist/src/config/credential/error.d.ts +8 -0
  51. package/dist/src/config/credential/index.d.ts +6 -0
  52. package/dist/src/config/credential/service.d.ts +34 -0
  53. package/dist/src/config/env/env.d.ts +55 -0
  54. package/dist/src/config/env/index.d.ts +2 -0
  55. package/dist/src/{layout/base-dir.d.ts → config/env/layout.d.ts} +0 -1
  56. package/dist/src/config/environment-name/index.d.ts +1 -0
  57. package/dist/src/config/environment-name/name.d.ts +10 -0
  58. package/dist/src/config/error.d.ts +4 -11
  59. package/dist/src/config/index.d.ts +10 -5
  60. package/dist/src/config/keystore/error.d.ts +8 -0
  61. package/dist/src/config/keystore/file.d.ts +9 -0
  62. package/dist/src/config/keystore/index.d.ts +4 -0
  63. package/dist/src/config/keystore/keyring-node.d.ts +4 -0
  64. package/dist/src/config/keystore/service.d.ts +33 -0
  65. package/dist/src/config/paths/index.d.ts +1 -0
  66. package/dist/src/config/paths/paths.d.ts +6 -0
  67. package/dist/src/config/persist/file-mode.d.ts +4 -0
  68. package/dist/src/config/persist/migration.d.ts +68 -0
  69. package/dist/src/config/persist/persist.d.ts +40 -0
  70. package/dist/src/config/persist/schema.d.ts +68 -0
  71. package/dist/src/config/resolve/resolve.d.ts +40 -0
  72. package/dist/src/config/selection/index.d.ts +1 -0
  73. package/dist/src/config/selection/resolve.d.ts +4 -0
  74. package/dist/src/config/selection/service.d.ts +10 -0
  75. package/dist/src/config/types.d.ts +36 -0
  76. package/dist/src/config/url/error.d.ts +10 -0
  77. package/dist/src/config/url/index.d.ts +2 -0
  78. package/dist/src/connection/index.d.ts +0 -1
  79. package/dist/src/contracts/index.d.ts +1 -1
  80. package/dist/src/domain/error.d.ts +14 -1
  81. package/dist/src/domain/helpers.d.ts +16 -1
  82. package/dist/src/domain/model-config.d.ts +4 -1
  83. package/dist/src/domain/thread-activities.d.ts +1 -1
  84. package/dist/src/domain/thread-lifecycle.d.ts +10 -1
  85. package/dist/src/index.d.ts +1 -2
  86. package/dist/src/{connection/node.d.ts → node/connection.d.ts} +1 -1
  87. package/dist/src/node/index.d.ts +1 -2
  88. package/dist/src/orchestration/index.d.ts +0 -1
  89. package/dist/src/orchestration/layer.d.ts +153 -7
  90. package/dist/src/orchestration/service.d.ts +1 -1
  91. package/dist/src/rpc/error.d.ts +2 -2
  92. package/dist/src/rpc/index.d.ts +2 -3
  93. package/dist/src/rpc/layer.d.ts +574 -46
  94. package/dist/src/rpc/operation.d.ts +574 -46
  95. package/dist/src/rpc/ws-group.d.ts +184 -19
  96. package/dist/src/runtime/index.d.ts +1 -2
  97. package/dist/src/runtime/layer.d.ts +12 -8
  98. package/dist/src/t3tools/index.d.ts +1 -1
  99. package/dist/t3tools.js +2 -2
  100. package/package.json +25 -21
  101. package/src/application/actions.test.ts +328 -0
  102. package/src/application/actions.ts +475 -0
  103. package/src/application/index.ts +9 -5
  104. package/src/application/layer.ts +9 -0
  105. package/src/application/model-selection.ts +2 -2
  106. package/src/application/project-commands.ts +23 -5
  107. package/src/application/projects.ts +6 -7
  108. package/src/application/service.ts +79 -1
  109. package/src/application/shell-sequence.ts +1 -1
  110. package/src/application/terminals.ts +2 -1
  111. package/src/application/thread-commands.ts +1 -1
  112. package/src/application/thread-update.ts +1 -1
  113. package/src/application/thread-wait.ts +1 -1
  114. package/src/application/threads.test.ts +9 -3
  115. package/src/application/threads.ts +6 -6
  116. package/src/auth/error.ts +2 -1
  117. package/src/auth/index.ts +7 -0
  118. package/src/auth/layer.test-utils.ts +34 -0
  119. package/src/auth/layer.ts +116 -34
  120. package/src/auth/local-base-dir.ts +13 -6
  121. package/src/auth/local-origin.ts +10 -7
  122. package/src/auth/local-token.ts +28 -23
  123. package/src/auth/service.test.ts +200 -0
  124. package/src/auth/service.ts +27 -3
  125. package/src/auth/transport.ts +2 -2
  126. package/src/auth/type.ts +47 -1
  127. package/src/bin.ts +24 -6
  128. package/src/cli/action-format.ts +110 -0
  129. package/src/cli/action.ts +398 -0
  130. package/src/cli/app.ts +6 -0
  131. package/src/cli/auth.ts +76 -23
  132. package/src/cli/env/flag.ts +8 -0
  133. package/src/cli/env/index.ts +2 -0
  134. package/src/cli/env/selection-layer.test.ts +49 -0
  135. package/src/cli/env/selection-layer.ts +27 -0
  136. package/src/cli/env.ts +107 -0
  137. package/src/cli/extra-args.test.ts +32 -0
  138. package/src/cli/extra-args.ts +22 -0
  139. package/src/cli/flags.ts +11 -1
  140. package/src/cli/format/auth.ts +92 -0
  141. package/src/cli/format/human.ts +131 -0
  142. package/src/cli/format/index.ts +12 -0
  143. package/src/cli/format/model.ts +29 -0
  144. package/src/cli/format/output.ts +51 -0
  145. package/src/cli/format/project.ts +32 -0
  146. package/src/cli/format/terminal.ts +87 -0
  147. package/src/cli/{thread-format.test.ts → format/thread.test.ts} +6 -4
  148. package/src/cli/format/thread.ts +185 -0
  149. package/src/cli/index.ts +20 -0
  150. package/src/cli/interaction/confirm.ts +64 -0
  151. package/src/cli/{self-action.ts → interaction/self-action.ts} +8 -6
  152. package/src/cli/message-input.ts +1 -1
  153. package/src/cli/model.ts +9 -5
  154. package/src/cli/project.ts +13 -7
  155. package/src/cli/projects/delete.ts +13 -12
  156. package/src/cli/require.ts +9 -7
  157. package/src/cli/runtime/index.ts +1 -0
  158. package/src/cli/runtime/service.ts +28 -0
  159. package/src/{scope → cli/scope}/resolve.ts +11 -9
  160. package/src/cli/terminal/attach.ts +3 -6
  161. package/src/cli/terminal/create.ts +10 -9
  162. package/src/cli/terminal/destroy.ts +13 -11
  163. package/src/cli/terminal/list.ts +10 -9
  164. package/src/cli/terminal/read.test-utils.ts +48 -0
  165. package/src/cli/terminal/read.test.ts +35 -0
  166. package/src/cli/terminal/read.ts +3 -6
  167. package/src/cli/terminal/scope.ts +10 -5
  168. package/src/cli/terminal/shared.ts +1 -1
  169. package/src/cli/terminal/stream.ts +3 -6
  170. package/src/cli/terminal/wait.test.ts +5 -3
  171. package/src/cli/terminal/wait.ts +10 -9
  172. package/src/cli/terminal/write.test.ts +34 -0
  173. package/src/cli/terminal/write.ts +10 -9
  174. package/src/cli/threads/approve.ts +11 -7
  175. package/src/cli/threads/archive.ts +14 -9
  176. package/src/cli/threads/callback.ts +6 -4
  177. package/src/cli/threads/delete.ts +17 -11
  178. package/src/cli/threads/interrupt.ts +14 -9
  179. package/src/cli/threads/list.test.ts +5 -3
  180. package/src/cli/threads/list.ts +10 -10
  181. package/src/cli/threads/messages.ts +11 -7
  182. package/src/cli/threads/respond.ts +11 -7
  183. package/src/cli/threads/send.ts +19 -9
  184. package/src/cli/threads/show.ts +11 -7
  185. package/src/cli/threads/start.ts +18 -13
  186. package/src/cli/threads/unarchive.ts +11 -7
  187. package/src/cli/threads/update.ts +14 -9
  188. package/src/cli/threads/wait.ts +11 -7
  189. package/src/cli/wait-events.ts +1 -1
  190. package/src/config/config.ts +260 -0
  191. package/src/config/credential/cipher-node.ts +40 -0
  192. package/src/config/credential/cipher-web.ts +82 -0
  193. package/src/config/credential/cipher.ts +39 -0
  194. package/src/config/credential/env.ts +13 -0
  195. package/src/config/credential/error.ts +9 -0
  196. package/src/config/credential/index.ts +6 -0
  197. package/src/config/credential/service.test-utils.ts +25 -0
  198. package/src/config/credential/service.test.ts +116 -0
  199. package/src/config/credential/service.ts +205 -0
  200. package/src/config/env/env.test-utils.ts +14 -0
  201. package/src/config/env/env.ts +81 -0
  202. package/src/config/env/index.ts +2 -0
  203. package/src/{layout/base-dir.ts → config/env/layout.ts} +0 -9
  204. package/src/config/environment-name/index.ts +7 -0
  205. package/src/config/environment-name/name.test.ts +66 -0
  206. package/src/config/environment-name/name.ts +49 -0
  207. package/src/config/error.ts +6 -8
  208. package/src/config/index.ts +16 -5
  209. package/src/config/keystore/error.ts +9 -0
  210. package/src/config/keystore/file.ts +96 -0
  211. package/src/config/keystore/index.ts +4 -0
  212. package/src/config/keystore/keyring-node.test.ts +12 -0
  213. package/src/config/keystore/keyring-node.ts +100 -0
  214. package/src/config/keystore/service.test-utils.ts +15 -0
  215. package/src/config/keystore/service.test.ts +18 -0
  216. package/src/config/keystore/service.ts +29 -0
  217. package/src/config/layer.test-utils.ts +45 -0
  218. package/src/config/layer.test.ts +209 -0
  219. package/src/config/paths/index.ts +1 -0
  220. package/src/config/paths/paths.ts +36 -0
  221. package/src/config/persist/file-mode.ts +21 -0
  222. package/src/config/persist/migration.test.ts +71 -0
  223. package/src/config/persist/migration.ts +82 -0
  224. package/src/config/persist/persist.test.ts +113 -0
  225. package/src/config/persist/persist.ts +65 -0
  226. package/src/config/persist/schema.ts +37 -0
  227. package/src/config/platform.test-utils.ts +20 -0
  228. package/src/config/resolve/resolve.test-utils.ts +20 -0
  229. package/src/config/resolve/resolve.test.ts +137 -0
  230. package/src/config/resolve/resolve.ts +104 -0
  231. package/src/config/selection/index.ts +1 -0
  232. package/src/config/selection/resolve.ts +14 -0
  233. package/src/config/selection/service.ts +29 -0
  234. package/src/config/temp-home.test-utils.ts +7 -0
  235. package/src/config/types.ts +49 -0
  236. package/src/config/url/error.ts +8 -0
  237. package/src/config/url/index.ts +7 -0
  238. package/src/config/url/url.test.ts +31 -0
  239. package/src/connection/index.ts +0 -1
  240. package/src/contracts/index.ts +1 -1
  241. package/src/domain/error.ts +20 -1
  242. package/src/domain/helpers.test.ts +1 -1
  243. package/src/domain/helpers.ts +1 -1
  244. package/src/domain/model-config.ts +1 -1
  245. package/src/domain/thread-activities.test.ts +1 -1
  246. package/src/domain/thread-activities.ts +1 -1
  247. package/src/domain/thread-lifecycle.test.ts +1 -1
  248. package/src/domain/thread-lifecycle.ts +1 -1
  249. package/src/effect.test-utils.ts +25 -0
  250. package/src/index.ts +1 -1
  251. package/src/{connection/node.ts → node/connection.ts} +1 -1
  252. package/src/node/index.ts +1 -2
  253. package/src/orchestration/index.ts +0 -1
  254. package/src/orchestration/layer.ts +1 -1
  255. package/src/orchestration/service.ts +1 -1
  256. package/src/rpc/error.ts +2 -2
  257. package/src/rpc/index.ts +2 -3
  258. package/src/rpc/layer.ts +1 -1
  259. package/src/rpc/ws-group.ts +1 -1
  260. package/src/runtime/index.ts +2 -1
  261. package/src/runtime/layer.test-utils.ts +32 -0
  262. package/src/runtime/layer.test.ts +66 -0
  263. package/src/runtime/layer.ts +15 -9
  264. package/src/t3tools/index.ts +1 -1
  265. package/src/types/marked-terminal.d.ts +11 -0
  266. package/dist/layout.js +0 -2
  267. package/dist/scope.js +0 -2
  268. package/dist/src/cli/output-format.d.ts +0 -11
  269. package/dist/src/config/layer.d.ts +0 -22
  270. package/dist/src/config/service.d.ts +0 -22
  271. package/dist/src/environment/layer.d.ts +0 -3
  272. package/dist/src/environment/service.d.ts +0 -12
  273. package/dist/src/layout/index.d.ts +0 -1
  274. package/dist/upstream-t3code/packages/contracts/src/auth.d.ts +0 -441
  275. package/dist/upstream-t3code/packages/contracts/src/baseSchemas.d.ts +0 -38
  276. package/dist/upstream-t3code/packages/contracts/src/desktopBootstrap.d.ts +0 -14
  277. package/dist/upstream-t3code/packages/contracts/src/editor.d.ts +0 -124
  278. package/dist/upstream-t3code/packages/contracts/src/environment.d.ts +0 -64
  279. package/dist/upstream-t3code/packages/contracts/src/environmentHttp.d.ts +0 -762
  280. package/dist/upstream-t3code/packages/contracts/src/filesystem.d.ts +0 -26
  281. package/dist/upstream-t3code/packages/contracts/src/git.d.ts +0 -500
  282. package/dist/upstream-t3code/packages/contracts/src/index.d.ts +0 -25
  283. package/dist/upstream-t3code/packages/contracts/src/ipc.d.ts +0 -490
  284. package/dist/upstream-t3code/packages/contracts/src/keybindings.d.ts +0 -133
  285. package/dist/upstream-t3code/packages/contracts/src/model.d.ts +0 -112
  286. package/dist/upstream-t3code/packages/contracts/src/orchestration.d.ts +0 -6682
  287. package/dist/upstream-t3code/packages/contracts/src/project.d.ts +0 -45
  288. package/dist/upstream-t3code/packages/contracts/src/provider.d.ts +0 -116
  289. package/dist/upstream-t3code/packages/contracts/src/providerInstance.d.ts +0 -99
  290. package/dist/upstream-t3code/packages/contracts/src/providerRuntime.d.ts +0 -4276
  291. package/dist/upstream-t3code/packages/contracts/src/relay.d.ts +0 -1262
  292. package/dist/upstream-t3code/packages/contracts/src/relayClient.d.ts +0 -48
  293. package/dist/upstream-t3code/packages/contracts/src/remoteAccess.d.ts +0 -45
  294. package/dist/upstream-t3code/packages/contracts/src/review.d.ts +0 -37
  295. package/dist/upstream-t3code/packages/contracts/src/rpc.d.ts +0 -8218
  296. package/dist/upstream-t3code/packages/contracts/src/server.d.ts +0 -2291
  297. package/dist/upstream-t3code/packages/contracts/src/settings.d.ts +0 -271
  298. package/dist/upstream-t3code/packages/contracts/src/sourceControl.d.ts +0 -177
  299. package/dist/upstream-t3code/packages/contracts/src/terminal.d.ts +0 -330
  300. package/dist/upstream-t3code/packages/contracts/src/vcs.d.ts +0 -148
  301. package/src/cli/auth-format.ts +0 -45
  302. package/src/cli/confirm.ts +0 -31
  303. package/src/cli/model-format.ts +0 -18
  304. package/src/cli/output-format.ts +0 -45
  305. package/src/cli/project-format.ts +0 -18
  306. package/src/cli/terminal/commands.test.ts +0 -101
  307. package/src/cli/terminal-format.ts +0 -167
  308. package/src/cli/thread-format.ts +0 -128
  309. package/src/config/layer.ts +0 -105
  310. package/src/config/service.ts +0 -26
  311. package/src/environment/layer.ts +0 -12
  312. package/src/environment/service.ts +0 -13
  313. package/src/layout/index.ts +0 -1
  314. /package/dist/src/{scope → cli/scope}/index.d.ts +0 -0
  315. /package/dist/src/config/{url.d.ts → url/url.d.ts} +0 -0
  316. /package/src/{scope → cli/scope}/index.ts +0 -0
  317. /package/src/config/{url.ts → url/url.ts} +0 -0
@@ -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,9 @@
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";
4
7
  import { createTerminalCommandGroup } from "./terminal.ts";
5
8
  import { createModelCommand } from "./model.ts";
6
9
  import { createProjectCommand } from "./project.ts";
@@ -15,8 +18,11 @@ import { waitForThreadCommand } from "./threads/wait.ts";
15
18
  export function createCliCommand() {
16
19
  return Command.make("t3cli").pipe(
17
20
  Command.withDescription("non-interactive cli for running t3code server"),
21
+ Command.withGlobalFlags([cliEnvironmentSetting]),
18
22
  Command.withSubcommands([
23
+ createActionCommand(),
19
24
  createAuthCommand(),
25
+ createEnvCommand(),
20
26
  listThreadsCommand,
21
27
  createModelCommand(),
22
28
  createProjectCommand(),
package/src/cli/auth.ts CHANGED
@@ -8,14 +8,49 @@ import {
8
8
  formatAuthPaired,
9
9
  formatAuthStatusHuman,
10
10
  formatAuthStatusJson,
11
- } from "./auth-format.ts";
11
+ } from "./format/auth.ts";
12
12
  import { T3Auth } from "../auth/service.ts";
13
- import { T3Config } from "../config/service.ts";
14
- import { Environment } from "../environment/service.ts";
15
- import { formatFlag } from "./flags.ts";
16
- import { resolveOutputFormat } from "./output-format.ts";
13
+ import { extraArgsConfig } from "./extra-args.ts";
14
+ import { CliRuntime } from "../cli/runtime/service.ts";
15
+ import { loadT3CliEnv } from "../config/env/env.ts";
16
+ import { requireEnvironmentReplaceConfirmation } from "./interaction/confirm.ts";
17
+ import { envNameFlag, formatFlag, replaceFlag } from "./flags.ts";
18
+ import { resolveOutputFormat } from "./format/output.ts";
17
19
  import { T3Output } from "./output/service.ts";
18
20
 
21
+ const persistAuthEnvironment = Effect.fn("persistAuthEnvironment")(function* (input: {
22
+ readonly explicitName: Option.Option<string>;
23
+ readonly fallbackName: string;
24
+ readonly url: string;
25
+ readonly token: string;
26
+ readonly local: boolean;
27
+ readonly replace: boolean;
28
+ }) {
29
+ const auth = yield* T3Auth;
30
+ const cliRuntime = yield* CliRuntime;
31
+ const t3CliEnv = yield* loadT3CliEnv;
32
+ const environmentName = Option.isSome(input.explicitName)
33
+ ? input.explicitName.value
34
+ : input.fallbackName;
35
+ const exists = yield* auth.environmentExists(environmentName);
36
+ if (exists) {
37
+ yield* requireEnvironmentReplaceConfirmation({
38
+ name: environmentName,
39
+ replace: input.replace,
40
+ cliRuntime,
41
+ t3CliEnv,
42
+ });
43
+ }
44
+ return yield* auth.persistEnvironment({
45
+ name: environmentName,
46
+ url: input.url,
47
+ token: input.token,
48
+ local: input.local,
49
+ replace: input.replace,
50
+ allowReplace: true,
51
+ });
52
+ });
53
+
19
54
  export function createAuthCommand() {
20
55
  return Command.make("auth").pipe(
21
56
  Command.withDescription("auth commands"),
@@ -28,24 +63,33 @@ const pairCommand = Command.make(
28
63
  {
29
64
  url: Flag.string("url"),
30
65
  local: Flag.boolean("local"),
66
+ name: envNameFlag,
67
+ replace: replaceFlag,
31
68
  format: formatFlag,
69
+ ...extraArgsConfig,
32
70
  },
33
- ({ url, local, format }) =>
71
+ ({ url, local, name, replace, format }) =>
34
72
  Effect.gen(function* () {
35
73
  const auth = yield* T3Auth;
36
- const environment = yield* Environment;
74
+ const cliRuntime = yield* CliRuntime;
75
+ const t3CliEnv = yield* loadT3CliEnv;
37
76
  const output = yield* T3Output;
38
- const resolvedFormat = resolveOutputFormat(format, environment, "json");
77
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
39
78
  const result = yield* auth.pair(url);
40
- yield* auth.writeConfig({
79
+ const fallbackName = yield* auth.defaultNameFromUrl(result.url);
80
+ const environmentName = yield* persistAuthEnvironment({
81
+ explicitName: name,
82
+ fallbackName,
41
83
  url: result.url,
42
84
  token: result.token,
43
85
  local,
86
+ replace,
44
87
  });
88
+ const payload = { ...result, name: environmentName };
45
89
  if (resolvedFormat === "json") {
46
- yield* output.printJson(result);
90
+ yield* output.printJson(payload);
47
91
  } else {
48
- yield* output.printInfo(formatAuthPaired(result));
92
+ yield* output.printInfo(formatAuthPaired(payload));
49
93
  }
50
94
  }),
51
95
  ).pipe(Command.withDescription("pair with t3code server"));
@@ -58,14 +102,18 @@ const localCommand = Command.make(
58
102
  role: Flag.choice("role", ["owner", "client"] as const).pipe(Flag.withDefault("owner")),
59
103
  label: Flag.string("label").pipe(Flag.withDefault("t3cli")),
60
104
  subject: Flag.string("subject").pipe(Flag.withDefault("t3cli-local")),
105
+ name: envNameFlag,
106
+ replace: replaceFlag,
61
107
  format: formatFlag,
108
+ ...extraArgsConfig,
62
109
  },
63
- ({ baseDir, origin, role, label, subject, format }) =>
110
+ ({ baseDir, origin, role, label, subject, name, replace, format }) =>
64
111
  Effect.gen(function* () {
65
112
  const auth = yield* T3Auth;
66
- const environment = yield* Environment;
113
+ const cliRuntime = yield* CliRuntime;
114
+ const t3CliEnv = yield* loadT3CliEnv;
67
115
  const output = yield* T3Output;
68
- const resolvedFormat = resolveOutputFormat(format, environment, "json");
116
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
69
117
  const result = yield* auth.local({
70
118
  role,
71
119
  label,
@@ -73,15 +121,20 @@ const localCommand = Command.make(
73
121
  ...(Option.isSome(baseDir) ? { baseDir: baseDir.value } : {}),
74
122
  ...(Option.isSome(origin) ? { origin: origin.value } : {}),
75
123
  });
76
- yield* auth.writeConfig({
124
+ const fallbackName = yield* auth.defaultNameForLocal();
125
+ const environmentName = yield* persistAuthEnvironment({
126
+ explicitName: name,
127
+ fallbackName,
77
128
  url: result.url,
78
129
  token: result.token,
79
130
  local: true,
131
+ replace,
80
132
  });
133
+ const payload = { ...result, name: environmentName };
81
134
  if (resolvedFormat === "json") {
82
- yield* output.printJson(formatAuthLocalJson(result));
135
+ yield* output.printJson(formatAuthLocalJson(payload));
83
136
  } else {
84
- yield* output.printInfo(formatAuthLocalHuman(result));
137
+ yield* output.printInfo(formatAuthLocalHuman(payload));
85
138
  }
86
139
  }),
87
140
  ).pipe(Command.withDescription("authenticate with local t3code installation"));
@@ -90,20 +143,20 @@ const statusCommand = Command.make(
90
143
  "status",
91
144
  {
92
145
  format: formatFlag,
146
+ ...extraArgsConfig,
93
147
  },
94
148
  ({ format }) =>
95
149
  Effect.gen(function* () {
96
- const configService = yield* T3Config;
97
150
  const auth = yield* T3Auth;
98
- const environment = yield* Environment;
151
+ const cliRuntime = yield* CliRuntime;
152
+ const t3CliEnv = yield* loadT3CliEnv;
99
153
  const output = yield* T3Output;
100
- const resolvedFormat = resolveOutputFormat(format, environment, "json");
101
- const config = yield* configService.resolve();
154
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
102
155
  const result = yield* auth.status();
103
156
  if (resolvedFormat === "json") {
104
- yield* output.printJson(formatAuthStatusJson({ config, result }));
157
+ yield* output.printJson(formatAuthStatusJson(result));
105
158
  } else {
106
- yield* output.printInfo(formatAuthStatusHuman({ config, result }));
159
+ yield* output.printInfo(formatAuthStatusHuman(result));
107
160
  }
108
161
  }),
109
162
  ).pipe(Command.withDescription("show auth status"));
@@ -0,0 +1,8 @@
1
+ import { Flag, GlobalFlag } from "effect/unstable/cli";
2
+
3
+ export const cliEnvironmentSetting = GlobalFlag.setting("environment")({
4
+ flag: Flag.string("environment").pipe(
5
+ Flag.withDescription("Auth environment name for this command"),
6
+ Flag.optional,
7
+ ),
8
+ });
@@ -0,0 +1,2 @@
1
+ export { cliEnvironmentSetting } from "./flag.ts";
2
+ export * as Selection from "./selection-layer.ts";
@@ -0,0 +1,49 @@
1
+ import "vite-plus/test/config";
2
+
3
+ import * as Effect from "effect/Effect";
4
+ import { assert, describe, it } from "@effect/vitest";
5
+
6
+ import { T3Config } from "../../config/config.ts";
7
+ import { ConfigPlatformLayer } from "../../config/platform.test-utils.ts";
8
+ import { makeTempHomeScoped } from "../../config/temp-home.test-utils.ts";
9
+ import { t3ConfigDepsLayer } from "../../config/layer.test-utils.ts";
10
+
11
+ describe("T3ConfigSelectionLive", () => {
12
+ it.effect("resolves T3CLI_ENV through the selection layer", () =>
13
+ Effect.gen(function* () {
14
+ return yield* makeTempHomeScoped("t3cli-selection-");
15
+ }).pipe(
16
+ Effect.flatMap((homeDir) =>
17
+ Effect.gen(function* () {
18
+ const config = yield* T3Config;
19
+ yield* config.upsertEnvironment({
20
+ name: "home",
21
+ url: "https://home.example",
22
+ token: "home-token",
23
+ local: false,
24
+ });
25
+ yield* config.upsertEnvironment({
26
+ name: "work",
27
+ url: "https://work.example",
28
+ token: "work-token",
29
+ local: true,
30
+ });
31
+ const resolved = yield* config.resolve();
32
+ assert.equal(resolved.source, "config");
33
+ if (resolved.source === "config") {
34
+ assert.equal(resolved.environment, "work");
35
+ }
36
+ }).pipe(
37
+ Effect.provide(
38
+ t3ConfigDepsLayer(homeDir, {
39
+ useSelectionLive: true,
40
+ env: { T3CLI_ENV: "work" },
41
+ }),
42
+ ),
43
+ ),
44
+ ),
45
+ Effect.provide(ConfigPlatformLayer),
46
+ Effect.scoped,
47
+ ),
48
+ );
49
+ });
@@ -0,0 +1,27 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
3
+ import * as Option from "effect/Option";
4
+
5
+ import { resolveConfiguredEnvironment } from "../../config/selection/resolve.ts";
6
+ import { T3ConfigSelection } from "../../config/selection/service.ts";
7
+ import { loadT3CliEnv } from "../../config/env/env.ts";
8
+ import { cliEnvironmentSetting } from "./flag.ts";
9
+
10
+ export const layer = Layer.effect(
11
+ T3ConfigSelection,
12
+ Effect.gen(function* () {
13
+ const t3CliEnv = yield* loadT3CliEnv;
14
+ return {
15
+ getSelectedEnvironment: () =>
16
+ Effect.gen(function* () {
17
+ const cliEnvironment = yield* Effect.serviceOption(cliEnvironmentSetting);
18
+ return resolveConfiguredEnvironment({
19
+ cliFlag: Option.isSome(cliEnvironment)
20
+ ? Option.getOrUndefined(cliEnvironment.value)
21
+ : undefined,
22
+ t3cliEnv: Option.getOrUndefined(t3CliEnv.t3cliEnv),
23
+ });
24
+ }),
25
+ };
26
+ }),
27
+ );