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
@@ -3,16 +3,18 @@ import * as Option from "effect/Option";
3
3
  import * as Stream from "effect/Stream";
4
4
  import { Argument, Command, Flag } from "effect/unstable/cli";
5
5
 
6
+ import { extraArgsConfig } from "../extra-args.ts";
6
7
  import { modelFlags, projectFlag, threadFormatFlag, worktreeFlag } from "../flags.ts";
7
8
  import { readInitialMessage } from "../message-input.ts";
8
9
  import { buildModelOptions } from "../model-options.ts";
9
10
  import { requireCommandProjectRef } from "../require.ts";
10
- import { resolveWorktreePath } from "../../scope/index.ts";
11
- import { formatThreadStartedHuman } from "../thread-format.ts";
11
+ import { resolveWorktreePath } from "../scope/index.ts";
12
+ import { formatThreadStartedHuman } from "../format/thread.ts";
12
13
  import { T3Application } from "../../application/service.ts";
13
- import { Environment } from "../../environment/service.ts";
14
+ import { CliRuntime } from "../../cli/runtime/service.ts";
15
+ import { loadT3CliEnv } from "../../config/env/env.ts";
14
16
  import { T3Input } from "../input/service.ts";
15
- import { canRenderLiveTerminal, resolveOutputFormat } from "../output-format.ts";
17
+ import { canRenderLiveTerminal, resolveOutputFormat } from "../format/output.ts";
16
18
  import { T3Output } from "../output/service.ts";
17
19
  import { printWaitEventsHuman, printWaitEventsNdjson } from "../wait-events.ts";
18
20
 
@@ -29,6 +31,7 @@ export const startThreadCommand = Command.make(
29
31
  ...modelFlags,
30
32
  wait: Flag.boolean("wait"),
31
33
  format: threadFormatFlag,
34
+ ...extraArgsConfig,
32
35
  },
33
36
  ({
34
37
  project,
@@ -64,16 +67,13 @@ export const startThreadCommand = Command.make(
64
67
  thinking,
65
68
  });
66
69
  const application = yield* T3Application;
67
- const environment = yield* Environment;
70
+ const cliRuntime = yield* CliRuntime;
71
+ const t3CliEnv = yield* loadT3CliEnv;
68
72
  const output = yield* T3Output;
69
- const projectRef = yield* requireCommandProjectRef({
70
- project,
71
- env: environment.env,
72
- cwd: environment.cwd,
73
- });
73
+ const projectRef = yield* requireCommandProjectRef({ project });
74
74
  const worktreePath = resolveWorktreePath({
75
75
  value: Option.getOrUndefined(worktree),
76
- env: environment.env,
76
+ scope: t3CliEnv.scope,
77
77
  });
78
78
  const input = {
79
79
  message: text,
@@ -86,7 +86,12 @@ export const startThreadCommand = Command.make(
86
86
  ...(modelValue !== undefined && modelValue.length > 0 ? { model: modelValue } : {}),
87
87
  ...(options.length > 0 ? { options } : {}),
88
88
  };
89
- const resolvedFormat = resolveOutputFormat(format, environment, wait ? "ndjson" : "json");
89
+ const resolvedFormat = resolveOutputFormat(
90
+ format,
91
+ cliRuntime,
92
+ t3CliEnv,
93
+ wait ? "ndjson" : "json",
94
+ );
90
95
 
91
96
  if (resolvedFormat === "ndjson") {
92
97
  const started = yield* application.startThread(input, {
@@ -117,7 +122,7 @@ export const startThreadCommand = Command.make(
117
122
  }
118
123
  yield* printWaitEventsHuman(output, application.watchThread(started.threadId), {
119
124
  threadId: started.threadId,
120
- live: canRenderLiveTerminal(environment),
125
+ live: canRenderLiveTerminal(cliRuntime, t3CliEnv),
121
126
  });
122
127
  return;
123
128
  }
@@ -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 { extraArgsConfig } from "../extra-args.ts";
6
+ import { formatFlag, threadFlag } from "../flags.ts";
7
+ import { MissingThreadError } from "../error.ts";
8
+ import { resolveThreadId } from "../scope/index.ts";
9
+ import { T3Application } from "../../application/service.ts";
10
+ import { CliRuntime } from "../../cli/runtime/service.ts";
11
+ import { loadT3CliEnv } from "../../config/env/env.ts";
12
+ import { resolveOutputFormat } from "../format/output.ts";
13
+ import { T3Output } from "../output/service.ts";
14
+
15
+ export const unarchiveThreadCommand = Command.make(
16
+ "unarchive",
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.unarchiveThread(threadId);
41
+ if (resolvedFormat === "json") {
42
+ return yield* output.printJson(dispatch);
43
+ }
44
+ return yield* output.printInfo(
45
+ `thread unarchived: ${threadId} (sequence ${dispatch.sequence})`,
46
+ );
47
+ }),
48
+ ).pipe(Command.withDescription("unarchive thread"));
@@ -0,0 +1,155 @@
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 { extraArgsConfig } from "../extra-args.ts";
6
+ import { formatFlag, modelFlags, selfActionForceFlag, threadFlag } from "../flags.ts";
7
+ import {
8
+ ConflictingUpdateFlagsError,
9
+ MissingThreadError,
10
+ MissingUpdateFieldsError,
11
+ } from "../error.ts";
12
+ import { requireSelfActionConfirmation } from "../interaction/self-action.ts";
13
+ import { buildModelOptions } from "../model-options.ts";
14
+ import { resolveThreadId } from "../scope/index.ts";
15
+ import { T3Application } from "../../application/service.ts";
16
+ import { CliRuntime } from "../../cli/runtime/service.ts";
17
+ import { loadT3CliEnv } from "../../config/env/env.ts";
18
+ import { resolveOutputFormat } from "../format/output.ts";
19
+ import { T3Output } from "../output/service.ts";
20
+
21
+ export const updateThreadCommand = Command.make(
22
+ "update",
23
+ {
24
+ thread: threadFlag,
25
+ force: selfActionForceFlag,
26
+ title: Flag.string("title").pipe(Flag.optional),
27
+ provider: Flag.string("provider").pipe(Flag.optional),
28
+ model: Flag.string("model").pipe(Flag.optional),
29
+ ...modelFlags,
30
+ branch: Flag.string("branch").pipe(Flag.optional),
31
+ clearBranch: Flag.boolean("clear-branch").pipe(Flag.optional),
32
+ worktree: Flag.string("worktree").pipe(Flag.optional),
33
+ clearWorktree: Flag.boolean("clear-worktree").pipe(Flag.optional),
34
+ format: formatFlag,
35
+ ...extraArgsConfig,
36
+ },
37
+ ({
38
+ thread,
39
+ force,
40
+ title,
41
+ provider,
42
+ model,
43
+ option,
44
+ reasoningEffort,
45
+ effort,
46
+ fastMode,
47
+ thinking,
48
+ branch,
49
+ clearBranch,
50
+ worktree,
51
+ clearWorktree,
52
+ format,
53
+ }) =>
54
+ Effect.gen(function* () {
55
+ const application = yield* T3Application;
56
+ const cliRuntime = yield* CliRuntime;
57
+ const t3CliEnv = yield* loadT3CliEnv;
58
+ const output = yield* T3Output;
59
+ const threadId = resolveThreadId({
60
+ value: Option.getOrUndefined(thread),
61
+ scope: t3CliEnv.scope,
62
+ });
63
+ if (threadId === undefined) {
64
+ return yield* Effect.fail(
65
+ new MissingThreadError({
66
+ message: "thread id is required: pass --thread or set T3CODE_THREAD_ID",
67
+ }),
68
+ );
69
+ }
70
+
71
+ yield* requireSelfActionConfirmation({
72
+ threadId,
73
+ force,
74
+ cliRuntime,
75
+ t3CliEnv,
76
+ action: "update",
77
+ });
78
+
79
+ const titleValue = Option.getOrUndefined(title);
80
+ const providerValue = Option.getOrUndefined(provider);
81
+ const modelValue = Option.getOrUndefined(model);
82
+ const branchValue = Option.getOrUndefined(branch);
83
+ const worktreeValue = Option.getOrUndefined(worktree);
84
+ const clearBranchValue = Option.getOrUndefined(clearBranch);
85
+ const clearWorktreeValue = Option.getOrUndefined(clearWorktree);
86
+ const options = buildModelOptions({
87
+ option,
88
+ reasoningEffort,
89
+ effort,
90
+ fastMode,
91
+ thinking,
92
+ });
93
+
94
+ if (clearBranchValue === true && branchValue !== undefined) {
95
+ return yield* Effect.fail(
96
+ new ConflictingUpdateFlagsError({
97
+ message: "--branch and --clear-branch are mutually exclusive",
98
+ }),
99
+ );
100
+ }
101
+ if (clearWorktreeValue === true && worktreeValue !== undefined) {
102
+ return yield* Effect.fail(
103
+ new ConflictingUpdateFlagsError({
104
+ message: "--worktree and --clear-worktree are mutually exclusive",
105
+ }),
106
+ );
107
+ }
108
+
109
+ const hasTitle = titleValue !== undefined && titleValue.length > 0;
110
+ const hasProvider = providerValue !== undefined && providerValue.length > 0;
111
+ const hasModel = modelValue !== undefined && modelValue.length > 0;
112
+ const hasBranch = branchValue !== undefined && branchValue.length > 0;
113
+ const hasWorktree = worktreeValue !== undefined && worktreeValue.length > 0;
114
+ if (
115
+ !hasTitle &&
116
+ !hasProvider &&
117
+ !hasModel &&
118
+ options.length === 0 &&
119
+ !hasBranch &&
120
+ clearBranchValue !== true &&
121
+ !hasWorktree &&
122
+ clearWorktreeValue !== true
123
+ ) {
124
+ return yield* Effect.fail(
125
+ new MissingUpdateFieldsError({
126
+ message:
127
+ "at least one update field is required: --title, model flags, --branch, --clear-branch, --worktree, or --clear-worktree",
128
+ }),
129
+ );
130
+ }
131
+
132
+ const dispatch = yield* application.updateThread({
133
+ threadId,
134
+ ...(hasTitle ? { title: titleValue } : {}),
135
+ ...(hasProvider ? { provider: providerValue } : {}),
136
+ ...(hasModel ? { model: modelValue } : {}),
137
+ ...(options.length > 0 ? { options } : {}),
138
+ ...(clearBranchValue === true
139
+ ? { branch: null }
140
+ : hasBranch
141
+ ? { branch: branchValue }
142
+ : {}),
143
+ ...(clearWorktreeValue === true
144
+ ? { worktreePath: null }
145
+ : hasWorktree
146
+ ? { worktreePath: worktreeValue }
147
+ : {}),
148
+ });
149
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "json");
150
+ if (resolvedFormat === "json") {
151
+ return yield* output.printJson(dispatch);
152
+ }
153
+ return yield* output.printInfo(`thread updated: ${threadId} (sequence ${dispatch.sequence})`);
154
+ }),
155
+ ).pipe(Command.withDescription("update thread metadata"));
@@ -2,12 +2,14 @@ import * as Effect from "effect/Effect";
2
2
  import * as Option from "effect/Option";
3
3
  import { Command } from "effect/unstable/cli";
4
4
 
5
+ import { extraArgsConfig } from "../extra-args.ts";
5
6
  import { threadFlag, waitFormatFlag } from "../flags.ts";
6
7
  import { MissingThreadError } from "../error.ts";
7
- import { resolveThreadId } from "../../scope/index.ts";
8
- import { Environment } from "../../environment/service.ts";
8
+ import { resolveThreadId } from "../scope/index.ts";
9
+ import { CliRuntime } from "../../cli/runtime/service.ts";
10
+ import { loadT3CliEnv } from "../../config/env/env.ts";
9
11
  import { T3Application } from "../../application/service.ts";
10
- import { canRenderLiveTerminal, resolveOutputFormat } from "../output-format.ts";
12
+ import { canRenderLiveTerminal, resolveOutputFormat } from "../format/output.ts";
11
13
  import { T3Output } from "../output/service.ts";
12
14
  import { printWaitEventsHuman, printWaitEventsNdjson } from "../wait-events.ts";
13
15
 
@@ -16,15 +18,17 @@ export const waitForThreadCommand = Command.make(
16
18
  {
17
19
  thread: threadFlag,
18
20
  format: waitFormatFlag,
21
+ ...extraArgsConfig,
19
22
  },
20
23
  ({ thread, format }) =>
21
24
  Effect.gen(function* () {
22
25
  const application = yield* T3Application;
23
- const environment = yield* Environment;
26
+ const cliRuntime = yield* CliRuntime;
27
+ const t3CliEnv = yield* loadT3CliEnv;
24
28
  const output = yield* T3Output;
25
29
  const threadId = resolveThreadId({
26
30
  value: Option.getOrUndefined(thread),
27
- env: environment.env,
31
+ scope: t3CliEnv.scope,
28
32
  });
29
33
  if (threadId === undefined) {
30
34
  return yield* Effect.fail(
@@ -33,13 +37,13 @@ export const waitForThreadCommand = Command.make(
33
37
  }),
34
38
  );
35
39
  }
36
- const resolvedFormat = resolveOutputFormat(format, environment, "ndjson");
40
+ const resolvedFormat = resolveOutputFormat(format, cliRuntime, t3CliEnv, "ndjson");
37
41
  if (resolvedFormat === "ndjson") {
38
42
  return yield* printWaitEventsNdjson(output, application.watchThread(threadId));
39
43
  }
40
44
  return yield* printWaitEventsHuman(output, application.watchThread(threadId), {
41
45
  threadId,
42
- live: canRenderLiveTerminal(environment),
46
+ live: canRenderLiveTerminal(cliRuntime, t3CliEnv),
43
47
  });
44
48
  }),
45
49
  ).pipe(Command.withDescription("wait for thread to pause"));
@@ -8,7 +8,7 @@ import type { WaitEvent } from "../application/service.ts";
8
8
  import { ThreadSessionError } from "../domain/error.ts";
9
9
  import { latestAssistantMessage } from "../domain/thread-lifecycle.ts";
10
10
  import type { T3Output } from "./output/service.ts";
11
- import { formatWaitDoneHuman, formatWaitEventNdjson } from "./thread-format.ts";
11
+ import { formatWaitDoneHuman, formatWaitEventNdjson } from "./format/thread.ts";
12
12
 
13
13
  export function printWaitEventsNdjson(
14
14
  output: T3Output["Service"],
@@ -0,0 +1,260 @@
1
+ import * as Context from "effect/Context";
2
+ import * as ConfigProvider from "effect/ConfigProvider";
3
+ import * as Effect from "effect/Effect";
4
+ import * as FileSystem from "effect/FileSystem";
5
+ import * as Layer from "effect/Layer";
6
+ import * as Option from "effect/Option";
7
+ import * as Path from "effect/Path";
8
+
9
+ import { credentialTokenFromEnv } from "./credential/env.ts";
10
+ import { T3CredentialCrypto } from "./credential/service.ts";
11
+ import { loadT3CliEnv } from "./env/env.ts";
12
+ import { validateEnvironmentName } from "./environment-name/name.ts";
13
+ import { ConfigError } from "./error.ts";
14
+ import { readEncryptedConfigFile, writeEncryptedConfigFile } from "./persist/persist.ts";
15
+ import {
16
+ buildResolvedConfigFromEnv,
17
+ buildResolvedConfigFromStored,
18
+ resolveDefaultForUpsert,
19
+ selectEnvironmentName,
20
+ summarizeEnvironments,
21
+ validateCredentialEnvVars,
22
+ } from "./resolve/resolve.ts";
23
+ import { T3ConfigSelection } from "./selection/service.ts";
24
+ import type { EnvironmentSummary, ResolvedConfig, UpsertEnvironmentInput } from "./types.ts";
25
+ import { normalizeHttpBaseUrl } from "./url/url.ts";
26
+
27
+ export class T3Config extends Context.Service<
28
+ T3Config,
29
+ {
30
+ readonly resolve: () => Effect.Effect<ResolvedConfig, ConfigError>;
31
+ readonly resolveActiveEnvironmentName: () => Effect.Effect<string | undefined, ConfigError>;
32
+ readonly listEnvironments: () => Effect.Effect<readonly EnvironmentSummary[], ConfigError>;
33
+ readonly upsertEnvironment: (input: UpsertEnvironmentInput) => Effect.Effect<void, ConfigError>;
34
+ readonly setDefaultEnvironment: (name: string) => Effect.Effect<void, ConfigError>;
35
+ readonly removeEnvironment: (name: string) => Effect.Effect<void, ConfigError>;
36
+ readonly hasEnvironment: (name: string) => Effect.Effect<boolean, ConfigError>;
37
+ readonly getDefaultEnvironmentName: () => Effect.Effect<string | undefined, ConfigError>;
38
+ }
39
+ >()("t3cli/T3Config") {}
40
+
41
+ export const make = Effect.fn("makeT3Config")(function* () {
42
+ const configSelection = yield* T3ConfigSelection;
43
+ const credentialCrypto = yield* T3CredentialCrypto;
44
+ const t3CliEnv = yield* loadT3CliEnv;
45
+ const fs = yield* FileSystem.FileSystem;
46
+ const path = yield* Path.Path;
47
+ const configProvider = yield* ConfigProvider.ConfigProvider;
48
+ const services = Layer.mergeAll(
49
+ Layer.succeed(FileSystem.FileSystem, fs),
50
+ Layer.succeed(Path.Path, path),
51
+ Layer.succeed(T3CredentialCrypto, credentialCrypto),
52
+ Layer.succeed(ConfigProvider.ConfigProvider, configProvider),
53
+ );
54
+
55
+ const hasEnvironment = Effect.fn("T3Config.hasEnvironment")(function* (name: string) {
56
+ const encrypted = yield* Effect.provide(readEncryptedConfigFile(), services);
57
+ return encrypted.environments[name] !== undefined;
58
+ });
59
+
60
+ const getDefaultEnvironmentName = Effect.fn("T3Config.getDefaultEnvironmentName")(function* () {
61
+ const encrypted = yield* Effect.provide(readEncryptedConfigFile(), services);
62
+ const defaultName = encrypted.default;
63
+ return defaultName !== undefined && defaultName.length > 0 ? defaultName : undefined;
64
+ });
65
+
66
+ const resolveActiveEnvironmentName = Effect.fn("T3Config.resolveActiveEnvironmentName")(
67
+ function* () {
68
+ const encrypted = yield* Effect.provide(readEncryptedConfigFile(), services);
69
+ const envUrl = Option.getOrUndefined(t3CliEnv.t3codeUrl);
70
+ const envToken = Option.getOrUndefined(credentialTokenFromEnv(t3CliEnv));
71
+ yield* validateCredentialEnvVars({ envUrl, envToken });
72
+ const hasEnvCredentials = envUrl !== undefined && envToken !== undefined;
73
+ if (hasEnvCredentials) {
74
+ return undefined;
75
+ }
76
+ const configuredEnvironment = yield* configSelection.getSelectedEnvironment();
77
+ const selectedName = selectEnvironmentName({
78
+ selectedEnvironment: configuredEnvironment,
79
+ defaultEnvironment: encrypted.default,
80
+ });
81
+ if (selectedName === undefined || selectedName.length === 0) {
82
+ return undefined;
83
+ }
84
+ if (encrypted.environments[selectedName] === undefined) {
85
+ return undefined;
86
+ }
87
+ return selectedName;
88
+ },
89
+ );
90
+
91
+ const listEnvironments = Effect.fn("T3Config.listEnvironments")(function* () {
92
+ const encrypted = yield* Effect.provide(readEncryptedConfigFile(), services);
93
+ return summarizeEnvironments(encrypted);
94
+ });
95
+
96
+ const upsertEnvironment = Effect.fn("T3Config.upsertEnvironment")(function* (
97
+ input: UpsertEnvironmentInput,
98
+ ) {
99
+ yield* validateEnvironmentName(input.name);
100
+ const normalizedUrl = yield* normalizeHttpBaseUrl(input.url).pipe(
101
+ Effect.mapError((error) => new ConfigError({ message: error.message, cause: error.cause })),
102
+ );
103
+ const encrypted = yield* Effect.provide(readEncryptedConfigFile(), services);
104
+ const token = yield* credentialCrypto.encrypt({
105
+ environmentName: input.name,
106
+ url: normalizedUrl,
107
+ local: input.local,
108
+ token: input.token,
109
+ });
110
+ const defaultName = resolveDefaultForUpsert(encrypted, input.name, input.makeDefault);
111
+ yield* Effect.provide(
112
+ writeEncryptedConfigFile({
113
+ version: 2,
114
+ ...(defaultName !== undefined ? { default: defaultName } : {}),
115
+ environments: {
116
+ ...encrypted.environments,
117
+ [input.name]: {
118
+ url: normalizedUrl,
119
+ local: input.local,
120
+ token,
121
+ },
122
+ },
123
+ }),
124
+ services,
125
+ );
126
+ });
127
+
128
+ const setDefaultEnvironment = Effect.fn("T3Config.setDefaultEnvironment")(function* (
129
+ name: string,
130
+ ) {
131
+ yield* validateEnvironmentName(name);
132
+ const encrypted = yield* Effect.provide(readEncryptedConfigFile(), services);
133
+ if (encrypted.environments[name] === undefined) {
134
+ return yield* Effect.fail(new ConfigError({ message: `environment not found: ${name}` }));
135
+ }
136
+ const selectedEnvironment = encrypted.environments[name];
137
+ yield* credentialCrypto
138
+ .decrypt({
139
+ environmentName: name,
140
+ url: selectedEnvironment.url,
141
+ local: selectedEnvironment.local,
142
+ token: selectedEnvironment.token,
143
+ })
144
+ .pipe(
145
+ Effect.mapError(
146
+ (error) =>
147
+ new ConfigError({
148
+ message: `failed to decrypt credentials for environment '${name}'`,
149
+ cause: error.cause,
150
+ }),
151
+ ),
152
+ Effect.asVoid,
153
+ );
154
+ yield* Effect.provide(
155
+ writeEncryptedConfigFile({
156
+ ...encrypted,
157
+ default: name,
158
+ }),
159
+ services,
160
+ );
161
+ return yield* Effect.void;
162
+ });
163
+
164
+ const removeEnvironment = Effect.fn("T3Config.removeEnvironment")(function* (name: string) {
165
+ yield* validateEnvironmentName(name);
166
+ const encrypted = yield* Effect.provide(readEncryptedConfigFile(), services);
167
+ if (encrypted.environments[name] === undefined) {
168
+ return yield* Effect.fail(new ConfigError({ message: `environment not found: ${name}` }));
169
+ }
170
+ const { [name]: _removed, ...environments } = encrypted.environments;
171
+ const defaultName = encrypted.default === name ? undefined : encrypted.default;
172
+ yield* Effect.provide(
173
+ writeEncryptedConfigFile({
174
+ version: 2,
175
+ ...(defaultName !== undefined ? { default: defaultName } : {}),
176
+ environments,
177
+ }),
178
+ services,
179
+ );
180
+ return yield* Effect.void;
181
+ });
182
+
183
+ const resolve = Effect.fn("T3Config.resolve")(function* () {
184
+ const encrypted = yield* Effect.provide(readEncryptedConfigFile(), services);
185
+ const envUrl = Option.getOrUndefined(t3CliEnv.t3codeUrl);
186
+ const envToken = Option.getOrUndefined(credentialTokenFromEnv(t3CliEnv));
187
+ yield* validateCredentialEnvVars({ envUrl, envToken });
188
+ const hasEnvUrl = envUrl !== undefined;
189
+ const configuredEnvironment = yield* configSelection.getSelectedEnvironment();
190
+ const selectedName = selectEnvironmentName({
191
+ selectedEnvironment: configuredEnvironment,
192
+ defaultEnvironment: encrypted.default,
193
+ });
194
+
195
+ if (hasEnvUrl && envToken !== undefined) {
196
+ if (selectedName !== undefined && selectedName.length > 0) {
197
+ yield* validateEnvironmentName(selectedName);
198
+ if (encrypted.environments[selectedName] === undefined) {
199
+ return yield* Effect.fail(
200
+ new ConfigError({ message: `environment not found: ${selectedName}` }),
201
+ );
202
+ }
203
+ }
204
+ return yield* buildResolvedConfigFromEnv({
205
+ envUrl,
206
+ envToken,
207
+ });
208
+ }
209
+
210
+ if (selectedName === undefined || selectedName.length === 0) {
211
+ return yield* Effect.fail(
212
+ new ConfigError({
213
+ message: "not authenticated. run: t3cli auth pair --url <pairing-url>",
214
+ }),
215
+ );
216
+ }
217
+ yield* validateEnvironmentName(selectedName);
218
+ if (encrypted.environments[selectedName] === undefined) {
219
+ return yield* Effect.fail(
220
+ new ConfigError({ message: `environment not found: ${selectedName}` }),
221
+ );
222
+ }
223
+
224
+ const selectedEnvironment = encrypted.environments[selectedName];
225
+ const token = yield* credentialCrypto
226
+ .decrypt({
227
+ environmentName: selectedName,
228
+ url: selectedEnvironment.url,
229
+ local: selectedEnvironment.local,
230
+ token: selectedEnvironment.token,
231
+ })
232
+ .pipe(
233
+ Effect.mapError(
234
+ (error) =>
235
+ new ConfigError({
236
+ message: `failed to decrypt credentials for environment '${selectedName}'`,
237
+ cause: error.cause,
238
+ }),
239
+ ),
240
+ );
241
+ return yield* buildResolvedConfigFromStored({
242
+ selectedName,
243
+ token,
244
+ encrypted,
245
+ });
246
+ });
247
+
248
+ return {
249
+ resolve,
250
+ resolveActiveEnvironmentName,
251
+ listEnvironments,
252
+ upsertEnvironment,
253
+ setDefaultEnvironment,
254
+ removeEnvironment,
255
+ hasEnvironment,
256
+ getDefaultEnvironmentName,
257
+ } as const;
258
+ });
259
+
260
+ export const layer = Layer.effect(T3Config, make());
@@ -0,0 +1,40 @@
1
+ import { createCipheriv, createDecipheriv } from "node:crypto";
2
+
3
+ import * as Effect from "effect/Effect";
4
+ import * as Layer from "effect/Layer";
5
+
6
+ import { credentialCipherTagByteLength, T3CredentialCipher } from "./cipher.ts";
7
+ import { CredentialCipherError } from "./error.ts";
8
+
9
+ const make = (): T3CredentialCipher["Service"] => ({
10
+ encrypt: (input) =>
11
+ Effect.try({
12
+ try: () => {
13
+ const cipher = createCipheriv("aes-256-gcm", input.key, input.nonce, {
14
+ authTagLength: credentialCipherTagByteLength,
15
+ });
16
+ cipher.setAAD(input.additionalData);
17
+ const ciphertext = Buffer.concat([cipher.update(input.plaintext), cipher.final()]);
18
+ return {
19
+ ciphertext: new Uint8Array(ciphertext),
20
+ tag: new Uint8Array(cipher.getAuthTag()),
21
+ };
22
+ },
23
+ catch: (cause) => new CredentialCipherError({ operation: "encrypt", cause }),
24
+ }),
25
+ decrypt: (input) =>
26
+ Effect.try({
27
+ try: () => {
28
+ const decipher = createDecipheriv("aes-256-gcm", input.key, input.nonce, {
29
+ authTagLength: credentialCipherTagByteLength,
30
+ });
31
+ decipher.setAAD(input.additionalData);
32
+ decipher.setAuthTag(input.tag);
33
+ const plaintext = Buffer.concat([decipher.update(input.ciphertext), decipher.final()]);
34
+ return new Uint8Array(plaintext);
35
+ },
36
+ catch: (cause) => new CredentialCipherError({ operation: "decrypt", cause }),
37
+ }),
38
+ });
39
+
40
+ export const layerNode = Layer.succeed(T3CredentialCipher, make());