@usestatemachines/cli 0.0.0-stage → 0.1.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 (169) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -2
  3. package/dist/agents/bundled.d.ts +5 -0
  4. package/dist/agents/bundled.js +6 -0
  5. package/dist/agents/destinations.d.ts +13 -0
  6. package/dist/agents/destinations.js +16 -0
  7. package/dist/api-internal.d.ts +62 -0
  8. package/dist/api-internal.js +348 -0
  9. package/dist/bin.d.ts +2 -0
  10. package/dist/bin.js +4 -0
  11. package/dist/command.d.ts +119 -0
  12. package/dist/command.js +195 -0
  13. package/dist/commands/api/command.d.ts +15 -0
  14. package/dist/commands/api/command.js +38 -0
  15. package/dist/commands/api/run.d.ts +4 -0
  16. package/dist/commands/api/run.js +24 -0
  17. package/dist/commands/apps/command.d.ts +19 -0
  18. package/dist/commands/apps/command.js +29 -0
  19. package/dist/commands/apps/list.d.ts +8 -0
  20. package/dist/commands/apps/list.js +10 -0
  21. package/dist/commands/connect/command.d.ts +34 -0
  22. package/dist/commands/connect/command.js +70 -0
  23. package/dist/commands/connect/run.d.ts +10 -0
  24. package/dist/commands/connect/run.js +71 -0
  25. package/dist/commands/doctor/command.d.ts +29 -0
  26. package/dist/commands/doctor/command.js +36 -0
  27. package/dist/commands/doctor/run.d.ts +13 -0
  28. package/dist/commands/doctor/run.js +12 -0
  29. package/dist/commands/env/command.d.ts +5 -0
  30. package/dist/commands/env/command.js +19 -0
  31. package/dist/commands/env/pull.d.ts +6 -0
  32. package/dist/commands/env/pull.js +6 -0
  33. package/dist/commands/environments/command.d.ts +121 -0
  34. package/dist/commands/environments/command.js +170 -0
  35. package/dist/commands/environments/create.d.ts +9 -0
  36. package/dist/commands/environments/create.js +42 -0
  37. package/dist/commands/environments/delete.d.ts +7 -0
  38. package/dist/commands/environments/delete.js +48 -0
  39. package/dist/commands/environments/get.d.ts +39 -0
  40. package/dist/commands/environments/get.js +5 -0
  41. package/dist/commands/environments/list.d.ts +41 -0
  42. package/dist/commands/environments/list.js +18 -0
  43. package/dist/commands/environments/wait.d.ts +39 -0
  44. package/dist/commands/environments/wait.js +21 -0
  45. package/dist/commands/init/command.d.ts +68 -0
  46. package/dist/commands/init/command.js +90 -0
  47. package/dist/commands/init/run.d.ts +8 -0
  48. package/dist/commands/init/run.js +422 -0
  49. package/dist/commands/link/command.d.ts +13 -0
  50. package/dist/commands/link/command.js +32 -0
  51. package/dist/commands/link/run.d.ts +12 -0
  52. package/dist/commands/link/run.js +7 -0
  53. package/dist/commands/login/command.d.ts +1 -0
  54. package/dist/commands/login/command.js +43 -0
  55. package/dist/commands/login/run.d.ts +30 -0
  56. package/dist/commands/login/run.js +43 -0
  57. package/dist/commands/login/schema.d.ts +33 -0
  58. package/dist/commands/login/schema.js +33 -0
  59. package/dist/commands/logout/command.d.ts +1 -0
  60. package/dist/commands/logout/command.js +24 -0
  61. package/dist/commands/logout/run.d.ts +10 -0
  62. package/dist/commands/logout/run.js +19 -0
  63. package/dist/commands/logout/schema.d.ts +10 -0
  64. package/dist/commands/logout/schema.js +10 -0
  65. package/dist/commands/profiles/command.d.ts +2 -0
  66. package/dist/commands/profiles/command.js +29 -0
  67. package/dist/commands/profiles/list.d.ts +20 -0
  68. package/dist/commands/profiles/list.js +10 -0
  69. package/dist/commands/profiles/schema.d.ts +24 -0
  70. package/dist/commands/profiles/schema.js +19 -0
  71. package/dist/commands/profiles/use.d.ts +7 -0
  72. package/dist/commands/profiles/use.js +7 -0
  73. package/dist/commands/requests/command.d.ts +39 -0
  74. package/dist/commands/requests/command.js +65 -0
  75. package/dist/commands/requests/get.d.ts +32 -0
  76. package/dist/commands/requests/get.js +15 -0
  77. package/dist/commands/requests/list.d.ts +27 -0
  78. package/dist/commands/requests/list.js +25 -0
  79. package/dist/commands/snapshots/command.d.ts +48 -0
  80. package/dist/commands/snapshots/command.js +80 -0
  81. package/dist/commands/snapshots/create.d.ts +7 -0
  82. package/dist/commands/snapshots/create.js +26 -0
  83. package/dist/commands/snapshots/delete.d.ts +34 -0
  84. package/dist/commands/snapshots/delete.js +8 -0
  85. package/dist/commands/snapshots/get.d.ts +35 -0
  86. package/dist/commands/snapshots/get.js +5 -0
  87. package/dist/commands/snapshots/list.d.ts +37 -0
  88. package/dist/commands/snapshots/list.js +10 -0
  89. package/dist/commands/unlink/command.d.ts +1 -0
  90. package/dist/commands/unlink/command.js +15 -0
  91. package/dist/commands/unlink/run.d.ts +7 -0
  92. package/dist/commands/unlink/run.js +8 -0
  93. package/dist/commands/whoami/command.d.ts +28 -0
  94. package/dist/commands/whoami/command.js +44 -0
  95. package/dist/commands/whoami/run.d.ts +5 -0
  96. package/dist/commands/whoami/run.js +39 -0
  97. package/dist/commands/workspaces/command.d.ts +33 -0
  98. package/dist/commands/workspaces/command.js +73 -0
  99. package/dist/commands/workspaces/list.d.ts +5 -0
  100. package/dist/commands/workspaces/list.js +42 -0
  101. package/dist/commands/workspaces/use.d.ts +5 -0
  102. package/dist/commands/workspaces/use.js +18 -0
  103. package/dist/config/project.d.ts +21 -0
  104. package/dist/config/project.js +105 -0
  105. package/dist/config/schema.d.ts +616 -0
  106. package/dist/config/schema.js +282 -0
  107. package/dist/context-types.d.ts +89 -0
  108. package/dist/context-types.js +56 -0
  109. package/dist/context.d.ts +13 -0
  110. package/dist/context.js +290 -0
  111. package/dist/credentials/sealing.d.ts +10 -0
  112. package/dist/credentials/sealing.js +72 -0
  113. package/dist/credentials/store.d.ts +17 -0
  114. package/dist/credentials/store.js +156 -0
  115. package/dist/doctor.d.ts +4 -0
  116. package/dist/doctor.js +239 -0
  117. package/dist/env-file.d.ts +10 -0
  118. package/dist/env-file.js +254 -0
  119. package/dist/errors.d.ts +784 -0
  120. package/dist/errors.js +459 -0
  121. package/dist/flags.d.ts +22 -0
  122. package/dist/flags.js +56 -0
  123. package/dist/generated/internal.d.ts +138 -0
  124. package/dist/generated/internal.js +2627 -0
  125. package/dist/generated/retry.d.ts +1 -0
  126. package/dist/generated/retry.js +11 -0
  127. package/dist/help.d.ts +408 -0
  128. package/dist/help.js +220 -0
  129. package/dist/io-types.d.ts +127 -0
  130. package/dist/io-types.js +1 -0
  131. package/dist/io.d.ts +13 -0
  132. package/dist/io.js +1017 -0
  133. package/dist/keys.d.ts +50 -0
  134. package/dist/keys.js +691 -0
  135. package/dist/link.d.ts +6 -0
  136. package/dist/link.js +58 -0
  137. package/dist/login.d.ts +92 -0
  138. package/dist/login.js +965 -0
  139. package/dist/main.d.ts +2 -0
  140. package/dist/main.js +126 -0
  141. package/dist/native-helper.d.ts +1 -0
  142. package/dist/native-helper.js +2 -0
  143. package/dist/output.d.ts +8 -0
  144. package/dist/output.js +135 -0
  145. package/dist/parser.d.ts +28 -0
  146. package/dist/parser.js +250 -0
  147. package/dist/program-types.d.ts +67 -0
  148. package/dist/program-types.js +14 -0
  149. package/dist/programs.d.ts +2 -0
  150. package/dist/programs.js +44 -0
  151. package/dist/project-roots.d.ts +3 -0
  152. package/dist/project-roots.js +26 -0
  153. package/dist/prompt.d.ts +3 -0
  154. package/dist/prompt.js +61 -0
  155. package/dist/registry.d.ts +2 -0
  156. package/dist/registry.js +44 -0
  157. package/dist/resources/create.d.ts +9 -0
  158. package/dist/resources/create.js +55 -0
  159. package/dist/resources/read.d.ts +15 -0
  160. package/dist/resources/read.js +69 -0
  161. package/dist/resources/schema.d.ts +177 -0
  162. package/dist/resources/schema.js +158 -0
  163. package/dist/text.d.ts +3 -0
  164. package/dist/text.js +19 -0
  165. package/dist/update.d.ts +22 -0
  166. package/dist/update.js +126 -0
  167. package/dist/version.d.ts +2 -0
  168. package/dist/version.js +2 -0
  169. package/package.json +52 -3
@@ -0,0 +1,39 @@
1
+ import type { z } from 'zod';
2
+ import type { WorkspaceContext } from '../../context-types.js';
3
+ import { resourceText } from '../../resources/read.js';
4
+ import type { waitInputSchema } from './command.js';
5
+ export declare function run(input: z.infer<typeof waitInputSchema>, context: WorkspaceContext): Promise<{
6
+ id: string;
7
+ workspaceId: string;
8
+ name: string | null;
9
+ labels: Record<string, string>;
10
+ status: string;
11
+ reason: string | null;
12
+ failure: {
13
+ appName: string;
14
+ code: string;
15
+ message: string;
16
+ } | null;
17
+ timeLimitMinutes: number;
18
+ tokenInUrl: boolean;
19
+ snapshotId: string | null;
20
+ apps: {
21
+ appId: string;
22
+ name: string;
23
+ version: string;
24
+ versionId: string;
25
+ setup: Record<string, z.JSONType>;
26
+ services: Record<string, z.JSONType>;
27
+ url: string;
28
+ }[];
29
+ createdBy: {
30
+ id: string | null;
31
+ name: string | null;
32
+ type: string;
33
+ };
34
+ createdAt: string;
35
+ startedAt: string | null;
36
+ deletedAt: string | null;
37
+ expiresAt: string | null;
38
+ }>;
39
+ export declare const text: typeof resourceText;
@@ -0,0 +1,21 @@
1
+ import { resourceError } from '../../resources/create.js';
2
+ import { environment, environmentResult, resourceText, } from '../../resources/read.js';
3
+ export async function run(input, context) {
4
+ await environment(context, input.id);
5
+ try {
6
+ return environmentResult(await context.sdk.environments.wait(input.id, {
7
+ status: input.status,
8
+ signal: context.io.signal,
9
+ ...(input.timeout === undefined
10
+ ? {}
11
+ : { timeoutMs: Number(input.timeout) * 1000 }),
12
+ }));
13
+ }
14
+ catch (cause) {
15
+ throw await resourceError(cause, context, {
16
+ resource: 'environment',
17
+ id: input.id,
18
+ });
19
+ }
20
+ }
21
+ export const text = resourceText;
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod';
2
+ export declare const packageManagerSchema: z.ZodEnum<{
3
+ bun: "bun";
4
+ npm: "npm";
5
+ pnpm: "pnpm";
6
+ yarn: "yarn";
7
+ }>;
8
+ export declare const initInputSchema: z.ZodObject<{
9
+ agent: z.ZodDefault<z.ZodArray<z.ZodString>>;
10
+ force: z.ZodDefault<z.ZodBoolean>;
11
+ sdk: z.ZodDefault<z.ZodBoolean>;
12
+ quickstart: z.ZodDefault<z.ZodBoolean>;
13
+ env: z.ZodDefault<z.ZodBoolean>;
14
+ packageManager: z.ZodOptional<z.ZodEnum<{
15
+ bun: "bun";
16
+ npm: "npm";
17
+ pnpm: "pnpm";
18
+ yarn: "yarn";
19
+ }>>;
20
+ }, z.core.$strict>;
21
+ export declare const initResultSchema: z.ZodObject<{
22
+ repositoryRoot: z.ZodString;
23
+ packageRoot: z.ZodNullable<z.ZodString>;
24
+ workspace: z.ZodObject<{
25
+ id: z.ZodString;
26
+ name: z.ZodString;
27
+ }, z.core.$strict>;
28
+ skills: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
29
+ agent: z.ZodString;
30
+ status: z.ZodLiteral<"unsupported">;
31
+ }, z.core.$strict>, z.ZodObject<{
32
+ agent: z.ZodEnum<{
33
+ claude: "claude";
34
+ codex: "codex";
35
+ }>;
36
+ path: z.ZodString;
37
+ status: z.ZodEnum<{
38
+ created: "created";
39
+ preserved: "preserved";
40
+ replaced: "replaced";
41
+ unchanged: "unchanged";
42
+ }>;
43
+ }, z.core.$strict>]>>;
44
+ changedFiles: z.ZodArray<z.ZodString>;
45
+ packageManager: z.ZodNullable<z.ZodEnum<{
46
+ bun: "bun";
47
+ npm: "npm";
48
+ pnpm: "pnpm";
49
+ yarn: "yarn";
50
+ }>>;
51
+ dependencies: z.ZodArray<z.ZodObject<{
52
+ name: z.ZodString;
53
+ status: z.ZodEnum<{
54
+ installed: "installed";
55
+ unchanged: "unchanged";
56
+ }>;
57
+ }, z.core.$strict>>;
58
+ environment: z.ZodNullable<z.ZodObject<{
59
+ path: z.ZodString;
60
+ workspaceId: z.core.$ZodBranded<z.ZodString, "WorkspaceId", "out">;
61
+ keyId: z.ZodString;
62
+ expiresAt: z.ZodString;
63
+ pendingRevocation: z.ZodBoolean;
64
+ }, z.core.$strict>>;
65
+ nextCommand: z.ZodString;
66
+ installCliCommand: z.ZodNullable<z.ZodString>;
67
+ }, z.core.$strict>;
68
+ export declare const initCommand: import("../../command.js").RegisteredCommand;
@@ -0,0 +1,90 @@
1
+ import { z } from 'zod';
2
+ import { agentDestinations } from '../../agents/destinations.js';
3
+ import { defineCommand } from '../../command.js';
4
+ import { envPullResultSchema } from '../../program-types.js';
5
+ export const packageManagerSchema = z.enum(['npm', 'pnpm', 'yarn', 'bun']);
6
+ export const initInputSchema = z.strictObject({
7
+ agent: z.array(z.string().min(1)).default([]),
8
+ force: z.boolean().default(false),
9
+ sdk: z.boolean().default(false),
10
+ quickstart: z.boolean().default(false),
11
+ env: z.boolean().default(false),
12
+ packageManager: packageManagerSchema.optional(),
13
+ });
14
+ export const initResultSchema = z.strictObject({
15
+ repositoryRoot: z.string(),
16
+ packageRoot: z.string().nullable(),
17
+ workspace: z.strictObject({ id: z.string(), name: z.string() }),
18
+ skills: z.array(z.union([
19
+ z.strictObject({ agent: z.string(), status: z.literal('unsupported') }),
20
+ z.strictObject({
21
+ agent: z.enum(agentDestinations.map((agent) => agent.id)),
22
+ path: z.string(),
23
+ status: z.enum(['created', 'replaced', 'unchanged', 'preserved']),
24
+ }),
25
+ ])),
26
+ changedFiles: z.array(z.string()),
27
+ packageManager: packageManagerSchema.nullable(),
28
+ dependencies: z.array(z.strictObject({
29
+ name: z.string(),
30
+ status: z.enum(['installed', 'unchanged']),
31
+ })),
32
+ environment: envPullResultSchema.nullable(),
33
+ nextCommand: z.string(),
34
+ installCliCommand: z.string().nullable(),
35
+ });
36
+ export const initCommand = defineCommand({
37
+ name: ['init'],
38
+ summary: 'Link this repository and install the State Machines skill.',
39
+ need: 'account',
40
+ workspace: true,
41
+ destructive: false,
42
+ streams: false,
43
+ arguments: [],
44
+ flags: [
45
+ {
46
+ name: 'agent',
47
+ key: 'agent',
48
+ type: 'string[]',
49
+ description: 'Install for claude or codex. Repeat for more agents.',
50
+ },
51
+ {
52
+ name: 'force',
53
+ key: 'force',
54
+ type: 'boolean',
55
+ negatedName: null,
56
+ description: 'Replace a different existing State Machines skill.',
57
+ },
58
+ {
59
+ name: 'sdk',
60
+ key: 'sdk',
61
+ type: 'boolean',
62
+ negatedName: null,
63
+ description: 'Add the SDK to the nearest containing package.',
64
+ },
65
+ {
66
+ name: 'quickstart',
67
+ key: 'quickstart',
68
+ type: 'boolean',
69
+ negatedName: null,
70
+ description: 'Write state-quickstart.mts in the nearest containing package.',
71
+ },
72
+ {
73
+ name: 'env',
74
+ key: 'env',
75
+ type: 'boolean',
76
+ negatedName: null,
77
+ description: 'Run env pull for .env.local. Replaces its previous key.',
78
+ },
79
+ {
80
+ name: 'package-manager',
81
+ key: 'packageManager',
82
+ type: 'string',
83
+ description: 'Use npm, pnpm, yarn, or bun for --sdk.',
84
+ },
85
+ ],
86
+ input: initInputSchema,
87
+ result: initResultSchema,
88
+ progress: z.never(),
89
+ load: () => import('./run.js'),
90
+ });
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+ import type { AccountContext } from '../../context-types.js';
3
+ import type { initInputSchema, initResultSchema } from './command.js';
4
+ type Input = z.infer<typeof initInputSchema>;
5
+ type Result = z.infer<typeof initResultSchema>;
6
+ export declare function run(input: Input, context: AccountContext): Promise<Result>;
7
+ export declare function text(result: Result): string;
8
+ export {};
@@ -0,0 +1,422 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { dirname, join, relative } from 'node:path';
3
+ import { z } from 'zod';
4
+ import { quickstart, skill } from '../../agents/bundled.js';
5
+ import { agentDestinations } from '../../agents/destinations.js';
6
+ import { CliError, normalizeError, withErrorDetails } from '../../errors.js';
7
+ import { linkWorkspace } from '../../link.js';
8
+ import { findPackageRoot, findProjectRoot } from '../../project-roots.js';
9
+ import { cliVersion, sdkVersion } from '../../version.js';
10
+ const manifestSchema = z.object({
11
+ dependencies: z.record(z.string(), z.string()).optional(),
12
+ devDependencies: z.record(z.string(), z.string()).optional(),
13
+ optionalDependencies: z.record(z.string(), z.string()).optional(),
14
+ peerDependencies: z.record(z.string(), z.string()).optional(),
15
+ packageManager: z.string().optional(),
16
+ workspaces: z.unknown().optional(),
17
+ });
18
+ const lockfiles = {
19
+ npm: ['package-lock.json', 'npm-shrinkwrap.json'],
20
+ pnpm: ['pnpm-lock.yaml'],
21
+ yarn: ['yarn.lock'],
22
+ bun: ['bun.lock', 'bun.lockb'],
23
+ };
24
+ function declares(manifest, name) {
25
+ return [
26
+ manifest.dependencies,
27
+ manifest.devDependencies,
28
+ manifest.optionalDependencies,
29
+ manifest.peerDependencies,
30
+ ].some((dependencies) => dependencies?.[name] !== undefined);
31
+ }
32
+ async function readManifest(io, root, options) {
33
+ try {
34
+ return manifestSchema.parse(JSON.parse((await io.files.read(join(root, 'package.json'), options)) ?? 'null'));
35
+ }
36
+ catch (error) {
37
+ if (error instanceof CliError) {
38
+ throw error;
39
+ }
40
+ throw new CliError('cli.invalid_arguments', {
41
+ message: 'The package.json file is invalid. Fix it before running init.',
42
+ });
43
+ }
44
+ }
45
+ async function checkDestination(io, path, root, options) {
46
+ let directory = dirname(path);
47
+ for (;;) {
48
+ const inspected = await io.files.inspect(directory, options);
49
+ if (inspected.kind !== 'missing' && inspected.kind !== 'directory') {
50
+ throw new CliError('cli.config_io');
51
+ }
52
+ if (directory === root || dirname(directory) === directory) {
53
+ break;
54
+ }
55
+ directory = dirname(directory);
56
+ }
57
+ return io.files.read(path, options);
58
+ }
59
+ async function selectPackageManager(io, root, repository, input, options) {
60
+ if (input.packageManager !== undefined) {
61
+ return input.packageManager;
62
+ }
63
+ let directory = root;
64
+ for (;;) {
65
+ const found = [];
66
+ for (const manager of [
67
+ 'npm',
68
+ 'pnpm',
69
+ 'yarn',
70
+ 'bun',
71
+ ]) {
72
+ for (const name of lockfiles[manager]) {
73
+ if ((await io.files.inspect(join(directory, name), options)).kind !==
74
+ 'missing') {
75
+ found.push(manager);
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ if (found.length > 0) {
81
+ const first = found[0];
82
+ if (found.length === 1 && first !== undefined) {
83
+ return first;
84
+ }
85
+ break;
86
+ }
87
+ if (directory === repository || dirname(directory) === directory) {
88
+ break;
89
+ }
90
+ directory = dirname(directory);
91
+ }
92
+ throw new CliError('cli.input_required', {
93
+ message: 'Choose a package manager because no single lockfile identifies one.',
94
+ next: [
95
+ {
96
+ command: 'statemachines init --sdk --package-manager <npm|pnpm|yarn|bun>',
97
+ reason: 'Choose the package manager for this package.',
98
+ },
99
+ ],
100
+ });
101
+ }
102
+ function installArgs(manager, name, dev) {
103
+ return manager === 'npm'
104
+ ? ['install', ...(dev ? ['--save-dev'] : []), name]
105
+ : ['add', ...(dev ? ['--dev'] : []), name];
106
+ }
107
+ async function workspaceRootArgs(io, manager, manifest, packageRoot, files, options) {
108
+ if (manager === 'pnpm') {
109
+ const workspace = await io.files.inspect(join(packageRoot, 'pnpm-workspace.yaml'), options);
110
+ return workspace.kind === 'file' ? ['--workspace-root'] : [];
111
+ }
112
+ if (manager !== 'yarn' || manifest.workspaces === undefined) {
113
+ return [];
114
+ }
115
+ const lock = [...files].find(([path, before]) => before !== null && path.endsWith('yarn.lock'));
116
+ const berry = /^yarn@(?!1\.)/.test(manifest.packageManager ?? '') ||
117
+ (lock !== undefined &&
118
+ (await io.files.read(lock[0], options))?.includes('__metadata:') ===
119
+ true);
120
+ return berry ? [] : ['-W'];
121
+ }
122
+ async function digest(io, path, options) {
123
+ const bytes = await io.files.readBytes(path, options);
124
+ return bytes === null
125
+ ? null
126
+ : createHash('sha256').update(bytes).digest('hex');
127
+ }
128
+ async function dependencyFiles(io, packageRoot, repositoryRoot, options) {
129
+ const files = new Map();
130
+ files.set(join(packageRoot, 'package.json'), await digest(io, join(packageRoot, 'package.json'), options));
131
+ let directory = packageRoot;
132
+ for (;;) {
133
+ for (const name of Object.values(lockfiles).flat()) {
134
+ const path = join(directory, name);
135
+ files.set(path, await digest(io, path, options));
136
+ }
137
+ if (directory === repositoryRoot || dirname(directory) === directory) {
138
+ return files;
139
+ }
140
+ directory = dirname(directory);
141
+ }
142
+ }
143
+ export async function run(input, context) {
144
+ const { io } = context;
145
+ const options = { signal: io.signal, deadline: null };
146
+ if (input.packageManager !== undefined && !input.sdk) {
147
+ throw new CliError('cli.invalid_arguments', {
148
+ message: 'Use --package-manager only with --sdk.',
149
+ });
150
+ }
151
+ const repositoryRoot = await findProjectRoot(io, options);
152
+ if (repositoryRoot === null) {
153
+ throw new CliError('cli.invalid_arguments', {
154
+ message: 'Run init inside a Git repository or a directory with package.json, other than your home directory.',
155
+ });
156
+ }
157
+ const packageRoot = await findPackageRoot(io, io.host.cwd, repositoryRoot, options);
158
+ if ((input.sdk || input.quickstart) && packageRoot === null) {
159
+ throw new CliError('cli.invalid_arguments', {
160
+ message: 'Run this option inside a package with package.json.',
161
+ });
162
+ }
163
+ if (input.env) {
164
+ if (context.account.kind !== 'cli-token') {
165
+ throw new CliError('cli.env_requires_login');
166
+ }
167
+ if ((await io.files.findRepositoryRoot(io.host.cwd, options)) === null) {
168
+ throw new CliError('cli.env_path_refused');
169
+ }
170
+ }
171
+ const packageManager = input.sdk && packageRoot !== null
172
+ ? await selectPackageManager(io, packageRoot, repositoryRoot, input, options)
173
+ : null;
174
+ const quickstartPath = input.quickstart && packageRoot !== null
175
+ ? join(packageRoot, 'state-quickstart.mts')
176
+ : null;
177
+ if (quickstartPath !== null) {
178
+ const existing = await checkDestination(io, quickstartPath, repositoryRoot, options);
179
+ if (existing !== null && existing !== quickstart) {
180
+ throw new CliError('cli.invalid_arguments', {
181
+ message: 'state-quickstart.mts already exists. Rename it before running init --quickstart.',
182
+ });
183
+ }
184
+ }
185
+ const detected = [];
186
+ for (const agent of agentDestinations) {
187
+ if ((await io.files.inspect(join(repositoryRoot, agent.directory), options))
188
+ .kind === 'directory') {
189
+ detected.push(agent.id);
190
+ }
191
+ }
192
+ const chosen = input.agent.length > 0 ? [...new Set(input.agent)] : detected;
193
+ const candidates = context.presentation.mode === 'interactive' && input.agent.length === 0
194
+ ? agentDestinations
195
+ : agentDestinations.filter((agent) => chosen.includes(agent.id));
196
+ for (const agent of candidates) {
197
+ await checkDestination(io, join(repositoryRoot, agent.path), repositoryRoot, options);
198
+ }
199
+ return io.files.withLock(join(repositoryRoot, '.statemachines', 'init.lock'), options, async () => {
200
+ const manifest = packageRoot === null
201
+ ? null
202
+ : await readManifest(io, packageRoot, options);
203
+ const changedFiles = [];
204
+ const existing = await context.projects.read();
205
+ if (existing !== null) {
206
+ const organizationId = context.account.kind === 'cli-token'
207
+ ? context.account.organizationId
208
+ : (await context.sdk.me()).organization?.id;
209
+ if (organizationId === undefined) {
210
+ throw new CliError('cli.invalid_response');
211
+ }
212
+ if (existing.organizationId !== organizationId) {
213
+ throw new CliError('cli.organization_mismatch');
214
+ }
215
+ }
216
+ else {
217
+ const ignorePath = join(repositoryRoot, '.gitignore');
218
+ const beforeIgnore = await io.files.read(ignorePath, options);
219
+ const linked = await linkWorkspace(context, { force: false });
220
+ changedFiles.push(linked.path);
221
+ if ((await io.files.read(ignorePath, options)) !== beforeIgnore) {
222
+ changedFiles.push(ignorePath);
223
+ }
224
+ }
225
+ const workspace = await context.resolveWorkspace();
226
+ if (workspace === null) {
227
+ throw new CliError('cli.not_linked');
228
+ }
229
+ if (existing !== null && workspace.id !== existing.workspaceId) {
230
+ throw new CliError('cli.workspace_mismatch', {
231
+ message: 'This repository is linked to another workspace. Use link --force to replace the link.',
232
+ next: [
233
+ {
234
+ command: 'statemachines link --force --workspace <id>',
235
+ reason: 'Choose the workspace for this repository.',
236
+ },
237
+ ],
238
+ });
239
+ }
240
+ const agents = context.presentation.mode === 'interactive' && input.agent.length === 0
241
+ ? await io.prompt.multiselect('Choose agents', agentDestinations.map((agent) => ({
242
+ value: agent.id,
243
+ label: agent.label,
244
+ })), detected, options)
245
+ : chosen;
246
+ const skills = [];
247
+ for (const id of agents) {
248
+ const agent = agentDestinations.find((candidate) => candidate.id === id);
249
+ if (agent === undefined) {
250
+ skills.push({ agent: id, status: 'unsupported' });
251
+ continue;
252
+ }
253
+ const path = join(repositoryRoot, agent.path);
254
+ const before = await io.files.read(path, options);
255
+ let status;
256
+ if (before === skill) {
257
+ status = 'unchanged';
258
+ }
259
+ else if (before !== null) {
260
+ status = input.force ? 'replaced' : 'preserved';
261
+ if (input.force) {
262
+ await io.files.atomicWrite(path, skill, 'public', options);
263
+ }
264
+ }
265
+ else if (await io.files.createIfMissing(path, skill, 'public', options)) {
266
+ status = 'created';
267
+ }
268
+ else {
269
+ status =
270
+ (await io.files.read(path, options)) === skill
271
+ ? 'unchanged'
272
+ : 'preserved';
273
+ }
274
+ if (status === 'created' || status === 'replaced') {
275
+ changedFiles.push(path);
276
+ }
277
+ skills.push({ agent: agent.id, path, status });
278
+ }
279
+ if (quickstartPath !== null) {
280
+ if (await io.files.createIfMissing(quickstartPath, quickstart, 'public', options)) {
281
+ changedFiles.push(quickstartPath);
282
+ }
283
+ else if ((await io.files.read(quickstartPath, options)) !== quickstart) {
284
+ throw new CliError('cli.invalid_arguments', {
285
+ message: 'state-quickstart.mts changed during init. Keep that file and run init without --quickstart.',
286
+ details: { changedFiles },
287
+ });
288
+ }
289
+ }
290
+ const dependencies = [];
291
+ let installCliCommand = null;
292
+ if (packageManager !== null &&
293
+ packageRoot !== null &&
294
+ manifest !== null) {
295
+ const cli = '@usestatemachines/cli';
296
+ const sdk = '@usestatemachines/sdk';
297
+ const existingCli = declares(manifest, cli);
298
+ const installCli = !existingCli &&
299
+ context.presentation.mode === 'interactive' &&
300
+ (await io.prompt.confirm('Install the CLI as a development dependency?', options));
301
+ const selected = [
302
+ { name: sdk, version: sdkVersion, dev: false },
303
+ ...(existingCli || installCli
304
+ ? [{ name: cli, version: cliVersion, dev: true }]
305
+ : []),
306
+ ];
307
+ const beforeFiles = await dependencyFiles(io, packageRoot, repositoryRoot, options);
308
+ const rootArgs = await workspaceRootArgs(io, packageManager, manifest, packageRoot, beforeFiles, options);
309
+ const add = (name, dev) => [
310
+ ...installArgs(packageManager, name, dev),
311
+ ...rootArgs,
312
+ ];
313
+ if (!existingCli && !installCli) {
314
+ installCliCommand = [
315
+ packageManager,
316
+ ...add(`${cli}@${cliVersion}`, true),
317
+ ].join(' ');
318
+ }
319
+ try {
320
+ for (const dependency of selected) {
321
+ if (declares(manifest, dependency.name)) {
322
+ dependencies.push({ name: dependency.name, status: 'unchanged' });
323
+ continue;
324
+ }
325
+ const outcome = await io.child.run({
326
+ command: packageManager,
327
+ args: add(`${dependency.name}@${dependency.version}`, dependency.dev),
328
+ cwd: packageRoot,
329
+ stdin: 'ignore',
330
+ output: 'stderr',
331
+ environment: Object.fromEntries(Object.entries(io.host.environment).filter((entry) => entry[1] !== undefined)),
332
+ options,
333
+ });
334
+ if (outcome.kind !== 'exit' || outcome.code !== 0) {
335
+ throw new CliError('cli.package_install', {
336
+ details: { outcome },
337
+ });
338
+ }
339
+ if (!declares(await readManifest(io, packageRoot, options), dependency.name)) {
340
+ throw new CliError('cli.package_install');
341
+ }
342
+ dependencies.push({ name: dependency.name, status: 'installed' });
343
+ }
344
+ }
345
+ catch (error) {
346
+ const after = {
347
+ signal: new AbortController().signal,
348
+ deadline: io.now() + 5_000,
349
+ };
350
+ const current = await Promise.all([...beforeFiles].map(async ([path, before]) => (await digest(io, path, after)) === before ? [] : [path]));
351
+ changedFiles.push(...current.flat());
352
+ if (options.signal.aborted) {
353
+ throw new CliError('cli.cancelled', { details: { changedFiles } });
354
+ }
355
+ const failure = normalizeError(error);
356
+ throw withErrorDetails(failure, {
357
+ changedFiles,
358
+ cause: failure.document.error.details,
359
+ });
360
+ }
361
+ for (const [path, before] of beforeFiles) {
362
+ if ((await digest(io, path, options)) !== before) {
363
+ changedFiles.push(path);
364
+ }
365
+ }
366
+ }
367
+ const ignoreFiles = new Map();
368
+ if (input.env) {
369
+ for (const directory of new Set([repositoryRoot, io.host.cwd])) {
370
+ const path = join(directory, '.gitignore');
371
+ ignoreFiles.set(path, await io.files.read(path, options));
372
+ }
373
+ }
374
+ const environment = input.env
375
+ ? await context
376
+ .forWorkspace(workspace)
377
+ .programs.pullEnvironment('.env.local')
378
+ : null;
379
+ if (environment !== null) {
380
+ changedFiles.push(environment.path);
381
+ for (const [path, before] of ignoreFiles) {
382
+ if ((await io.files.read(path, options)) !== before &&
383
+ !changedFiles.includes(path)) {
384
+ changedFiles.push(path);
385
+ }
386
+ }
387
+ }
388
+ return {
389
+ repositoryRoot,
390
+ packageRoot,
391
+ workspace: { id: workspace.id, name: workspace.name },
392
+ skills,
393
+ changedFiles,
394
+ packageManager,
395
+ dependencies,
396
+ environment,
397
+ nextCommand: quickstartPath === null
398
+ ? 'statemachines run -- <command>'
399
+ : `statemachines run -- npx tsx ${relative(io.host.cwd, quickstartPath).replaceAll('\\', '/')}`,
400
+ installCliCommand,
401
+ };
402
+ });
403
+ }
404
+ export function text(result) {
405
+ const lines = [`Linked to ${result.workspace.name}.`];
406
+ for (const installed of result.skills) {
407
+ lines.push(installed.status === 'unsupported'
408
+ ? `No skill installed for unsupported agent ${installed.agent}.`
409
+ : `${installed.agent}: ${installed.status === 'preserved' ? 'kept the existing skill' : installed.status} ${installed.path}.`);
410
+ }
411
+ if (result.skills.length === 0) {
412
+ lines.push('No agents selected. No skill installed.');
413
+ }
414
+ lines.push(result.changedFiles.length === 0
415
+ ? 'No files changed.'
416
+ : `Changed files:\n${result.changedFiles.map((path) => ` ${path}`).join('\n')}`);
417
+ if (result.installCliCommand !== null) {
418
+ lines.push(`Optional CLI dependency: ${result.installCliCommand}`);
419
+ }
420
+ lines.push(`Next: ${result.nextCommand}`);
421
+ return lines.join('\n');
422
+ }
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ export declare const linkInputSchema: z.ZodObject<{
3
+ force: z.ZodDefault<z.ZodBoolean>;
4
+ }, z.core.$strict>;
5
+ export declare const linkResultSchema: z.ZodObject<{
6
+ path: z.ZodString;
7
+ organizationId: z.ZodString;
8
+ workspace: z.ZodObject<{
9
+ id: z.ZodString;
10
+ name: z.ZodString;
11
+ }, z.core.$strict>;
12
+ }, z.core.$strict>;
13
+ export declare const linkCommand: import("../../command.js").RegisteredCommand;