@rigkit/cli 0.2.7 → 0.2.8
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 +12 -3
- package/package.json +4 -7
- package/src/cli.test.ts +139 -7
- package/src/cli.ts +699 -235
- package/src/completion.test.ts +139 -10
- package/src/completion.ts +427 -72
- package/src/init.ts +6 -4
- package/src/project.test.ts +33 -3
- package/src/project.ts +99 -11
- package/src/run-logger.test.ts +92 -0
- package/src/run-logger.ts +203 -0
- package/src/run-presenter.ts +176 -299
- package/src/ui.ts +159 -0
- package/src/version.ts +1 -1
- package/src/remote-project.test.ts +0 -55
- package/src/remote-project.ts +0 -225
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ npm i -g @rigkit/cli
|
|
|
7
7
|
rig init
|
|
8
8
|
rig plan
|
|
9
9
|
rig ls
|
|
10
|
-
rig plan
|
|
10
|
+
rig -chdir=examples/smoke plan
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
`rig init` asks for a project name, Freestyle API key, and package manager. It creates a project folder containing a workflow-based `rig.config.ts`, `.env`, `.env.example`, `package.json`, and local ignore rules.
|
|
@@ -16,10 +16,19 @@ Interactive terminals use Inquirer prompts and a chalk/log-update run timeline.
|
|
|
16
16
|
|
|
17
17
|
Interactive providers can ask the CLI to open provider-owned URLs. For example, Freestyle terminal sessions are served by the Freestyle provider, while the CLI only opens the presented URL in a browser.
|
|
18
18
|
|
|
19
|
-
Workspace
|
|
19
|
+
Workspace lifecycle commands are built in: `rig create <workspace>` creates a
|
|
20
|
+
workspace and `rig rm <workspace>` removes one. Workspace-specific operations
|
|
21
|
+
defined by the project run as `rig run <workspace> <operation>`, for example
|
|
22
|
+
`rig run website-workspace open-cmux`.
|
|
20
23
|
|
|
21
24
|
`rig ls` lists workspaces for the selected project. `rig ls snapshots` lists cached snapshot runs, and `rig ls config` shows the resolved project paths.
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
Use Terraform-style global context options before the command to select another
|
|
27
|
+
project or config:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
rig -chdir=examples/smoke plan
|
|
31
|
+
rig -chdir=examples/global-fragments -config=api.rig.config.ts apply
|
|
32
|
+
```
|
|
24
33
|
|
|
25
34
|
Projects should install matching `@rigkit/sdk` versions locally.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigkit/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,12 +22,9 @@
|
|
|
22
22
|
"chalk": "^5.6.2",
|
|
23
23
|
"commander": "^14.0.3",
|
|
24
24
|
"inquirer": "^13.4.3",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"@rigkit/provider-cmux": "0.2.7",
|
|
29
|
-
"@rigkit/runtime-client": "0.2.7",
|
|
30
|
-
"@rigkit/engine": "0.2.7"
|
|
25
|
+
"@rigkit/provider-cmux": "0.2.8",
|
|
26
|
+
"@rigkit/runtime-client": "0.2.8",
|
|
27
|
+
"@rigkit/engine": "0.2.8"
|
|
31
28
|
},
|
|
32
29
|
"devDependencies": {
|
|
33
30
|
"@types/bun": "latest",
|
package/src/cli.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { projectIdFor, runtimeFingerprintFor, runtimePaths, SUPPORTED_RUNTIME_API_VERSION } from "@rigkit/runtime-client";
|
|
@@ -24,7 +24,9 @@ describe("CLI entrypoint", () => {
|
|
|
24
24
|
expect(rootHelp.stderr).toBe("");
|
|
25
25
|
expect(rootHelp.stdout).toContain("rig ");
|
|
26
26
|
expect(rootHelp.stdout).toContain("plan Plan project workflow changes");
|
|
27
|
+
expect(rootHelp.stdout).toContain("rm Remove a workspace");
|
|
27
28
|
expect(rootHelp.stdout).toContain("run Run a workspace operation");
|
|
29
|
+
expect(rootHelp.stdout).toContain("cache Inspect and clear Rigkit cache");
|
|
28
30
|
|
|
29
31
|
const version = await runCli(["version"]);
|
|
30
32
|
expect(version.exitCode).toBe(0);
|
|
@@ -36,7 +38,9 @@ describe("CLI entrypoint", () => {
|
|
|
36
38
|
expect(help.stderr).toBe("");
|
|
37
39
|
expect(help.stdout).toContain("rig ");
|
|
38
40
|
expect(help.stdout).toContain("plan Plan project workflow changes");
|
|
41
|
+
expect(help.stdout).toContain("rm Remove a workspace");
|
|
39
42
|
expect(help.stdout).toContain("run Run a workspace operation");
|
|
43
|
+
expect(help.stdout).toContain("cache Inspect and clear Rigkit cache");
|
|
40
44
|
});
|
|
41
45
|
|
|
42
46
|
test("rejects operation shorthand at the root", async () => {
|
|
@@ -52,7 +56,7 @@ describe("CLI entrypoint", () => {
|
|
|
52
56
|
|
|
53
57
|
expect(result.exitCode).toBe(0);
|
|
54
58
|
expect(result.stderr).toBe("");
|
|
55
|
-
expect(result.stdout.trim()).toBe("version\tshow CLI version");
|
|
59
|
+
expect(result.stdout.trim()).toBe("version\tshow CLI version\t\tCommands");
|
|
56
60
|
});
|
|
57
61
|
|
|
58
62
|
test("discovers projects without starting a runtime", async () => {
|
|
@@ -77,11 +81,54 @@ describe("CLI entrypoint", () => {
|
|
|
77
81
|
}
|
|
78
82
|
});
|
|
79
83
|
|
|
84
|
+
test("shows named config choices when the default config is missing", async () => {
|
|
85
|
+
const cwd = mkdtempSync(join(tmpdir(), "rigkit-cli-named-configs-"));
|
|
86
|
+
writeFileSync(join(cwd, "api.rig.config.ts"), "export default {}\n");
|
|
87
|
+
writeFileSync(join(cwd, "web.rig.config.ts"), "export default {}\n");
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const result = await runCli(["create", "--json"], { cwd });
|
|
91
|
+
|
|
92
|
+
expect(result.exitCode).toBe(1);
|
|
93
|
+
expect(result.stdout).toBe("");
|
|
94
|
+
expect(result.stderr).toContain("No Rigkit config found from");
|
|
95
|
+
expect(result.stderr).toContain("Found named Rigkit configs");
|
|
96
|
+
expect(result.stderr).toContain("api.rig.config.ts");
|
|
97
|
+
expect(result.stderr).toContain("web.rig.config.ts");
|
|
98
|
+
expect(result.stderr).toContain("rig -chdir=. -config=api.rig.config.ts <command>");
|
|
99
|
+
} finally {
|
|
100
|
+
rmSync(cwd, { recursive: true, force: true });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("clears all global fragment cache without loading a config", async () => {
|
|
105
|
+
const rigkitHome = mkdtempSync(join(tmpdir(), "rigkit-cli-cache-"));
|
|
106
|
+
const fragmentDir = join(rigkitHome, "fragments", "sha256-test");
|
|
107
|
+
mkdirSync(fragmentDir, { recursive: true });
|
|
108
|
+
writeFileSync(join(fragmentDir, "state.sqlite"), "");
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const result = await runCli(["cache", "clear", "--global", "--all", "--json"], {
|
|
112
|
+
env: { RIGKIT_HOME: rigkitHome },
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(result.exitCode).toBe(0);
|
|
116
|
+
expect(result.stderr).toBe("");
|
|
117
|
+
expect(JSON.parse(result.stdout)).toMatchObject({
|
|
118
|
+
ok: true,
|
|
119
|
+
scope: "global-all",
|
|
120
|
+
});
|
|
121
|
+
expect(existsSync(fragmentDir)).toBe(false);
|
|
122
|
+
} finally {
|
|
123
|
+
rmSync(rigkitHome, { recursive: true, force: true });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
80
127
|
test("lists workspaces from the project runtime", async () => {
|
|
81
128
|
const projectDir = mkdtempSync(join(tmpdir(), "rigkit-cli-ls-"));
|
|
82
129
|
|
|
83
130
|
await withWorkspaceRuntime({ projectDir }, async ({ env }) => {
|
|
84
|
-
const result = await runCli([
|
|
131
|
+
const result = await runCli([`-chdir=${projectDir}`, "ls"], { env });
|
|
85
132
|
|
|
86
133
|
expect(result.exitCode).toBe(0);
|
|
87
134
|
expect(result.stderr).toBe("");
|
|
@@ -94,7 +141,7 @@ describe("CLI entrypoint", () => {
|
|
|
94
141
|
const projectDir = mkdtempSync(join(tmpdir(), "rigkit-cli-ls-json-"));
|
|
95
142
|
|
|
96
143
|
await withWorkspaceRuntime({ projectDir }, async ({ env }) => {
|
|
97
|
-
const result = await runCli([
|
|
144
|
+
const result = await runCli([`-chdir=${projectDir}`, "ls", "--json"], { env });
|
|
98
145
|
|
|
99
146
|
expect(result.exitCode).toBe(0);
|
|
100
147
|
expect(result.stderr).toBe("");
|
|
@@ -112,7 +159,7 @@ describe("CLI entrypoint", () => {
|
|
|
112
159
|
const projectDir = mkdtempSync(join(tmpdir(), "rigkit-cli-create-name-"));
|
|
113
160
|
|
|
114
161
|
await withWorkspaceRuntime({ projectDir }, async ({ env }) => {
|
|
115
|
-
const result = await runCli([
|
|
162
|
+
const result = await runCli([`-chdir=${projectDir}`, "create", "--name", "some workspace", "--json"], { env });
|
|
116
163
|
|
|
117
164
|
expect(result.exitCode).toBe(1);
|
|
118
165
|
expect(result.stdout).toBe("");
|
|
@@ -120,6 +167,34 @@ describe("CLI entrypoint", () => {
|
|
|
120
167
|
});
|
|
121
168
|
});
|
|
122
169
|
|
|
170
|
+
test("accepts create name as a positional argument", async () => {
|
|
171
|
+
const projectDir = mkdtempSync(join(tmpdir(), "rigkit-cli-create-positional-"));
|
|
172
|
+
|
|
173
|
+
await withWorkspaceRuntime({ projectDir }, async ({ env }) => {
|
|
174
|
+
const result = await runCli([`-chdir=${projectDir}`, "create", "new-workspace", "--json"], { env });
|
|
175
|
+
|
|
176
|
+
expect(result.exitCode).toBe(0);
|
|
177
|
+
expect(result.stderr).toBe("");
|
|
178
|
+
expect(JSON.parse(result.stdout)).toMatchObject({
|
|
179
|
+
name: "new-workspace",
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("removes a workspace with the built-in rm command", async () => {
|
|
185
|
+
const projectDir = mkdtempSync(join(tmpdir(), "rigkit-cli-rm-"));
|
|
186
|
+
|
|
187
|
+
await withWorkspaceRuntime({ projectDir }, async ({ env }) => {
|
|
188
|
+
const result = await runCli([`-chdir=${projectDir}`, "rm", "api", "-y", "--json"], { env });
|
|
189
|
+
|
|
190
|
+
expect(result.exitCode).toBe(0);
|
|
191
|
+
expect(result.stderr).toBe("");
|
|
192
|
+
expect(JSON.parse(result.stdout)).toMatchObject({
|
|
193
|
+
name: "api",
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
123
198
|
test("requires discovered projects for operation --all", async () => {
|
|
124
199
|
const cwd = mkdtempSync(join(tmpdir(), "rigkit-cli-run-all-"));
|
|
125
200
|
|
|
@@ -196,10 +271,11 @@ async function withWorkspaceRuntime(
|
|
|
196
271
|
writeFileSync(paths.tokenPath, `${token}\n`);
|
|
197
272
|
|
|
198
273
|
const now = new Date(0).toISOString();
|
|
274
|
+
let runResult: unknown = undefined;
|
|
199
275
|
const server = Bun.serve({
|
|
200
276
|
hostname: "127.0.0.1",
|
|
201
277
|
port: 0,
|
|
202
|
-
fetch(request) {
|
|
278
|
+
async fetch(request) {
|
|
203
279
|
if (request.headers.get("authorization") !== `Bearer ${token}`) {
|
|
204
280
|
return runtimeJson({ error: { message: "Unauthorized" } }, { status: 401 });
|
|
205
281
|
}
|
|
@@ -240,6 +316,7 @@ async function withWorkspaceRuntime(
|
|
|
240
316
|
description: "Create a workspace",
|
|
241
317
|
createsWorkspace: true,
|
|
242
318
|
cli: {
|
|
319
|
+
positionals: [{ name: "name", index: 0 }],
|
|
243
320
|
options: [{ name: "name", flag: "--name", required: true, type: "string" }],
|
|
244
321
|
},
|
|
245
322
|
inputSchema: {
|
|
@@ -251,9 +328,64 @@ async function withWorkspaceRuntime(
|
|
|
251
328
|
required: ["name"],
|
|
252
329
|
},
|
|
253
330
|
}],
|
|
254
|
-
workspaceOperations: [
|
|
331
|
+
workspaceOperations: [{
|
|
332
|
+
id: "remove",
|
|
333
|
+
kind: "workspace-action",
|
|
334
|
+
source: "core",
|
|
335
|
+
title: "Remove",
|
|
336
|
+
description: "remove workspace",
|
|
337
|
+
cli: {
|
|
338
|
+
options: [{ name: "yes", flag: "--yes", aliases: ["-y"], type: "boolean", runtime: false }],
|
|
339
|
+
},
|
|
340
|
+
inputSchema: {
|
|
341
|
+
type: "object",
|
|
342
|
+
additionalProperties: false,
|
|
343
|
+
properties: {},
|
|
344
|
+
},
|
|
345
|
+
}],
|
|
255
346
|
});
|
|
256
347
|
}
|
|
348
|
+
if (pathname === "/runs") {
|
|
349
|
+
const body = await request.json() as { operation?: string; input?: { name?: string } };
|
|
350
|
+
runResult = body.operation === "api/remove"
|
|
351
|
+
? {
|
|
352
|
+
id: "workspace-api",
|
|
353
|
+
name: "api",
|
|
354
|
+
workflow: "smoke",
|
|
355
|
+
ctx: {},
|
|
356
|
+
createdAt: now,
|
|
357
|
+
updatedAt: now,
|
|
358
|
+
}
|
|
359
|
+
: {
|
|
360
|
+
id: "workspace-new",
|
|
361
|
+
name: body.input?.name ?? "new-workspace",
|
|
362
|
+
workflow: "smoke",
|
|
363
|
+
ctx: {},
|
|
364
|
+
createdAt: now,
|
|
365
|
+
updatedAt: now,
|
|
366
|
+
};
|
|
367
|
+
return runtimeJson({
|
|
368
|
+
runId: "run-test",
|
|
369
|
+
operation: body.operation ?? "test",
|
|
370
|
+
status: "running",
|
|
371
|
+
eventsUrl: "/runs/run-test/events",
|
|
372
|
+
sessionUrl: "",
|
|
373
|
+
}, { status: 202 });
|
|
374
|
+
}
|
|
375
|
+
if (pathname === "/runs/run-test/events") {
|
|
376
|
+
return new Response(
|
|
377
|
+
`data: ${JSON.stringify({
|
|
378
|
+
type: "run.completed",
|
|
379
|
+
result: runResult,
|
|
380
|
+
})}\n\n`,
|
|
381
|
+
{
|
|
382
|
+
headers: {
|
|
383
|
+
"content-type": "text/event-stream",
|
|
384
|
+
"x-rigkit-api-version": String(SUPPORTED_RUNTIME_API_VERSION),
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
);
|
|
388
|
+
}
|
|
257
389
|
return runtimeJson({ error: { message: "Not found" } }, { status: 404 });
|
|
258
390
|
},
|
|
259
391
|
});
|