t3code-cli 0.11.0 → 0.13.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 +85549 -2668
- 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/rolldown-runtime.js +1 -1
- package/dist/rpc.js +1 -1
- package/dist/runtime.js +2 -2
- package/dist/shared.js +23313 -8022
- 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 +66 -50
- 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 +23 -3
- 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 +25 -19
- package/dist/src/application/terminals.d.ts +8 -8
- package/dist/src/application/thread-commands.d.ts +19 -19
- package/dist/src/application/thread-update.d.ts +1 -1
- package/dist/src/application/thread-wait.d.ts +19 -15
- package/dist/src/application/threads.d.ts +134 -108
- package/dist/src/auth/error.d.ts +3 -3
- package/dist/src/auth/index.d.ts +1 -1
- package/dist/src/auth/layer.d.ts +36 -8
- 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/remote-error.d.ts +3 -0
- 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/error.d.ts +3 -1
- package/dist/src/connection/index.d.ts +0 -1
- package/dist/src/connection/prepared.d.ts +14 -0
- 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 +53 -43
- package/dist/src/domain/model-config.d.ts +92 -84
- package/dist/src/domain/thread-activities.d.ts +1 -1
- package/dist/src/domain/thread-lifecycle.d.ts +24 -20
- 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 +321 -390
- package/dist/src/orchestration/service.d.ts +1 -1
- package/dist/src/rpc/error.d.ts +4 -6
- package/dist/src/rpc/layer.d.ts +2036 -1917
- package/dist/src/rpc/operation.d.ts +4 -5732
- package/dist/src/rpc/service.d.ts +1 -1
- package/dist/src/rpc/session.d.ts +22 -0
- package/dist/src/rpc/ws-group.d.ts +456 -1032
- package/dist/src/runtime/index.d.ts +1 -2
- package/dist/src/runtime/layer.d.ts +12 -8
- package/dist/src/sql/node-sqlite-client.d.ts +1 -1
- package/dist/src/t3tools/index.d.ts +1 -1
- package/dist/t3tools.js +2 -2
- package/package.json +30 -25
- 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 +5 -1
- package/src/application/threads.test.ts +9 -3
- package/src/application/threads.ts +6 -6
- package/src/auth/error.ts +4 -9
- 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/remote-error.ts +17 -0
- package/src/auth/service.test.ts +200 -0
- package/src/auth/service.ts +27 -3
- package/src/auth/transport.ts +45 -114
- 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/error.ts +4 -1
- package/src/connection/index.ts +0 -1
- package/src/connection/layer.ts +5 -2
- package/src/connection/prepared.ts +83 -0
- 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 +3 -2
- package/src/orchestration/service.ts +1 -1
- package/src/rpc/error.ts +10 -17
- package/src/rpc/layer.ts +17 -51
- package/src/rpc/operation.ts +16 -2
- package/src/rpc/service.ts +2 -1
- package/src/rpc/session.ts +168 -0
- package/src/rpc/ws-group.ts +13 -27
- 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 +21 -12
- 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,475 @@
|
|
|
1
|
+
import * as Crypto from "effect/Crypto";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Path from "effect/Path";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import {
|
|
6
|
+
MAX_SCRIPT_ID_LENGTH,
|
|
7
|
+
SCRIPT_RUN_COMMAND_PATTERN,
|
|
8
|
+
type OrchestrationProjectShell,
|
|
9
|
+
type OrchestrationShellSnapshot,
|
|
10
|
+
type ProjectScript,
|
|
11
|
+
} from "@t3tools/contracts";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
ProjectActionLookupError,
|
|
15
|
+
ProjectActionValidationError,
|
|
16
|
+
ProjectLookupError,
|
|
17
|
+
ThreadLookupError,
|
|
18
|
+
} from "../domain/error.ts";
|
|
19
|
+
import { findProjectById, resolveProjectScope } from "../domain/helpers.ts";
|
|
20
|
+
import { T3Orchestration } from "../orchestration/service.ts";
|
|
21
|
+
import { makeProjectMetaUpdateCommand } from "./project-commands.ts";
|
|
22
|
+
import { waitForShellSequence } from "./shell-sequence.ts";
|
|
23
|
+
import {
|
|
24
|
+
T3TerminalApplication,
|
|
25
|
+
type AddProjectActionInput,
|
|
26
|
+
type ProjectActionSelector,
|
|
27
|
+
type T3ActionApplicationService,
|
|
28
|
+
type UpdateProjectActionInput,
|
|
29
|
+
} from "./service.ts";
|
|
30
|
+
|
|
31
|
+
const DEFAULT_ACTION_ICON = "play";
|
|
32
|
+
const isScriptRunCommand = Schema.is(SCRIPT_RUN_COMMAND_PATTERN);
|
|
33
|
+
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
|
|
34
|
+
type MutablePartial<T> = { -readonly [K in keyof T]?: T[K] };
|
|
35
|
+
|
|
36
|
+
export const makeActionApplication = Effect.fn("makeActionApplication")(function* () {
|
|
37
|
+
const orchestration = yield* T3Orchestration;
|
|
38
|
+
const terminalApplication = yield* T3TerminalApplication;
|
|
39
|
+
const crypto = yield* Crypto.Crypto;
|
|
40
|
+
const path = yield* Path.Path;
|
|
41
|
+
|
|
42
|
+
const resolveProject = Effect.fn("T3ActionApplication.resolveProject")(function* (
|
|
43
|
+
snapshot: OrchestrationShellSnapshot,
|
|
44
|
+
projectRef: string,
|
|
45
|
+
) {
|
|
46
|
+
const scope = yield* resolveProjectScope(snapshot, { ref: projectRef }).pipe(
|
|
47
|
+
Effect.provideService(Path.Path, path),
|
|
48
|
+
);
|
|
49
|
+
if (scope === undefined) {
|
|
50
|
+
return yield* Effect.fail(
|
|
51
|
+
new ProjectLookupError({
|
|
52
|
+
message: `project not found: ${projectRef}`,
|
|
53
|
+
ref: projectRef,
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return scope.project;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const dispatchScriptsUpdate = Effect.fn("T3ActionApplication.dispatchScriptsUpdate")(function* (
|
|
61
|
+
projectId: string,
|
|
62
|
+
scripts: ReadonlyArray<ProjectScript>,
|
|
63
|
+
) {
|
|
64
|
+
const command = yield* makeProjectMetaUpdateCommand({
|
|
65
|
+
projectId,
|
|
66
|
+
scripts: [...scripts],
|
|
67
|
+
}).pipe(Effect.provideService(Crypto.Crypto, crypto));
|
|
68
|
+
const dispatch = yield* orchestration.dispatch(command);
|
|
69
|
+
const snapshot = yield* waitForShellSequence({ sequence: dispatch.sequence }).pipe(
|
|
70
|
+
Effect.provideService(T3Orchestration, orchestration),
|
|
71
|
+
);
|
|
72
|
+
const project = findProjectById(snapshot, projectId);
|
|
73
|
+
if (project === null) {
|
|
74
|
+
return yield* Effect.fail(
|
|
75
|
+
new ProjectLookupError({
|
|
76
|
+
message: `project not found after action update: ${projectId}`,
|
|
77
|
+
ref: projectId,
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return { dispatch, project };
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const listActions: T3ActionApplicationService["listActions"] = Effect.fn(
|
|
85
|
+
"T3ActionApplication.listActions",
|
|
86
|
+
)(function* (projectRef: string) {
|
|
87
|
+
const snapshot = yield* orchestration.getShellSnapshot();
|
|
88
|
+
const project = yield* resolveProject(snapshot, projectRef);
|
|
89
|
+
return { project, actions: project.scripts };
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const addAction: T3ActionApplicationService["addAction"] = Effect.fn(
|
|
93
|
+
"T3ActionApplication.addAction",
|
|
94
|
+
)(function* (input: AddProjectActionInput) {
|
|
95
|
+
const snapshot = yield* orchestration.getShellSnapshot();
|
|
96
|
+
const project = yield* resolveProject(snapshot, input.projectRef);
|
|
97
|
+
const name = yield* requireTrimmedNonEmpty(input.name, "action name", project.id);
|
|
98
|
+
const command = yield* requireTrimmedNonEmpty(input.command, "action command", project.id);
|
|
99
|
+
const id =
|
|
100
|
+
input.id !== undefined
|
|
101
|
+
? yield* requireProjectScriptId(input.id, project.id)
|
|
102
|
+
: nextProjectScriptId(
|
|
103
|
+
name,
|
|
104
|
+
project.scripts.map((script) => script.id),
|
|
105
|
+
);
|
|
106
|
+
yield* validateUnusedId(project, id);
|
|
107
|
+
const preview = yield* normalizePreviewInput({
|
|
108
|
+
projectId: project.id,
|
|
109
|
+
autoOpenPreview: input.autoOpenPreview ?? false,
|
|
110
|
+
...(input.previewUrl !== undefined ? { previewUrl: input.previewUrl } : {}),
|
|
111
|
+
});
|
|
112
|
+
const action: ProjectScript = {
|
|
113
|
+
id,
|
|
114
|
+
name,
|
|
115
|
+
command,
|
|
116
|
+
icon: input.icon ?? DEFAULT_ACTION_ICON,
|
|
117
|
+
runOnWorktreeCreate: input.setup === true,
|
|
118
|
+
...preview,
|
|
119
|
+
};
|
|
120
|
+
const nextScripts = enforceSingleSetup(
|
|
121
|
+
[...project.scripts, action],
|
|
122
|
+
action.runOnWorktreeCreate ? action.id : null,
|
|
123
|
+
);
|
|
124
|
+
const result = yield* dispatchScriptsUpdate(project.id, nextScripts);
|
|
125
|
+
const persisted = yield* resolveActionBySelectorEffect(
|
|
126
|
+
result.project.scripts,
|
|
127
|
+
{ id: action.id },
|
|
128
|
+
project.id,
|
|
129
|
+
);
|
|
130
|
+
return { ...result, action: persisted };
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const updateAction: T3ActionApplicationService["updateAction"] = Effect.fn(
|
|
134
|
+
"T3ActionApplication.updateAction",
|
|
135
|
+
)(function* (input: UpdateProjectActionInput) {
|
|
136
|
+
const snapshot = yield* orchestration.getShellSnapshot();
|
|
137
|
+
const project = yield* resolveProject(snapshot, input.projectRef);
|
|
138
|
+
const existing = yield* resolveActionBySelectorEffect(
|
|
139
|
+
project.scripts,
|
|
140
|
+
input.selector,
|
|
141
|
+
project.id,
|
|
142
|
+
);
|
|
143
|
+
const updated = yield* normalizeActionUpdate(project.id, existing, input);
|
|
144
|
+
const nextScripts = enforceSingleSetup(
|
|
145
|
+
project.scripts.map((script) => (script.id === existing.id ? updated : script)),
|
|
146
|
+
updated.runOnWorktreeCreate ? updated.id : null,
|
|
147
|
+
);
|
|
148
|
+
const result = yield* dispatchScriptsUpdate(project.id, nextScripts);
|
|
149
|
+
const persisted = yield* resolveActionBySelectorEffect(
|
|
150
|
+
result.project.scripts,
|
|
151
|
+
{ id: existing.id },
|
|
152
|
+
project.id,
|
|
153
|
+
);
|
|
154
|
+
return { ...result, action: persisted };
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const deleteAction: T3ActionApplicationService["deleteAction"] = Effect.fn(
|
|
158
|
+
"T3ActionApplication.deleteAction",
|
|
159
|
+
)(function* (input: { readonly projectRef: string; readonly selector: ProjectActionSelector }) {
|
|
160
|
+
const snapshot = yield* orchestration.getShellSnapshot();
|
|
161
|
+
const project = yield* resolveProject(snapshot, input.projectRef);
|
|
162
|
+
const action = yield* resolveActionBySelectorEffect(
|
|
163
|
+
project.scripts,
|
|
164
|
+
input.selector,
|
|
165
|
+
project.id,
|
|
166
|
+
);
|
|
167
|
+
const nextScripts = project.scripts.filter((script) => script.id !== action.id);
|
|
168
|
+
const result = yield* dispatchScriptsUpdate(project.id, nextScripts);
|
|
169
|
+
return { ...result, action };
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const runAction: T3ActionApplicationService["runAction"] = Effect.fn(
|
|
173
|
+
"T3ActionApplication.runAction",
|
|
174
|
+
)(function* (input: {
|
|
175
|
+
readonly threadId: string;
|
|
176
|
+
readonly selector: ProjectActionSelector;
|
|
177
|
+
readonly terminalId?: string;
|
|
178
|
+
}) {
|
|
179
|
+
const snapshot = yield* orchestration.getShellSnapshot();
|
|
180
|
+
const thread = snapshot.threads.find((candidate) => candidate.id === input.threadId);
|
|
181
|
+
if (thread === undefined) {
|
|
182
|
+
return yield* Effect.fail(
|
|
183
|
+
new ThreadLookupError({
|
|
184
|
+
message: `thread not found: ${input.threadId}`,
|
|
185
|
+
threadId: input.threadId,
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
const project = findProjectById(snapshot, thread.projectId);
|
|
190
|
+
if (project === null) {
|
|
191
|
+
return yield* Effect.fail(
|
|
192
|
+
new ProjectLookupError({
|
|
193
|
+
message: `project not found for thread: ${input.threadId}`,
|
|
194
|
+
ref: thread.projectId,
|
|
195
|
+
}),
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
const action = yield* resolveActionBySelectorEffect(
|
|
199
|
+
project.scripts,
|
|
200
|
+
input.selector,
|
|
201
|
+
project.id,
|
|
202
|
+
);
|
|
203
|
+
const env = {
|
|
204
|
+
T3CODE_PROJECT_ROOT: project.workspaceRoot,
|
|
205
|
+
...(thread.worktreePath !== null ? { T3CODE_WORKTREE_PATH: thread.worktreePath } : {}),
|
|
206
|
+
};
|
|
207
|
+
const terminal = yield* terminalApplication.createTerminal({
|
|
208
|
+
threadId: thread.id,
|
|
209
|
+
command: action.command,
|
|
210
|
+
env,
|
|
211
|
+
...(input.terminalId !== undefined ? { terminalId: input.terminalId } : {}),
|
|
212
|
+
});
|
|
213
|
+
return { project, action, terminal };
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
addAction,
|
|
218
|
+
deleteAction,
|
|
219
|
+
listActions,
|
|
220
|
+
runAction,
|
|
221
|
+
updateAction,
|
|
222
|
+
} satisfies T3ActionApplicationService;
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
export function nextProjectScriptId(name: string, existingIds: Iterable<string>): string {
|
|
226
|
+
const taken = new Set(Array.from(existingIds));
|
|
227
|
+
const baseId = normalizeScriptId(name);
|
|
228
|
+
if (!taken.has(baseId)) {
|
|
229
|
+
return baseId;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
let suffix = 2;
|
|
233
|
+
while (suffix < 10_000) {
|
|
234
|
+
const candidate = `${baseId}-${suffix}`;
|
|
235
|
+
const safeCandidate =
|
|
236
|
+
candidate.length <= MAX_SCRIPT_ID_LENGTH
|
|
237
|
+
? candidate
|
|
238
|
+
: `${baseId.slice(0, Math.max(1, MAX_SCRIPT_ID_LENGTH - String(suffix).length - 1))}-${suffix}`;
|
|
239
|
+
if (!taken.has(safeCandidate)) {
|
|
240
|
+
return safeCandidate;
|
|
241
|
+
}
|
|
242
|
+
suffix += 1;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return `${baseId}-${Date.now()}`.slice(0, MAX_SCRIPT_ID_LENGTH);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function resolveActionBySelector(
|
|
249
|
+
scripts: ReadonlyArray<ProjectScript>,
|
|
250
|
+
selector: ProjectActionSelector,
|
|
251
|
+
projectId: string,
|
|
252
|
+
): ProjectScript {
|
|
253
|
+
const result = resolveActionSelector(scripts, selector, projectId);
|
|
254
|
+
if ("action" in result) {
|
|
255
|
+
return result.action;
|
|
256
|
+
}
|
|
257
|
+
throw result.error;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function resolveActionBySelectorEffect(
|
|
261
|
+
scripts: ReadonlyArray<ProjectScript>,
|
|
262
|
+
selector: ProjectActionSelector,
|
|
263
|
+
projectId: string,
|
|
264
|
+
) {
|
|
265
|
+
const result = resolveActionSelector(scripts, selector, projectId);
|
|
266
|
+
if ("action" in result) {
|
|
267
|
+
return Effect.succeed(result.action);
|
|
268
|
+
}
|
|
269
|
+
return Effect.fail(result.error);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function resolveActionSelector(
|
|
273
|
+
scripts: ReadonlyArray<ProjectScript>,
|
|
274
|
+
selector: ProjectActionSelector,
|
|
275
|
+
projectId: string,
|
|
276
|
+
): { readonly action: ProjectScript } | { readonly error: ProjectActionLookupError } {
|
|
277
|
+
if (selector.id !== undefined) {
|
|
278
|
+
const id = selector.id.trim();
|
|
279
|
+
const match = scripts.find((script) => script.id === id);
|
|
280
|
+
if (match !== undefined) {
|
|
281
|
+
return { action: match };
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
error: new ProjectActionLookupError({
|
|
285
|
+
message: `action not found by id: ${id}`,
|
|
286
|
+
projectId,
|
|
287
|
+
selector: `id:${id}`,
|
|
288
|
+
}),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const normalized = selector.name.trim().toLowerCase();
|
|
293
|
+
const matches = scripts.filter((script) => script.name.trim().toLowerCase() === normalized);
|
|
294
|
+
if (matches.length === 1) {
|
|
295
|
+
return { action: matches[0]! };
|
|
296
|
+
}
|
|
297
|
+
if (matches.length === 0) {
|
|
298
|
+
return {
|
|
299
|
+
error: new ProjectActionLookupError({
|
|
300
|
+
message: `action not found by name: ${selector.name.trim()}`,
|
|
301
|
+
projectId,
|
|
302
|
+
selector: `name:${selector.name.trim()}`,
|
|
303
|
+
}),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
error: new ProjectActionLookupError({
|
|
308
|
+
message: `action name is ambiguous: ${selector.name.trim()} matched ${matches.length} actions`,
|
|
309
|
+
projectId,
|
|
310
|
+
selector: `name:${selector.name.trim()}`,
|
|
311
|
+
}),
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function normalizeScriptId(value: string): string {
|
|
316
|
+
const cleaned = value
|
|
317
|
+
.trim()
|
|
318
|
+
.toLowerCase()
|
|
319
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
320
|
+
.replace(/^-+|-+$/g, "");
|
|
321
|
+
if (cleaned.length === 0) {
|
|
322
|
+
return "script";
|
|
323
|
+
}
|
|
324
|
+
if (cleaned.length <= MAX_SCRIPT_ID_LENGTH) {
|
|
325
|
+
return cleaned;
|
|
326
|
+
}
|
|
327
|
+
const truncated = cleaned.slice(0, MAX_SCRIPT_ID_LENGTH).replace(/-+$/g, "");
|
|
328
|
+
return truncated.length > 0 ? truncated : "script";
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function validateUnusedId(project: OrchestrationProjectShell, id: string) {
|
|
332
|
+
if (project.scripts.some((script) => script.id === id)) {
|
|
333
|
+
return Effect.fail(
|
|
334
|
+
new ProjectActionValidationError({
|
|
335
|
+
message: `action id already exists: ${id}`,
|
|
336
|
+
projectId: project.id,
|
|
337
|
+
}),
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
return Effect.void;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function requireProjectScriptId(value: string, projectId: string) {
|
|
344
|
+
return Effect.gen(function* () {
|
|
345
|
+
const id = yield* requireTrimmedNonEmpty(value, "action id", projectId);
|
|
346
|
+
if (!isScriptRunCommand(`script.${id}.run`)) {
|
|
347
|
+
return yield* Effect.fail(
|
|
348
|
+
new ProjectActionValidationError({
|
|
349
|
+
message: `action id must be lowercase alphanumeric or hyphenated and at most ${MAX_SCRIPT_ID_LENGTH} characters`,
|
|
350
|
+
projectId,
|
|
351
|
+
}),
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return id;
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function requireTrimmedNonEmpty(value: string, field: string, projectId: string) {
|
|
359
|
+
const trimmed = value.trim();
|
|
360
|
+
if (trimmed.length === 0) {
|
|
361
|
+
return Effect.fail(
|
|
362
|
+
new ProjectActionValidationError({
|
|
363
|
+
message: `${field} must not be empty`,
|
|
364
|
+
projectId,
|
|
365
|
+
}),
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
return Effect.succeed(trimmed);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function enforceSingleSetup(
|
|
372
|
+
scripts: ReadonlyArray<ProjectScript>,
|
|
373
|
+
setupActionId: string | null,
|
|
374
|
+
): ReadonlyArray<ProjectScript> {
|
|
375
|
+
if (setupActionId === null) {
|
|
376
|
+
return scripts;
|
|
377
|
+
}
|
|
378
|
+
return scripts.map((script) =>
|
|
379
|
+
script.id === setupActionId
|
|
380
|
+
? { ...script, runOnWorktreeCreate: true }
|
|
381
|
+
: script.runOnWorktreeCreate
|
|
382
|
+
? { ...script, runOnWorktreeCreate: false }
|
|
383
|
+
: script,
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function normalizePreviewInput(input: {
|
|
388
|
+
readonly projectId: string;
|
|
389
|
+
readonly previewUrl?: string;
|
|
390
|
+
readonly autoOpenPreview: boolean;
|
|
391
|
+
}) {
|
|
392
|
+
return Effect.gen(function* () {
|
|
393
|
+
const previewUrl = input.previewUrl?.trim();
|
|
394
|
+
if (previewUrl !== undefined && previewUrl.length > 0) {
|
|
395
|
+
return {
|
|
396
|
+
previewUrl,
|
|
397
|
+
...(input.autoOpenPreview ? { autoOpenPreview: true } : {}),
|
|
398
|
+
} satisfies Partial<ProjectScript>;
|
|
399
|
+
}
|
|
400
|
+
if (input.autoOpenPreview) {
|
|
401
|
+
return yield* Effect.fail(
|
|
402
|
+
new ProjectActionValidationError({
|
|
403
|
+
message: "--auto-open-preview requires --preview-url",
|
|
404
|
+
projectId: input.projectId,
|
|
405
|
+
}),
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
return {};
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function normalizeActionUpdate(
|
|
413
|
+
projectId: string,
|
|
414
|
+
existing: ProjectScript,
|
|
415
|
+
input: UpdateProjectActionInput,
|
|
416
|
+
) {
|
|
417
|
+
return Effect.gen(function* () {
|
|
418
|
+
const patch: MutablePartial<ProjectScript> = {};
|
|
419
|
+
let clearPreviewUrl = false;
|
|
420
|
+
let clearAutoOpenPreview = false;
|
|
421
|
+
if (input.name !== undefined) {
|
|
422
|
+
patch.name = yield* requireTrimmedNonEmpty(input.name, "action name", projectId);
|
|
423
|
+
}
|
|
424
|
+
if (input.command !== undefined) {
|
|
425
|
+
patch.command = yield* requireTrimmedNonEmpty(input.command, "action command", projectId);
|
|
426
|
+
}
|
|
427
|
+
if (input.icon !== undefined) {
|
|
428
|
+
patch.icon = input.icon;
|
|
429
|
+
}
|
|
430
|
+
if (input.setup !== undefined) {
|
|
431
|
+
patch.runOnWorktreeCreate = input.setup;
|
|
432
|
+
}
|
|
433
|
+
if (input.previewUrl !== undefined) {
|
|
434
|
+
if (input.previewUrl === null) {
|
|
435
|
+
clearPreviewUrl = true;
|
|
436
|
+
clearAutoOpenPreview = true;
|
|
437
|
+
} else {
|
|
438
|
+
patch.previewUrl = yield* requireTrimmedNonEmpty(
|
|
439
|
+
input.previewUrl,
|
|
440
|
+
"preview URL",
|
|
441
|
+
projectId,
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (input.autoOpenPreview !== undefined) {
|
|
446
|
+
if (input.autoOpenPreview !== true) {
|
|
447
|
+
clearAutoOpenPreview = true;
|
|
448
|
+
} else {
|
|
449
|
+
const nextPreviewUrl = clearPreviewUrl
|
|
450
|
+
? undefined
|
|
451
|
+
: (patch.previewUrl ?? existing.previewUrl);
|
|
452
|
+
if (nextPreviewUrl === undefined) {
|
|
453
|
+
return yield* Effect.fail(
|
|
454
|
+
new ProjectActionValidationError({
|
|
455
|
+
message: "--auto-open-preview requires an existing or updated --preview-url",
|
|
456
|
+
projectId,
|
|
457
|
+
}),
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
patch.autoOpenPreview = true;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
const updated: Mutable<ProjectScript> = {
|
|
464
|
+
...existing,
|
|
465
|
+
...patch,
|
|
466
|
+
};
|
|
467
|
+
if (clearPreviewUrl) {
|
|
468
|
+
delete updated.previewUrl;
|
|
469
|
+
}
|
|
470
|
+
if (clearAutoOpenPreview) {
|
|
471
|
+
delete updated.autoOpenPreview;
|
|
472
|
+
}
|
|
473
|
+
return updated;
|
|
474
|
+
});
|
|
475
|
+
}
|
package/src/application/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export {
|
|
2
|
+
T3ActionApplication,
|
|
2
3
|
T3Application,
|
|
3
4
|
T3ModelApplication,
|
|
4
5
|
T3ProjectApplication,
|
|
@@ -7,6 +8,7 @@ export {
|
|
|
7
8
|
} from "./service.ts";
|
|
8
9
|
export {
|
|
9
10
|
makeT3Application,
|
|
11
|
+
T3ActionApplicationLive,
|
|
10
12
|
T3ApplicationLive,
|
|
11
13
|
T3ApplicationSlicesLive,
|
|
12
14
|
T3ModelApplicationLive,
|
|
@@ -15,14 +17,16 @@ export {
|
|
|
15
17
|
T3ThreadApplicationLive,
|
|
16
18
|
} from "./layer.ts";
|
|
17
19
|
export type {
|
|
20
|
+
AddProjectActionInput,
|
|
21
|
+
ProjectActionDeleteResult,
|
|
22
|
+
ProjectActionMutationResult,
|
|
23
|
+
ProjectActionRunResult,
|
|
24
|
+
ProjectActionSelector,
|
|
18
25
|
SendThreadInput,
|
|
19
26
|
StartThreadInput,
|
|
20
27
|
StartThreadPolicy,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
T3ProjectApplicationService,
|
|
24
|
-
T3TerminalApplicationService,
|
|
25
|
-
T3ThreadApplicationService,
|
|
28
|
+
T3ActionApplicationService,
|
|
29
|
+
UpdateProjectActionInput,
|
|
26
30
|
UpdateThreadInput,
|
|
27
31
|
WaitEvent,
|
|
28
32
|
} from "./service.ts";
|
package/src/application/layer.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
3
|
|
|
4
|
+
import { makeActionApplication } from "./actions.ts";
|
|
4
5
|
import { makeModelsApplication } from "./models.ts";
|
|
5
6
|
import { makeProjectApplication } from "./projects.ts";
|
|
6
7
|
import {
|
|
8
|
+
T3ActionApplication,
|
|
7
9
|
T3Application,
|
|
8
10
|
T3ModelApplication,
|
|
9
11
|
T3ProjectApplication,
|
|
@@ -15,10 +17,12 @@ import { makeThreadApplication } from "./threads.ts";
|
|
|
15
17
|
|
|
16
18
|
export const makeT3Application = Effect.fn("makeT3Application")(function* () {
|
|
17
19
|
const models = yield* T3ModelApplication;
|
|
20
|
+
const actions = yield* T3ActionApplication;
|
|
18
21
|
const projects = yield* T3ProjectApplication;
|
|
19
22
|
const terminals = yield* T3TerminalApplication;
|
|
20
23
|
const threads = yield* T3ThreadApplication;
|
|
21
24
|
return {
|
|
25
|
+
...actions,
|
|
22
26
|
...models,
|
|
23
27
|
...projects,
|
|
24
28
|
...terminals,
|
|
@@ -35,9 +39,14 @@ export const T3TerminalApplicationLive = Layer.effect(
|
|
|
35
39
|
T3TerminalApplication,
|
|
36
40
|
makeTerminalApplication(),
|
|
37
41
|
);
|
|
42
|
+
export const T3ActionApplicationLive = Layer.effect(
|
|
43
|
+
T3ActionApplication,
|
|
44
|
+
makeActionApplication(),
|
|
45
|
+
).pipe(Layer.provide(T3TerminalApplicationLive));
|
|
38
46
|
export const T3ThreadApplicationLive = Layer.effect(T3ThreadApplication, makeThreadApplication());
|
|
39
47
|
|
|
40
48
|
export const T3ApplicationSlicesLive = Layer.mergeAll(
|
|
49
|
+
T3ActionApplicationLive,
|
|
41
50
|
T3ModelApplicationLive,
|
|
42
51
|
T3ProjectApplicationLive,
|
|
43
52
|
T3TerminalApplicationLive,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
-
import { ModelSelection, ProviderInstanceId } from "
|
|
3
|
-
import type { OrchestrationProjectShell } from "
|
|
2
|
+
import { ModelSelection, ProviderInstanceId } from "@t3tools/contracts";
|
|
3
|
+
import type { OrchestrationProjectShell } from "@t3tools/contracts";
|
|
4
4
|
import * as Schema from "effect/Schema";
|
|
5
5
|
|
|
6
6
|
import { ModelSelectionError } from "../domain/error.ts";
|
|
@@ -2,18 +2,16 @@ import * as Crypto from "effect/Crypto";
|
|
|
2
2
|
import * as DateTime from "effect/DateTime";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import * as Path from "effect/Path";
|
|
5
|
-
import { CommandId, ProjectId, type ClientOrchestrationCommand } from "
|
|
6
|
-
|
|
7
|
-
import { Environment } from "../environment/service.ts";
|
|
5
|
+
import { CommandId, ProjectId, type ClientOrchestrationCommand } from "@t3tools/contracts";
|
|
8
6
|
|
|
9
7
|
export const makeProjectCreateCommand = Effect.fn("makeProjectCreateCommand")(function* (input: {
|
|
10
8
|
readonly path: string;
|
|
11
9
|
readonly title?: string;
|
|
10
|
+
readonly cwd: string;
|
|
12
11
|
}) {
|
|
13
12
|
const path = yield* Path.Path;
|
|
14
13
|
const crypto = yield* Crypto.Crypto;
|
|
15
|
-
const
|
|
16
|
-
const workspaceRoot = path.resolve(environment.cwd, input.path);
|
|
14
|
+
const workspaceRoot = path.resolve(input.cwd, input.path);
|
|
17
15
|
const projectId = ProjectId.make(yield* crypto.randomUUIDv4.pipe(Effect.orDie));
|
|
18
16
|
const title = input.title?.trim();
|
|
19
17
|
const createdAt = DateTime.formatIso(yield* DateTime.now);
|
|
@@ -43,3 +41,23 @@ export const makeProjectDeleteCommand = Effect.fn("makeProjectDeleteCommand")(fu
|
|
|
43
41
|
...(input.force === true ? { force: true } : {}),
|
|
44
42
|
} satisfies Extract<ClientOrchestrationCommand, { readonly type: "project.delete" }>;
|
|
45
43
|
});
|
|
44
|
+
|
|
45
|
+
export const makeProjectMetaUpdateCommand = Effect.fn("makeProjectMetaUpdateCommand")(
|
|
46
|
+
function* (input: {
|
|
47
|
+
readonly projectId: string;
|
|
48
|
+
readonly scripts: Extract<
|
|
49
|
+
ClientOrchestrationCommand,
|
|
50
|
+
{ readonly type: "project.meta.update" }
|
|
51
|
+
>["scripts"];
|
|
52
|
+
}) {
|
|
53
|
+
const crypto = yield* Crypto.Crypto;
|
|
54
|
+
return {
|
|
55
|
+
type: "project.meta.update",
|
|
56
|
+
commandId: CommandId.make(
|
|
57
|
+
`t3cli:project-meta-update:${yield* crypto.randomUUIDv4.pipe(Effect.orDie)}`,
|
|
58
|
+
),
|
|
59
|
+
projectId: ProjectId.make(input.projectId),
|
|
60
|
+
scripts: input.scripts,
|
|
61
|
+
} satisfies Extract<ClientOrchestrationCommand, { readonly type: "project.meta.update" }>;
|
|
62
|
+
},
|
|
63
|
+
);
|
|
@@ -2,7 +2,7 @@ import * as Crypto from "effect/Crypto";
|
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Path from "effect/Path";
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { CliRuntime } from "../cli/runtime/service.ts";
|
|
6
6
|
import { T3Orchestration } from "../orchestration/service.ts";
|
|
7
7
|
import { ProjectCreateVisibilityError, ProjectLookupError } from "../domain/error.ts";
|
|
8
8
|
import { findProjectById, resolveProjectScope } from "../domain/helpers.ts";
|
|
@@ -14,7 +14,7 @@ export const makeProjectApplication = Effect.fn("makeProjectApplication")(functi
|
|
|
14
14
|
const orchestration = yield* T3Orchestration;
|
|
15
15
|
const crypto = yield* Crypto.Crypto;
|
|
16
16
|
const path = yield* Path.Path;
|
|
17
|
-
const
|
|
17
|
+
const cliRuntime = yield* CliRuntime;
|
|
18
18
|
const loadShell: T3ProjectApplicationService["loadShell"] = Effect.fn(
|
|
19
19
|
"T3ApplicationLive.loadShell",
|
|
20
20
|
)(function* () {
|
|
@@ -40,11 +40,10 @@ export const makeProjectApplication = Effect.fn("makeProjectApplication")(functi
|
|
|
40
40
|
const addProject: T3ProjectApplicationService["addProject"] = Effect.fn(
|
|
41
41
|
"T3ApplicationLive.addProject",
|
|
42
42
|
)(function* (projectInput: { readonly path: string; readonly title?: string }) {
|
|
43
|
-
const command = yield* makeProjectCreateCommand(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
);
|
|
43
|
+
const command = yield* makeProjectCreateCommand({
|
|
44
|
+
...projectInput,
|
|
45
|
+
cwd: cliRuntime.cwd,
|
|
46
|
+
}).pipe(Effect.provideService(Path.Path, path), Effect.provideService(Crypto.Crypto, crypto));
|
|
48
47
|
const dispatch = yield* orchestration.dispatch(command);
|
|
49
48
|
const snapshot = yield* waitForShellSequence({ sequence: dispatch.sequence }).pipe(
|
|
50
49
|
Effect.provideService(T3Orchestration, orchestration),
|