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.
- package/README.md +42 -10
- package/dist/application.js +2 -2
- package/dist/auth.js +1 -1
- package/dist/bin.js +85526 -2662
- package/dist/cli.js +15 -2
- package/dist/config.js +120 -2
- package/dist/connection.js +2 -2
- package/dist/index.js +1 -1
- package/dist/node.js +6 -2
- package/dist/orchestration.js +2 -2
- package/dist/rpc.js +1 -1
- package/dist/runtime.js +2 -2
- package/dist/shared.js +42956 -38119
- package/dist/src/application/actions.d.ts +25 -0
- package/dist/src/application/index.d.ts +3 -3
- package/dist/src/application/layer.d.ts +51 -35
- package/dist/src/application/model-selection.d.ts +2 -2
- package/dist/src/application/models.d.ts +1 -1
- package/dist/src/application/project-commands.d.ts +22 -2
- package/dist/src/application/projects.d.ts +7 -7
- package/dist/src/application/service.d.ts +65 -2
- package/dist/src/application/shell-sequence.d.ts +11 -0
- package/dist/src/application/terminals.d.ts +2 -2
- package/dist/src/application/thread-commands.d.ts +1 -1
- package/dist/src/application/thread-wait.d.ts +9 -0
- package/dist/src/application/threads.d.ts +56 -5
- package/dist/src/auth/error.d.ts +2 -1
- package/dist/src/auth/index.d.ts +1 -1
- package/dist/src/auth/layer.d.ts +34 -6
- package/dist/src/auth/local-base-dir.d.ts +5 -2
- package/dist/src/auth/local-origin.d.ts +3 -3
- package/dist/src/auth/local-token.d.ts +3 -3
- package/dist/src/auth/service.d.ts +15 -3
- package/dist/src/auth/type.d.ts +40 -1
- package/dist/src/cli/env/flag.d.ts +2 -0
- package/dist/src/cli/env/index.d.ts +2 -0
- package/dist/src/cli/env/selection-layer.d.ts +3 -0
- package/dist/src/cli/flags.d.ts +2 -0
- package/dist/src/cli/format/index.d.ts +1 -0
- package/dist/src/cli/format/output.d.ts +12 -0
- package/dist/src/cli/index.d.ts +4 -0
- package/dist/src/cli/runtime/index.d.ts +1 -0
- package/dist/src/cli/runtime/service.d.ts +16 -0
- package/dist/src/{scope → cli/scope}/resolve.d.ts +5 -4
- package/dist/src/config/config.d.ts +49 -0
- package/dist/src/config/credential/cipher-node.d.ts +3 -0
- package/dist/src/config/credential/cipher-web.d.ts +3 -0
- package/dist/src/config/credential/cipher.d.ts +29 -0
- package/dist/src/config/credential/env.d.ts +3 -0
- package/dist/src/config/credential/error.d.ts +8 -0
- package/dist/src/config/credential/index.d.ts +6 -0
- package/dist/src/config/credential/service.d.ts +34 -0
- package/dist/src/config/env/env.d.ts +55 -0
- package/dist/src/config/env/index.d.ts +2 -0
- package/dist/src/{layout/base-dir.d.ts → config/env/layout.d.ts} +0 -1
- package/dist/src/config/environment-name/index.d.ts +1 -0
- package/dist/src/config/environment-name/name.d.ts +10 -0
- package/dist/src/config/error.d.ts +4 -11
- package/dist/src/config/index.d.ts +10 -5
- package/dist/src/config/keystore/error.d.ts +8 -0
- package/dist/src/config/keystore/file.d.ts +9 -0
- package/dist/src/config/keystore/index.d.ts +4 -0
- package/dist/src/config/keystore/keyring-node.d.ts +4 -0
- package/dist/src/config/keystore/service.d.ts +33 -0
- package/dist/src/config/paths/index.d.ts +1 -0
- package/dist/src/config/paths/paths.d.ts +6 -0
- package/dist/src/config/persist/file-mode.d.ts +4 -0
- package/dist/src/config/persist/migration.d.ts +68 -0
- package/dist/src/config/persist/persist.d.ts +40 -0
- package/dist/src/config/persist/schema.d.ts +68 -0
- package/dist/src/config/resolve/resolve.d.ts +40 -0
- package/dist/src/config/selection/index.d.ts +1 -0
- package/dist/src/config/selection/resolve.d.ts +4 -0
- package/dist/src/config/selection/service.d.ts +10 -0
- package/dist/src/config/types.d.ts +36 -0
- package/dist/src/config/url/error.d.ts +10 -0
- package/dist/src/config/url/index.d.ts +2 -0
- package/dist/src/connection/index.d.ts +0 -1
- package/dist/src/contracts/index.d.ts +1 -1
- package/dist/src/domain/error.d.ts +14 -1
- package/dist/src/domain/helpers.d.ts +16 -1
- package/dist/src/domain/model-config.d.ts +4 -1
- package/dist/src/domain/thread-activities.d.ts +1 -1
- package/dist/src/domain/thread-lifecycle.d.ts +10 -1
- package/dist/src/index.d.ts +1 -2
- package/dist/src/{connection/node.d.ts → node/connection.d.ts} +1 -1
- package/dist/src/node/index.d.ts +1 -2
- package/dist/src/orchestration/index.d.ts +0 -1
- package/dist/src/orchestration/layer.d.ts +153 -7
- package/dist/src/orchestration/service.d.ts +1 -1
- package/dist/src/rpc/error.d.ts +2 -2
- package/dist/src/rpc/index.d.ts +2 -3
- package/dist/src/rpc/layer.d.ts +574 -46
- package/dist/src/rpc/operation.d.ts +574 -46
- package/dist/src/rpc/ws-group.d.ts +184 -19
- package/dist/src/runtime/index.d.ts +1 -2
- package/dist/src/runtime/layer.d.ts +12 -8
- package/dist/src/t3tools/index.d.ts +1 -1
- package/dist/t3tools.js +2 -2
- package/package.json +25 -21
- package/src/application/actions.test.ts +328 -0
- package/src/application/actions.ts +475 -0
- package/src/application/index.ts +9 -5
- package/src/application/layer.ts +9 -0
- package/src/application/model-selection.ts +2 -2
- package/src/application/project-commands.ts +23 -5
- package/src/application/projects.ts +6 -7
- package/src/application/service.ts +79 -1
- package/src/application/shell-sequence.ts +1 -1
- package/src/application/terminals.ts +2 -1
- package/src/application/thread-commands.ts +1 -1
- package/src/application/thread-update.ts +1 -1
- package/src/application/thread-wait.ts +1 -1
- package/src/application/threads.test.ts +9 -3
- package/src/application/threads.ts +6 -6
- package/src/auth/error.ts +2 -1
- package/src/auth/index.ts +7 -0
- package/src/auth/layer.test-utils.ts +34 -0
- package/src/auth/layer.ts +116 -34
- package/src/auth/local-base-dir.ts +13 -6
- package/src/auth/local-origin.ts +10 -7
- package/src/auth/local-token.ts +28 -23
- package/src/auth/service.test.ts +200 -0
- package/src/auth/service.ts +27 -3
- package/src/auth/transport.ts +2 -2
- package/src/auth/type.ts +47 -1
- package/src/bin.ts +24 -6
- package/src/cli/action-format.ts +110 -0
- package/src/cli/action.ts +398 -0
- package/src/cli/app.ts +6 -0
- package/src/cli/auth.ts +76 -23
- package/src/cli/env/flag.ts +8 -0
- package/src/cli/env/index.ts +2 -0
- package/src/cli/env/selection-layer.test.ts +49 -0
- package/src/cli/env/selection-layer.ts +27 -0
- package/src/cli/env.ts +107 -0
- package/src/cli/extra-args.test.ts +32 -0
- package/src/cli/extra-args.ts +22 -0
- package/src/cli/flags.ts +11 -1
- package/src/cli/format/auth.ts +92 -0
- package/src/cli/format/human.ts +131 -0
- package/src/cli/format/index.ts +12 -0
- package/src/cli/format/model.ts +29 -0
- package/src/cli/format/output.ts +51 -0
- package/src/cli/format/project.ts +32 -0
- package/src/cli/format/terminal.ts +87 -0
- package/src/cli/{thread-format.test.ts → format/thread.test.ts} +6 -4
- package/src/cli/format/thread.ts +185 -0
- package/src/cli/index.ts +20 -0
- package/src/cli/interaction/confirm.ts +64 -0
- package/src/cli/{self-action.ts → interaction/self-action.ts} +8 -6
- package/src/cli/message-input.ts +1 -1
- package/src/cli/model.ts +9 -5
- package/src/cli/project.ts +13 -7
- package/src/cli/projects/delete.ts +13 -12
- package/src/cli/require.ts +9 -7
- package/src/cli/runtime/index.ts +1 -0
- package/src/cli/runtime/service.ts +28 -0
- package/src/{scope → cli/scope}/resolve.ts +11 -9
- package/src/cli/terminal/attach.ts +3 -6
- package/src/cli/terminal/create.ts +10 -9
- package/src/cli/terminal/destroy.ts +13 -11
- package/src/cli/terminal/list.ts +10 -9
- package/src/cli/terminal/read.test-utils.ts +48 -0
- package/src/cli/terminal/read.test.ts +35 -0
- package/src/cli/terminal/read.ts +3 -6
- package/src/cli/terminal/scope.ts +10 -5
- package/src/cli/terminal/shared.ts +1 -1
- package/src/cli/terminal/stream.ts +3 -6
- package/src/cli/terminal/wait.test.ts +5 -3
- package/src/cli/terminal/wait.ts +10 -9
- package/src/cli/terminal/write.test.ts +34 -0
- package/src/cli/terminal/write.ts +10 -9
- package/src/cli/threads/approve.ts +11 -7
- package/src/cli/threads/archive.ts +14 -9
- package/src/cli/threads/callback.ts +6 -4
- package/src/cli/threads/delete.ts +17 -11
- package/src/cli/threads/interrupt.ts +14 -9
- package/src/cli/threads/list.test.ts +5 -3
- package/src/cli/threads/list.ts +10 -10
- package/src/cli/threads/messages.ts +11 -7
- package/src/cli/threads/respond.ts +11 -7
- package/src/cli/threads/send.ts +19 -9
- package/src/cli/threads/show.ts +11 -7
- package/src/cli/threads/start.ts +18 -13
- package/src/cli/threads/unarchive.ts +11 -7
- package/src/cli/threads/update.ts +14 -9
- package/src/cli/threads/wait.ts +11 -7
- package/src/cli/wait-events.ts +1 -1
- package/src/config/config.ts +260 -0
- package/src/config/credential/cipher-node.ts +40 -0
- package/src/config/credential/cipher-web.ts +82 -0
- package/src/config/credential/cipher.ts +39 -0
- package/src/config/credential/env.ts +13 -0
- package/src/config/credential/error.ts +9 -0
- package/src/config/credential/index.ts +6 -0
- package/src/config/credential/service.test-utils.ts +25 -0
- package/src/config/credential/service.test.ts +116 -0
- package/src/config/credential/service.ts +205 -0
- package/src/config/env/env.test-utils.ts +14 -0
- package/src/config/env/env.ts +81 -0
- package/src/config/env/index.ts +2 -0
- package/src/{layout/base-dir.ts → config/env/layout.ts} +0 -9
- package/src/config/environment-name/index.ts +7 -0
- package/src/config/environment-name/name.test.ts +66 -0
- package/src/config/environment-name/name.ts +49 -0
- package/src/config/error.ts +6 -8
- package/src/config/index.ts +16 -5
- package/src/config/keystore/error.ts +9 -0
- package/src/config/keystore/file.ts +96 -0
- package/src/config/keystore/index.ts +4 -0
- package/src/config/keystore/keyring-node.test.ts +12 -0
- package/src/config/keystore/keyring-node.ts +100 -0
- package/src/config/keystore/service.test-utils.ts +15 -0
- package/src/config/keystore/service.test.ts +18 -0
- package/src/config/keystore/service.ts +29 -0
- package/src/config/layer.test-utils.ts +45 -0
- package/src/config/layer.test.ts +209 -0
- package/src/config/paths/index.ts +1 -0
- package/src/config/paths/paths.ts +36 -0
- package/src/config/persist/file-mode.ts +21 -0
- package/src/config/persist/migration.test.ts +71 -0
- package/src/config/persist/migration.ts +82 -0
- package/src/config/persist/persist.test.ts +113 -0
- package/src/config/persist/persist.ts +65 -0
- package/src/config/persist/schema.ts +37 -0
- package/src/config/platform.test-utils.ts +20 -0
- package/src/config/resolve/resolve.test-utils.ts +20 -0
- package/src/config/resolve/resolve.test.ts +137 -0
- package/src/config/resolve/resolve.ts +104 -0
- package/src/config/selection/index.ts +1 -0
- package/src/config/selection/resolve.ts +14 -0
- package/src/config/selection/service.ts +29 -0
- package/src/config/temp-home.test-utils.ts +7 -0
- package/src/config/types.ts +49 -0
- package/src/config/url/error.ts +8 -0
- package/src/config/url/index.ts +7 -0
- package/src/config/url/url.test.ts +31 -0
- package/src/connection/index.ts +0 -1
- package/src/contracts/index.ts +1 -1
- package/src/domain/error.ts +20 -1
- package/src/domain/helpers.test.ts +1 -1
- package/src/domain/helpers.ts +1 -1
- package/src/domain/model-config.ts +1 -1
- package/src/domain/thread-activities.test.ts +1 -1
- package/src/domain/thread-activities.ts +1 -1
- package/src/domain/thread-lifecycle.test.ts +1 -1
- package/src/domain/thread-lifecycle.ts +1 -1
- package/src/effect.test-utils.ts +25 -0
- package/src/index.ts +1 -1
- package/src/{connection/node.ts → node/connection.ts} +1 -1
- package/src/node/index.ts +1 -2
- package/src/orchestration/index.ts +0 -1
- package/src/orchestration/layer.ts +1 -1
- package/src/orchestration/service.ts +1 -1
- package/src/rpc/error.ts +2 -2
- package/src/rpc/index.ts +2 -3
- package/src/rpc/layer.ts +1 -1
- package/src/rpc/ws-group.ts +1 -1
- package/src/runtime/index.ts +2 -1
- package/src/runtime/layer.test-utils.ts +32 -0
- package/src/runtime/layer.test.ts +66 -0
- package/src/runtime/layer.ts +15 -9
- package/src/t3tools/index.ts +1 -1
- package/src/types/marked-terminal.d.ts +11 -0
- package/dist/layout.js +0 -2
- package/dist/scope.js +0 -2
- package/dist/src/cli/output-format.d.ts +0 -11
- package/dist/src/config/layer.d.ts +0 -22
- package/dist/src/config/service.d.ts +0 -22
- package/dist/src/environment/layer.d.ts +0 -3
- package/dist/src/environment/service.d.ts +0 -12
- package/dist/src/layout/index.d.ts +0 -1
- package/dist/upstream-t3code/packages/contracts/src/auth.d.ts +0 -441
- package/dist/upstream-t3code/packages/contracts/src/baseSchemas.d.ts +0 -38
- package/dist/upstream-t3code/packages/contracts/src/desktopBootstrap.d.ts +0 -14
- package/dist/upstream-t3code/packages/contracts/src/editor.d.ts +0 -124
- package/dist/upstream-t3code/packages/contracts/src/environment.d.ts +0 -64
- package/dist/upstream-t3code/packages/contracts/src/environmentHttp.d.ts +0 -762
- package/dist/upstream-t3code/packages/contracts/src/filesystem.d.ts +0 -26
- package/dist/upstream-t3code/packages/contracts/src/git.d.ts +0 -500
- package/dist/upstream-t3code/packages/contracts/src/index.d.ts +0 -25
- package/dist/upstream-t3code/packages/contracts/src/ipc.d.ts +0 -490
- package/dist/upstream-t3code/packages/contracts/src/keybindings.d.ts +0 -133
- package/dist/upstream-t3code/packages/contracts/src/model.d.ts +0 -112
- package/dist/upstream-t3code/packages/contracts/src/orchestration.d.ts +0 -6682
- package/dist/upstream-t3code/packages/contracts/src/project.d.ts +0 -45
- package/dist/upstream-t3code/packages/contracts/src/provider.d.ts +0 -116
- package/dist/upstream-t3code/packages/contracts/src/providerInstance.d.ts +0 -99
- package/dist/upstream-t3code/packages/contracts/src/providerRuntime.d.ts +0 -4276
- package/dist/upstream-t3code/packages/contracts/src/relay.d.ts +0 -1262
- package/dist/upstream-t3code/packages/contracts/src/relayClient.d.ts +0 -48
- package/dist/upstream-t3code/packages/contracts/src/remoteAccess.d.ts +0 -45
- package/dist/upstream-t3code/packages/contracts/src/review.d.ts +0 -37
- package/dist/upstream-t3code/packages/contracts/src/rpc.d.ts +0 -8218
- package/dist/upstream-t3code/packages/contracts/src/server.d.ts +0 -2291
- package/dist/upstream-t3code/packages/contracts/src/settings.d.ts +0 -271
- package/dist/upstream-t3code/packages/contracts/src/sourceControl.d.ts +0 -177
- package/dist/upstream-t3code/packages/contracts/src/terminal.d.ts +0 -330
- package/dist/upstream-t3code/packages/contracts/src/vcs.d.ts +0 -148
- package/src/cli/auth-format.ts +0 -45
- package/src/cli/confirm.ts +0 -31
- package/src/cli/model-format.ts +0 -18
- package/src/cli/output-format.ts +0 -45
- package/src/cli/project-format.ts +0 -18
- package/src/cli/terminal/commands.test.ts +0 -101
- package/src/cli/terminal-format.ts +0 -167
- package/src/cli/thread-format.ts +0 -128
- package/src/config/layer.ts +0 -105
- package/src/config/service.ts +0 -26
- package/src/environment/layer.ts +0 -12
- package/src/environment/service.ts +0 -13
- package/src/layout/index.ts +0 -1
- /package/dist/src/{scope → cli/scope}/index.d.ts +0 -0
- /package/dist/src/config/{url.d.ts → url/url.d.ts} +0 -0
- /package/src/{scope → cli/scope}/index.ts +0 -0
- /package/src/config/{url.ts → url/url.ts} +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import "vite-plus/test/config";
|
|
2
|
+
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Exit from "effect/Exit";
|
|
5
|
+
import * as FileSystem from "effect/FileSystem";
|
|
6
|
+
import * as Path from "effect/Path";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
import { assert, describe, it } from "@effect/vitest";
|
|
9
|
+
|
|
10
|
+
import { T3Auth } from "./service.ts";
|
|
11
|
+
import { StoredConfigV2FileJson } from "../config/persist/schema.ts";
|
|
12
|
+
import { ConfigPlatformLayer } from "../config/platform.test-utils.ts";
|
|
13
|
+
import { makeTempHomeScoped } from "../config/temp-home.test-utils.ts";
|
|
14
|
+
import { t3AuthDepsLayer } from "./layer.test-utils.ts";
|
|
15
|
+
|
|
16
|
+
describe("T3Auth persistence", () => {
|
|
17
|
+
it.effect("fails to persist a duplicate environment without allowReplace", () =>
|
|
18
|
+
Effect.gen(function* () {
|
|
19
|
+
return yield* makeTempHomeScoped("t3cli-auth-");
|
|
20
|
+
}).pipe(
|
|
21
|
+
Effect.flatMap((homeDir) =>
|
|
22
|
+
Effect.gen(function* () {
|
|
23
|
+
const auth = yield* T3Auth;
|
|
24
|
+
yield* auth.persistEnvironment({
|
|
25
|
+
name: "work",
|
|
26
|
+
url: "https://work.example",
|
|
27
|
+
token: "work-token",
|
|
28
|
+
local: false,
|
|
29
|
+
allowReplace: true,
|
|
30
|
+
});
|
|
31
|
+
const result = yield* auth
|
|
32
|
+
.persistEnvironment({
|
|
33
|
+
name: "work",
|
|
34
|
+
url: "https://work.example",
|
|
35
|
+
token: "work-token-2",
|
|
36
|
+
local: false,
|
|
37
|
+
allowReplace: false,
|
|
38
|
+
})
|
|
39
|
+
.pipe(Effect.exit);
|
|
40
|
+
assert.equal(Exit.isFailure(result), true);
|
|
41
|
+
}).pipe(Effect.provide(t3AuthDepsLayer(homeDir))),
|
|
42
|
+
),
|
|
43
|
+
Effect.provide(ConfigPlatformLayer),
|
|
44
|
+
Effect.scoped,
|
|
45
|
+
),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
it.effect("does not change default when replace is used for a new environment", () =>
|
|
49
|
+
Effect.gen(function* () {
|
|
50
|
+
return yield* makeTempHomeScoped("t3cli-auth-");
|
|
51
|
+
}).pipe(
|
|
52
|
+
Effect.flatMap((homeDir) =>
|
|
53
|
+
Effect.gen(function* () {
|
|
54
|
+
const auth = yield* T3Auth;
|
|
55
|
+
yield* auth.persistEnvironment({
|
|
56
|
+
name: "home",
|
|
57
|
+
url: "https://home.example",
|
|
58
|
+
token: "home-token",
|
|
59
|
+
local: false,
|
|
60
|
+
allowReplace: true,
|
|
61
|
+
});
|
|
62
|
+
yield* auth.persistEnvironment({
|
|
63
|
+
name: "work",
|
|
64
|
+
url: "https://work.example",
|
|
65
|
+
token: "work-token",
|
|
66
|
+
local: false,
|
|
67
|
+
replace: true,
|
|
68
|
+
allowReplace: true,
|
|
69
|
+
});
|
|
70
|
+
const listed = yield* auth.listEnvironments();
|
|
71
|
+
assert.equal(listed.find((environment) => environment.name === "home")?.default, true);
|
|
72
|
+
assert.equal(listed.find((environment) => environment.name === "work")?.default, false);
|
|
73
|
+
}).pipe(Effect.provide(t3AuthDepsLayer(homeDir))),
|
|
74
|
+
),
|
|
75
|
+
Effect.provide(ConfigPlatformLayer),
|
|
76
|
+
Effect.scoped,
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
it.effect("promotes default when replacing an existing environment with replace", () =>
|
|
81
|
+
Effect.gen(function* () {
|
|
82
|
+
return yield* makeTempHomeScoped("t3cli-auth-");
|
|
83
|
+
}).pipe(
|
|
84
|
+
Effect.flatMap((homeDir) =>
|
|
85
|
+
Effect.gen(function* () {
|
|
86
|
+
const auth = yield* T3Auth;
|
|
87
|
+
yield* auth.persistEnvironment({
|
|
88
|
+
name: "home",
|
|
89
|
+
url: "https://home.example",
|
|
90
|
+
token: "home-token",
|
|
91
|
+
local: false,
|
|
92
|
+
allowReplace: true,
|
|
93
|
+
});
|
|
94
|
+
yield* auth.persistEnvironment({
|
|
95
|
+
name: "work",
|
|
96
|
+
url: "https://work.example",
|
|
97
|
+
token: "work-token",
|
|
98
|
+
local: false,
|
|
99
|
+
allowReplace: true,
|
|
100
|
+
});
|
|
101
|
+
yield* auth.persistEnvironment({
|
|
102
|
+
name: "work",
|
|
103
|
+
url: "https://work.example",
|
|
104
|
+
token: "work-token-2",
|
|
105
|
+
local: false,
|
|
106
|
+
replace: true,
|
|
107
|
+
allowReplace: true,
|
|
108
|
+
});
|
|
109
|
+
const listed = yield* auth.listEnvironments();
|
|
110
|
+
assert.equal(listed.find((environment) => environment.name === "work")?.default, true);
|
|
111
|
+
}).pipe(Effect.provide(t3AuthDepsLayer(homeDir))),
|
|
112
|
+
),
|
|
113
|
+
Effect.provide(ConfigPlatformLayer),
|
|
114
|
+
Effect.scoped,
|
|
115
|
+
),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
it.effect("lists environments without decrypting tokens", () =>
|
|
119
|
+
Effect.gen(function* () {
|
|
120
|
+
return yield* makeTempHomeScoped("t3cli-auth-");
|
|
121
|
+
}).pipe(
|
|
122
|
+
Effect.flatMap((homeDir) =>
|
|
123
|
+
Effect.gen(function* () {
|
|
124
|
+
const fs = yield* FileSystem.FileSystem;
|
|
125
|
+
const path = yield* Path.Path;
|
|
126
|
+
const configPath = path.join(homeDir, ".config", "t3cli", "config.json");
|
|
127
|
+
|
|
128
|
+
yield* Effect.gen(function* () {
|
|
129
|
+
const auth = yield* T3Auth;
|
|
130
|
+
yield* auth.persistEnvironment({
|
|
131
|
+
name: "home",
|
|
132
|
+
url: "https://home.example",
|
|
133
|
+
token: "home-token",
|
|
134
|
+
local: false,
|
|
135
|
+
allowReplace: true,
|
|
136
|
+
});
|
|
137
|
+
yield* auth.persistEnvironment({
|
|
138
|
+
name: "work",
|
|
139
|
+
url: "https://work.example",
|
|
140
|
+
token: "work-token",
|
|
141
|
+
local: false,
|
|
142
|
+
allowReplace: true,
|
|
143
|
+
});
|
|
144
|
+
}).pipe(Effect.provide(t3AuthDepsLayer(homeDir)));
|
|
145
|
+
|
|
146
|
+
const raw = yield* fs.readFileString(configPath);
|
|
147
|
+
const parsed = yield* Schema.decodeUnknownEffect(StoredConfigV2FileJson)(raw);
|
|
148
|
+
const homeEnvironment = parsed.environments.home;
|
|
149
|
+
assert.isDefined(homeEnvironment);
|
|
150
|
+
const corrupted = yield* Schema.encodeEffect(StoredConfigV2FileJson)({
|
|
151
|
+
...parsed,
|
|
152
|
+
environments: {
|
|
153
|
+
...parsed.environments,
|
|
154
|
+
home: {
|
|
155
|
+
...homeEnvironment,
|
|
156
|
+
token: {
|
|
157
|
+
...homeEnvironment.token,
|
|
158
|
+
tag: "AAAAAAAAAAAAAAAAAAAAAA==",
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
yield* fs.writeFileString(configPath, `${corrupted}\n`, { mode: 0o600 });
|
|
164
|
+
|
|
165
|
+
yield* Effect.gen(function* () {
|
|
166
|
+
const auth = yield* T3Auth;
|
|
167
|
+
const listed = yield* auth.listEnvironments();
|
|
168
|
+
assert.equal(listed.length, 2);
|
|
169
|
+
assert.equal(listed.find((environment) => environment.name === "home")?.active, true);
|
|
170
|
+
}).pipe(Effect.provide(t3AuthDepsLayer(homeDir)));
|
|
171
|
+
}),
|
|
172
|
+
),
|
|
173
|
+
Effect.provide(ConfigPlatformLayer),
|
|
174
|
+
Effect.scoped,
|
|
175
|
+
),
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
it.effect("resolves unpair target from encrypted default metadata", () =>
|
|
179
|
+
Effect.gen(function* () {
|
|
180
|
+
return yield* makeTempHomeScoped("t3cli-auth-");
|
|
181
|
+
}).pipe(
|
|
182
|
+
Effect.flatMap((homeDir) =>
|
|
183
|
+
Effect.gen(function* () {
|
|
184
|
+
const auth = yield* T3Auth;
|
|
185
|
+
yield* auth.persistEnvironment({
|
|
186
|
+
name: "home",
|
|
187
|
+
url: "https://home.example",
|
|
188
|
+
token: "home-token",
|
|
189
|
+
local: false,
|
|
190
|
+
allowReplace: true,
|
|
191
|
+
});
|
|
192
|
+
const target = yield* auth.resolveUnpairTarget({});
|
|
193
|
+
assert.equal(target, "home");
|
|
194
|
+
}).pipe(Effect.provide(t3AuthDepsLayer(homeDir))),
|
|
195
|
+
),
|
|
196
|
+
Effect.provide(ConfigPlatformLayer),
|
|
197
|
+
Effect.scoped,
|
|
198
|
+
),
|
|
199
|
+
);
|
|
200
|
+
});
|
package/src/auth/service.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
2
|
import type * as Effect from "effect/Effect";
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { AuthWebSocketTicketResult } from "./schema.ts";
|
|
5
5
|
import type { AuthError } from "./error.ts";
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
AuthConfigInput,
|
|
8
|
+
AuthEnvironmentListItem,
|
|
9
|
+
AuthStatusResult,
|
|
10
|
+
AuthUnpairResult,
|
|
11
|
+
AuthUseResult,
|
|
12
|
+
LocalAuthInput,
|
|
13
|
+
LocalAuthResult,
|
|
14
|
+
PairResult,
|
|
15
|
+
PersistEnvironmentInput,
|
|
16
|
+
} from "./type.ts";
|
|
7
17
|
|
|
8
18
|
export class T3Auth extends Context.Service<
|
|
9
19
|
T3Auth,
|
|
@@ -11,7 +21,21 @@ export class T3Auth extends Context.Service<
|
|
|
11
21
|
readonly pair: (value: string) => Effect.Effect<PairResult, AuthError>;
|
|
12
22
|
readonly local: (input: LocalAuthInput) => Effect.Effect<LocalAuthResult, AuthError>;
|
|
13
23
|
readonly writeConfig: (input: AuthConfigInput) => Effect.Effect<void, AuthError>;
|
|
14
|
-
readonly
|
|
24
|
+
readonly persistEnvironment: (
|
|
25
|
+
input: PersistEnvironmentInput,
|
|
26
|
+
) => Effect.Effect<string, AuthError>;
|
|
27
|
+
readonly environmentExists: (name: string) => Effect.Effect<boolean, AuthError>;
|
|
28
|
+
readonly defaultNameFromUrl: (url: string) => Effect.Effect<string, AuthError>;
|
|
29
|
+
readonly defaultNameForLocal: () => Effect.Effect<string, AuthError>;
|
|
30
|
+
readonly listEnvironments: () => Effect.Effect<readonly AuthEnvironmentListItem[], AuthError>;
|
|
31
|
+
readonly useEnvironment: (name: string) => Effect.Effect<AuthUseResult, AuthError>;
|
|
32
|
+
readonly unpairEnvironment: (input: {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
}) => Effect.Effect<AuthUnpairResult, AuthError>;
|
|
35
|
+
readonly resolveUnpairTarget: (input: {
|
|
36
|
+
readonly name?: string;
|
|
37
|
+
}) => Effect.Effect<string, AuthError>;
|
|
38
|
+
readonly status: () => Effect.Effect<AuthStatusResult, AuthError>;
|
|
15
39
|
readonly issueWebSocketTicket: () => Effect.Effect<AuthWebSocketTicketResult, AuthError>;
|
|
16
40
|
}
|
|
17
41
|
>()("t3cli/T3Auth") {}
|
package/src/auth/transport.ts
CHANGED
|
@@ -2,14 +2,14 @@ import {
|
|
|
2
2
|
AuthAccessTokenType,
|
|
3
3
|
AuthEnvironmentBootstrapTokenType,
|
|
4
4
|
AuthTokenExchangeGrantType,
|
|
5
|
-
} from "
|
|
5
|
+
} from "@t3tools/contracts";
|
|
6
6
|
import * as Context from "effect/Context";
|
|
7
7
|
import * as DateTime from "effect/DateTime";
|
|
8
8
|
import * as Effect from "effect/Effect";
|
|
9
9
|
import * as Layer from "effect/Layer";
|
|
10
10
|
import { HttpClient, HttpClientError, HttpClientRequest } from "effect/unstable/http";
|
|
11
11
|
|
|
12
|
-
import { toHttpEndpointUrl } from "../config/url.ts";
|
|
12
|
+
import { toHttpEndpointUrl } from "../config/url/url.ts";
|
|
13
13
|
import { AuthTransportError } from "./error.ts";
|
|
14
14
|
import {
|
|
15
15
|
type AuthBearerBootstrapResult,
|
package/src/auth/type.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AuthBearerBootstrapResult } from "./schema.ts";
|
|
2
|
+
import type { AuthSessionState } from "./schema.ts";
|
|
2
3
|
|
|
3
4
|
export type AuthSessionRole = AuthBearerBootstrapResult["role"];
|
|
4
5
|
|
|
@@ -8,9 +9,44 @@ export type PairingUrl = {
|
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
export type AuthConfigInput = {
|
|
12
|
+
readonly name: string;
|
|
11
13
|
readonly url: string;
|
|
12
14
|
readonly token: string;
|
|
13
|
-
readonly local
|
|
15
|
+
readonly local: boolean;
|
|
16
|
+
readonly makeDefault?: boolean;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type PersistEnvironmentInput = {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly url: string;
|
|
22
|
+
readonly token: string;
|
|
23
|
+
readonly local: boolean;
|
|
24
|
+
readonly replace?: boolean;
|
|
25
|
+
readonly allowReplace: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type AuthResolvedConfig = {
|
|
29
|
+
readonly url: string;
|
|
30
|
+
readonly token: string;
|
|
31
|
+
readonly source: "env" | "config";
|
|
32
|
+
readonly local: boolean;
|
|
33
|
+
readonly environment?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type AuthEnvironmentSummary = {
|
|
37
|
+
readonly name: string;
|
|
38
|
+
readonly url: string;
|
|
39
|
+
readonly local: boolean;
|
|
40
|
+
readonly default: boolean;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type AuthStatusResult = {
|
|
44
|
+
readonly config: AuthResolvedConfig;
|
|
45
|
+
readonly session: AuthSessionState;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type AuthEnvironmentListItem = AuthEnvironmentSummary & {
|
|
49
|
+
readonly active: boolean;
|
|
14
50
|
};
|
|
15
51
|
|
|
16
52
|
export type PairResult = {
|
|
@@ -51,3 +87,13 @@ export type LocalAuthResult = {
|
|
|
51
87
|
readonly source: "local";
|
|
52
88
|
readonly baseDir: string;
|
|
53
89
|
};
|
|
90
|
+
|
|
91
|
+
export type AuthUseResult = {
|
|
92
|
+
readonly name: string;
|
|
93
|
+
readonly default: true;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export type AuthUnpairResult = {
|
|
97
|
+
readonly name: string;
|
|
98
|
+
readonly removed: true;
|
|
99
|
+
};
|
package/src/bin.ts
CHANGED
|
@@ -1,31 +1,44 @@
|
|
|
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
|
|
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";
|
|
12
15
|
import { NodeTerminalIoLive } from "./cli/terminal/io-node-layer.ts";
|
|
13
16
|
import { T3Output } from "./cli/output/service.ts";
|
|
14
|
-
import {
|
|
17
|
+
import { BaseAppLayer } from "./runtime/layer.ts";
|
|
15
18
|
import { T3VersionBundledLive, T3VersionPackageJsonLive } from "./version/layer.ts";
|
|
16
19
|
import { T3Version } from "./version/service.ts";
|
|
17
20
|
|
|
18
21
|
declare const T3CLI_VERSION: string | undefined;
|
|
19
22
|
|
|
23
|
+
if (process.env.HOME === undefined || process.env.HOME.trim().length === 0) {
|
|
24
|
+
process.env.HOME = homedir();
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
const VersionLive =
|
|
21
28
|
typeof T3CLI_VERSION === "string" ? T3VersionBundledLive : T3VersionPackageJsonLive;
|
|
22
29
|
|
|
23
|
-
const PlatformLayer = Layer.mergeAll(NodeServices.layer,
|
|
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
|
+
);
|
|
24
37
|
|
|
25
38
|
const CliLayer = Layer.mergeAll(
|
|
26
|
-
|
|
39
|
+
CliAppLayer.pipe(Layer.provide(PlatformLayer)),
|
|
27
40
|
NodeServices.layer,
|
|
28
|
-
|
|
41
|
+
CliRuntime.layer,
|
|
29
42
|
T3InputLive.pipe(Layer.provide(NodeServices.layer)),
|
|
30
43
|
T3OutputLive.pipe(Layer.provide(NodeServices.layer)),
|
|
31
44
|
NodeTerminalIoLive,
|
|
@@ -36,6 +49,11 @@ const program = Effect.gen(function* () {
|
|
|
36
49
|
const version = yield* T3Version;
|
|
37
50
|
return yield* Command.run(createCliCommand(), { version: version.version });
|
|
38
51
|
}).pipe(
|
|
52
|
+
Effect.catchTag("ShowHelp", (error) =>
|
|
53
|
+
Effect.sync(() => {
|
|
54
|
+
process.exitCode = error.errors.length > 0 ? 1 : 0;
|
|
55
|
+
}),
|
|
56
|
+
),
|
|
39
57
|
Effect.tapError((error) =>
|
|
40
58
|
Effect.gen(function* () {
|
|
41
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
|
+
}
|