@scenar/cli 0.3.0 → 0.4.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/package.json +4 -9
- package/src/__tests__/embed-snippet.test.ts +1 -1
- package/src/__tests__/install-command.test.ts +97 -0
- package/src/__tests__/local-url.test.ts +17 -0
- package/src/__tests__/run-install.test.ts +222 -0
- package/src/api.d.ts +3 -1
- package/src/api.d.ts.map +1 -1
- package/src/api.js +3 -1
- package/src/api.js.map +1 -1
- package/src/api.ts +10 -1
- package/src/commands/install.d.ts +3 -0
- package/src/commands/install.d.ts.map +1 -0
- package/src/commands/install.js +67 -0
- package/src/commands/install.js.map +1 -0
- package/src/commands/install.ts +89 -0
- package/src/commands/pack.js +2 -2
- package/src/commands/pack.js.map +1 -1
- package/src/commands/pack.ts +2 -2
- package/src/commands/serve.d.ts.map +1 -1
- package/src/commands/serve.js +1 -2
- package/src/commands/serve.js.map +1 -1
- package/src/commands/serve.ts +1 -2
- package/src/commands/try.js +1 -1
- package/src/commands/try.ts +1 -1
- package/src/embed/embed-snippet.d.ts.map +1 -0
- package/src/embed/embed-snippet.js.map +1 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +3 -5
- package/src/index.js.map +1 -1
- package/src/index.ts +3 -5
- package/src/install/run-install.d.ts +72 -0
- package/src/install/run-install.d.ts.map +1 -0
- package/src/install/run-install.js +378 -0
- package/src/install/run-install.js.map +1 -0
- package/src/install/run-install.ts +461 -0
- package/src/install/scaffold.d.ts +29 -0
- package/src/install/scaffold.d.ts.map +1 -0
- package/src/install/scaffold.js +233 -0
- package/src/install/scaffold.js.map +1 -0
- package/src/install/scaffold.ts +255 -0
- package/src/pack/pack-manifest.d.ts +1 -1
- package/src/pack/pack-manifest.d.ts.map +1 -1
- package/src/pack/pack-manifest.ts +1 -1
- package/src/publish/publish-flow.d.ts +3 -3
- package/src/publish/publish-flow.js +3 -3
- package/src/publish/publish-flow.ts +3 -3
- package/src/publish/run-publish.js +1 -1
- package/src/publish/run-publish.js.map +1 -1
- package/src/publish/run-publish.ts +1 -1
- package/src/render/detect-render-export.d.ts +2 -2
- package/src/render/detect-render-export.js +2 -2
- package/src/render/detect-render-export.ts +2 -2
- package/src/serve/local-url.d.ts +8 -0
- package/src/serve/local-url.d.ts.map +1 -0
- package/src/serve/local-url.js +21 -0
- package/src/serve/local-url.js.map +1 -0
- package/src/serve/local-url.ts +20 -0
- package/src/serve/run-serve.js +2 -2
- package/src/serve/run-serve.js.map +1 -1
- package/src/serve/run-serve.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/src/__tests__/deploy-command.test.ts +0 -45
- package/src/__tests__/deploy-flow.test.ts +0 -125
- package/src/__tests__/deploy-upload.test.ts +0 -39
- package/src/commands/deploy.d.ts +0 -3
- package/src/commands/deploy.d.ts.map +0 -1
- package/src/commands/deploy.js +0 -150
- package/src/commands/deploy.js.map +0 -1
- package/src/commands/deploy.ts +0 -186
- package/src/commands/preview.d.ts +0 -3
- package/src/commands/preview.d.ts.map +0 -1
- package/src/commands/preview.js +0 -93
- package/src/commands/preview.js.map +0 -1
- package/src/commands/preview.ts +0 -138
- package/src/deploy/client.d.ts +0 -20
- package/src/deploy/client.d.ts.map +0 -1
- package/src/deploy/client.js +0 -22
- package/src/deploy/client.js.map +0 -1
- package/src/deploy/client.ts +0 -28
- package/src/deploy/deploy-flow.d.ts +0 -78
- package/src/deploy/deploy-flow.d.ts.map +0 -1
- package/src/deploy/deploy-flow.js +0 -53
- package/src/deploy/deploy-flow.js.map +0 -1
- package/src/deploy/deploy-flow.ts +0 -115
- package/src/deploy/embed-snippet.d.ts.map +0 -1
- package/src/deploy/embed-snippet.js.map +0 -1
- package/src/deploy/upload.d.ts +0 -10
- package/src/deploy/upload.d.ts.map +0 -1
- package/src/deploy/upload.js +0 -23
- package/src/deploy/upload.js.map +0 -1
- package/src/deploy/upload.ts +0 -29
- /package/src/{deploy → embed}/embed-snippet.d.ts +0 -0
- /package/src/{deploy → embed}/embed-snippet.js +0 -0
- /package/src/{deploy → embed}/embed-snippet.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scenar/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Scenar CLI — validate scenarios, generate narration, and render videos.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -39,14 +39,9 @@
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@
|
|
43
|
-
"@
|
|
44
|
-
"@
|
|
45
|
-
"@scenar/core": "0.3.0",
|
|
46
|
-
"@scenar/embed": "0.3.0",
|
|
47
|
-
"@scenar/preview": "0.3.0",
|
|
48
|
-
"@scenar/sdk": "0.3.0",
|
|
49
|
-
"@scenar/stubs": "0.3.0",
|
|
42
|
+
"@scenar/core": "0.4.0",
|
|
43
|
+
"@scenar/embed": "0.4.0",
|
|
44
|
+
"@scenar/sdk": "0.4.0",
|
|
50
45
|
"commander": "^13.0.0",
|
|
51
46
|
"yaml": "^2.7.0"
|
|
52
47
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { buildEmbedSnippet, buildEnhancedEmbedSnippet } from "../
|
|
2
|
+
import { buildEmbedSnippet, buildEnhancedEmbedSnippet } from "../embed/embed-snippet.js";
|
|
3
3
|
|
|
4
4
|
describe("buildEmbedSnippet", () => {
|
|
5
5
|
const embedUrl = "https://d-dep1.scenarusercontent.net/";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtemp, rm, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { createProgram } from "../index.js";
|
|
7
|
+
|
|
8
|
+
describe("scenar install (command surface)", () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
process.exitCode = undefined;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("registers the install command", () => {
|
|
14
|
+
const program = createProgram();
|
|
15
|
+
const cmd = program.commands.find((c) => c.name() === "install");
|
|
16
|
+
expect(cmd).toBeDefined();
|
|
17
|
+
expect(cmd!.description()).toContain("Bootstrap a Scenar demos project");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("takes variadic packages and exposes its options", () => {
|
|
21
|
+
const program = createProgram();
|
|
22
|
+
const cmd = program.commands.find((c) => c.name() === "install");
|
|
23
|
+
expect(cmd!.registeredArguments).toHaveLength(1);
|
|
24
|
+
expect(cmd!.registeredArguments[0]!.variadic).toBe(true);
|
|
25
|
+
const opts = cmd!.options.map((o) => o.long);
|
|
26
|
+
expect(opts).toContain("--dir");
|
|
27
|
+
expect(opts).toContain("--no-install");
|
|
28
|
+
expect(opts).toContain("--package-manager");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe("scenar install (end-to-end, --no-install)", () => {
|
|
33
|
+
let dir: string;
|
|
34
|
+
|
|
35
|
+
beforeEach(async () => {
|
|
36
|
+
dir = await mkdtemp(join(tmpdir(), "scenar-install-cmd-"));
|
|
37
|
+
process.exitCode = undefined;
|
|
38
|
+
vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
afterEach(async () => {
|
|
42
|
+
vi.restoreAllMocks();
|
|
43
|
+
await rm(dir, { recursive: true, force: true });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
async function runInstallCommand(args: string[]): Promise<void> {
|
|
47
|
+
const program = createProgram();
|
|
48
|
+
program.exitOverride();
|
|
49
|
+
try {
|
|
50
|
+
await program.parseAsync(["node", "scenar", "install", ...args]);
|
|
51
|
+
} catch {
|
|
52
|
+
// commander throws under exitOverride; assertions cover the outcome
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
it("scaffolds a runnable starter tour on first run", async () => {
|
|
57
|
+
await runInstallCommand(["--no-install", "--dir", dir]);
|
|
58
|
+
|
|
59
|
+
expect(process.exitCode).not.toBe(1);
|
|
60
|
+
expect(existsSync(join(dir, "package.json"))).toBe(true);
|
|
61
|
+
expect(existsSync(join(dir, "tsconfig.json"))).toBe(true);
|
|
62
|
+
expect(existsSync(join(dir, ".gitignore"))).toBe(true);
|
|
63
|
+
expect(existsSync(join(dir, "tours/example-tour/steps.ts"))).toBe(true);
|
|
64
|
+
expect(existsSync(join(dir, "tours/example-tour/index.tsx"))).toBe(true);
|
|
65
|
+
expect(existsSync(join(dir, "tours/example-tour/.scenar/providers.tsx"))).toBe(true);
|
|
66
|
+
|
|
67
|
+
const index = await readFile(join(dir, "tours/example-tour/index.tsx"), "utf-8");
|
|
68
|
+
expect(index).toContain("renderStep");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("never overwrites authored files on re-run", async () => {
|
|
72
|
+
await runInstallCommand(["--no-install", "--dir", dir]);
|
|
73
|
+
|
|
74
|
+
// Every scaffolded file is author-owned, so edits must survive a re-run.
|
|
75
|
+
const indexPath = join(dir, "tours/example-tour/index.tsx");
|
|
76
|
+
const marker = "// EDITED BY AUTHOR — must survive re-run\n";
|
|
77
|
+
const original = await readFile(indexPath, "utf-8");
|
|
78
|
+
await writeFile(indexPath, marker + original, "utf-8");
|
|
79
|
+
|
|
80
|
+
await runInstallCommand(["--no-install", "--dir", dir]);
|
|
81
|
+
|
|
82
|
+
const after = await readFile(indexPath, "utf-8");
|
|
83
|
+
expect(after.startsWith(marker)).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("records a named dependency in package.json", async () => {
|
|
87
|
+
await runInstallCommand(["--no-install", "--dir", dir, "@stigmer/react@^1.0.0"]);
|
|
88
|
+
|
|
89
|
+
const pkg = JSON.parse(await readFile(join(dir, "package.json"), "utf-8"));
|
|
90
|
+
expect(pkg.dependencies["@stigmer/react"]).toBe("^1.0.0");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("rejects an invalid --package-manager", async () => {
|
|
94
|
+
await runInstallCommand(["--no-install", "--dir", dir, "--package-manager", "bun"]);
|
|
95
|
+
expect(process.exitCode).toBe(1);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { localViewUrl } from "../serve/local-url.js";
|
|
3
|
+
|
|
4
|
+
describe("localViewUrl", () => {
|
|
5
|
+
it("downgrades https to http for *.localhost hosts (local edges serve http)", () => {
|
|
6
|
+
expect(localViewUrl("https://d-abc.localhost:8787/")).toBe("http://d-abc.localhost:8787/");
|
|
7
|
+
expect(localViewUrl("https://localhost:8787/")).toBe("http://localhost:8787/");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("leaves production https URLs untouched", () => {
|
|
11
|
+
expect(localViewUrl("https://d-abc.scenar.ai/")).toBe("https://d-abc.scenar.ai/");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("returns non-URL input unchanged", () => {
|
|
15
|
+
expect(localViewUrl("not a url")).toBe("not a url");
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtemp, rm, mkdir, writeFile, readFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import {
|
|
7
|
+
runInstall,
|
|
8
|
+
parseSpec,
|
|
9
|
+
detectPackageManager,
|
|
10
|
+
findWorkspaceRoot,
|
|
11
|
+
} from "../install/run-install.js";
|
|
12
|
+
|
|
13
|
+
const silent = () => {};
|
|
14
|
+
|
|
15
|
+
describe("parseSpec", () => {
|
|
16
|
+
const cwd = "/tmp/does-not-matter";
|
|
17
|
+
|
|
18
|
+
it("parses a bare name", () => {
|
|
19
|
+
expect(parseSpec("react", cwd)).toEqual({ name: "react", range: "" });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("parses a scoped bare name", () => {
|
|
23
|
+
expect(parseSpec("@stigmer/react", cwd)).toEqual({
|
|
24
|
+
name: "@stigmer/react",
|
|
25
|
+
range: "",
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("parses name@range", () => {
|
|
30
|
+
expect(parseSpec("react@^19.0.0", cwd)).toEqual({
|
|
31
|
+
name: "react",
|
|
32
|
+
range: "^19.0.0",
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("parses @scope/name@range", () => {
|
|
37
|
+
expect(parseSpec("@stigmer/react@1.2.0", cwd)).toEqual({
|
|
38
|
+
name: "@stigmer/react",
|
|
39
|
+
range: "1.2.0",
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("rejects git/URL specs without a name", () => {
|
|
44
|
+
expect(() => parseSpec("git+https://example.com/x.git", cwd)).toThrow(
|
|
45
|
+
/no package name/,
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("detectPackageManager", () => {
|
|
51
|
+
let dir: string;
|
|
52
|
+
|
|
53
|
+
beforeEach(async () => {
|
|
54
|
+
dir = await mkdtemp(join(tmpdir(), "scenar-pm-"));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
afterEach(async () => {
|
|
58
|
+
await rm(dir, { recursive: true, force: true });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("defaults to npm when no lockfile is present", () => {
|
|
62
|
+
expect(detectPackageManager(dir)).toBe("npm");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("detects pnpm", async () => {
|
|
66
|
+
await writeFile(join(dir, "pnpm-lock.yaml"), "", "utf-8");
|
|
67
|
+
expect(detectPackageManager(dir)).toBe("pnpm");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("detects yarn", async () => {
|
|
71
|
+
await writeFile(join(dir, "yarn.lock"), "", "utf-8");
|
|
72
|
+
expect(detectPackageManager(dir)).toBe("yarn");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("detects npm from package-lock.json", async () => {
|
|
76
|
+
await writeFile(join(dir, "package-lock.json"), "{}", "utf-8");
|
|
77
|
+
expect(detectPackageManager(dir)).toBe("npm");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("findWorkspaceRoot", () => {
|
|
82
|
+
let root: string;
|
|
83
|
+
|
|
84
|
+
beforeEach(async () => {
|
|
85
|
+
root = await mkdtemp(join(tmpdir(), "scenar-ws-"));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
afterEach(async () => {
|
|
89
|
+
await rm(root, { recursive: true, force: true });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("detects a member via pnpm-workspace.yaml globs", async () => {
|
|
93
|
+
await writeFile(
|
|
94
|
+
join(root, "pnpm-workspace.yaml"),
|
|
95
|
+
"packages:\n - 'packages/*'\n",
|
|
96
|
+
"utf-8",
|
|
97
|
+
);
|
|
98
|
+
const member = join(root, "packages", "demos");
|
|
99
|
+
await mkdir(member, { recursive: true });
|
|
100
|
+
expect(findWorkspaceRoot(member)).toBe(root);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("detects a member via package.json workspaces", async () => {
|
|
104
|
+
await writeFile(
|
|
105
|
+
join(root, "package.json"),
|
|
106
|
+
JSON.stringify({ name: "root", workspaces: ["apps/*"] }),
|
|
107
|
+
"utf-8",
|
|
108
|
+
);
|
|
109
|
+
const member = join(root, "apps", "web");
|
|
110
|
+
await mkdir(member, { recursive: true });
|
|
111
|
+
expect(findWorkspaceRoot(member)).toBe(root);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("returns null for a standalone directory", async () => {
|
|
115
|
+
const standalone = join(root, "standalone");
|
|
116
|
+
await mkdir(standalone, { recursive: true });
|
|
117
|
+
expect(findWorkspaceRoot(standalone)).toBeNull();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("runInstall (skipInstall)", () => {
|
|
122
|
+
let dir: string;
|
|
123
|
+
|
|
124
|
+
beforeEach(async () => {
|
|
125
|
+
dir = await mkdtemp(join(tmpdir(), "scenar-install-"));
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
afterEach(async () => {
|
|
129
|
+
await rm(dir, { recursive: true, force: true });
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
async function readPkg(d: string) {
|
|
133
|
+
return JSON.parse(await readFile(join(d, "package.json"), "utf-8"));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
it("scaffolds a fresh project with a runnable starter tour", () => {
|
|
137
|
+
const result = runInstall({ cwd: dir, packages: [], onLog: silent, skipInstall: true });
|
|
138
|
+
expect(result.scaffolded).toBe(true);
|
|
139
|
+
expect(existsSync(join(dir, "package.json"))).toBe(true);
|
|
140
|
+
expect(existsSync(join(dir, ".gitignore"))).toBe(true);
|
|
141
|
+
expect(existsSync(join(dir, "tsconfig.json"))).toBe(true);
|
|
142
|
+
expect(existsSync(join(dir, "tours/example-tour/steps.ts"))).toBe(true);
|
|
143
|
+
expect(existsSync(join(dir, "tours/example-tour/index.tsx"))).toBe(true);
|
|
144
|
+
expect(existsSync(join(dir, "tours/example-tour/.scenar/providers.tsx"))).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("records a bare package as '*'", async () => {
|
|
148
|
+
runInstall({ cwd: dir, packages: ["@stigmer/react"], onLog: silent, skipInstall: true });
|
|
149
|
+
const pkg = await readPkg(dir);
|
|
150
|
+
expect(pkg.dependencies["@stigmer/react"]).toBe("*");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("records an explicit range", async () => {
|
|
154
|
+
runInstall({ cwd: dir, packages: ["@stigmer/react@^1.2.0"], onLog: silent, skipInstall: true });
|
|
155
|
+
const pkg = await readPkg(dir);
|
|
156
|
+
expect(pkg.dependencies["@stigmer/react"]).toBe("^1.2.0");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("does not clobber an existing pin when given a bare name", async () => {
|
|
160
|
+
runInstall({ cwd: dir, packages: ["@stigmer/react@^1.2.0"], onLog: silent, skipInstall: true });
|
|
161
|
+
runInstall({ cwd: dir, packages: ["@stigmer/react"], onLog: silent, skipInstall: true });
|
|
162
|
+
const pkg = await readPkg(dir);
|
|
163
|
+
expect(pkg.dependencies["@stigmer/react"]).toBe("^1.2.0");
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("resolves a file: spec's name from its target package.json", async () => {
|
|
167
|
+
const lib = join(dir, "..", `lib-${Date.now()}`);
|
|
168
|
+
await mkdir(lib, { recursive: true });
|
|
169
|
+
await writeFile(
|
|
170
|
+
join(lib, "package.json"),
|
|
171
|
+
JSON.stringify({ name: "@local/lib", version: "0.0.0" }),
|
|
172
|
+
"utf-8",
|
|
173
|
+
);
|
|
174
|
+
try {
|
|
175
|
+
runInstall({
|
|
176
|
+
cwd: dir,
|
|
177
|
+
packages: [`file:${lib}`],
|
|
178
|
+
onLog: silent,
|
|
179
|
+
skipInstall: true,
|
|
180
|
+
});
|
|
181
|
+
const pkg = await readPkg(dir);
|
|
182
|
+
expect(pkg.dependencies["@local/lib"]).toBe(`file:${lib}`);
|
|
183
|
+
} finally {
|
|
184
|
+
await rm(lib, { recursive: true, force: true });
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("uses workspace:* for a workspace member under pnpm", async () => {
|
|
189
|
+
const root = await mkdtemp(join(tmpdir(), "scenar-ws-install-"));
|
|
190
|
+
try {
|
|
191
|
+
await writeFile(join(root, "pnpm-lock.yaml"), "", "utf-8");
|
|
192
|
+
await writeFile(
|
|
193
|
+
join(root, "pnpm-workspace.yaml"),
|
|
194
|
+
"packages:\n - 'packages/*'\n",
|
|
195
|
+
"utf-8",
|
|
196
|
+
);
|
|
197
|
+
const reactPkg = join(root, "packages", "react");
|
|
198
|
+
await mkdir(reactPkg, { recursive: true });
|
|
199
|
+
await writeFile(
|
|
200
|
+
join(reactPkg, "package.json"),
|
|
201
|
+
JSON.stringify({ name: "@stigmer/react", version: "0.0.0" }),
|
|
202
|
+
"utf-8",
|
|
203
|
+
);
|
|
204
|
+
const demos = join(root, "packages", "demos");
|
|
205
|
+
await mkdir(demos, { recursive: true });
|
|
206
|
+
|
|
207
|
+
const result = runInstall({
|
|
208
|
+
cwd: demos,
|
|
209
|
+
packages: ["@stigmer/react"],
|
|
210
|
+
onLog: silent,
|
|
211
|
+
skipInstall: true,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(result.workspaceRoot).toBe(root);
|
|
215
|
+
expect(result.packageManager).toBe("pnpm");
|
|
216
|
+
const pkg = await readPkg(demos);
|
|
217
|
+
expect(pkg.dependencies["@stigmer/react"]).toBe("workspace:*");
|
|
218
|
+
} finally {
|
|
219
|
+
await rm(root, { recursive: true, force: true });
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
package/src/api.d.ts
CHANGED
|
@@ -21,11 +21,13 @@ export type { RunPublishOptions, PublishRunResult } from "./publish/run-publish.
|
|
|
21
21
|
export { runPublishFlow, validateRepoName, validatePublishPath, normalizePath, pagesUrl, repoUrl, } from "./publish/publish-flow.js";
|
|
22
22
|
export type { PublishFlowDeps, PublishOptions, PublishResult, } from "./publish/publish-flow.js";
|
|
23
23
|
export { createGithubPublisher } from "./publish/github.js";
|
|
24
|
+
export { runInstall } from "./install/run-install.js";
|
|
25
|
+
export type { RunInstallOptions, RunInstallResult, ParsedSpec, PackageManager, } from "./install/run-install.js";
|
|
24
26
|
export { validateScenario } from "./validate/scenario-validator.js";
|
|
25
27
|
export { loadScenarioYaml } from "./util/load-yaml.js";
|
|
26
28
|
export { readBundleViewport } from "./bundle/read-viewport.js";
|
|
27
29
|
export type { BundleViewport } from "./bundle/read-viewport.js";
|
|
28
|
-
export { buildEmbedSnippet } from "./
|
|
30
|
+
export { buildEmbedSnippet } from "./embed/embed-snippet.js";
|
|
29
31
|
export { DEFAULT_VIEWPORT, parseViewport } from "./pack/viewport.js";
|
|
30
32
|
export type { Viewport } from "./pack/viewport.js";
|
|
31
33
|
//# sourceMappingURL=api.d.ts.map
|
package/src/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGnG,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG7E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACjF,YAAY,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAG7F,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,eAAe,EACf,cAAc,EACd,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGnG,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG7E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACjF,YAAY,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAG7F,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,eAAe,EACf,cAAc,EACd,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,cAAc,GACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC"}
|
package/src/api.js
CHANGED
|
@@ -18,11 +18,13 @@ export { startBundleServer, createBundleServer } from "./serve/static-server.js"
|
|
|
18
18
|
export { runPublish } from "./publish/run-publish.js";
|
|
19
19
|
export { runPublishFlow, validateRepoName, validatePublishPath, normalizePath, pagesUrl, repoUrl, } from "./publish/publish-flow.js";
|
|
20
20
|
export { createGithubPublisher } from "./publish/github.js";
|
|
21
|
+
// Install (bootstrap a demos project: scaffold + add deps + run the package manager)
|
|
22
|
+
export { runInstall } from "./install/run-install.js";
|
|
21
23
|
// Validate
|
|
22
24
|
export { validateScenario } from "./validate/scenario-validator.js";
|
|
23
25
|
export { loadScenarioYaml } from "./util/load-yaml.js";
|
|
24
26
|
// Bundle helpers (viewport + embed snippet)
|
|
25
27
|
export { readBundleViewport } from "./bundle/read-viewport.js";
|
|
26
|
-
export { buildEmbedSnippet } from "./
|
|
28
|
+
export { buildEmbedSnippet } from "./embed/embed-snippet.js";
|
|
27
29
|
export { DEFAULT_VIEWPORT, parseViewport } from "./pack/viewport.js";
|
|
28
30
|
//# sourceMappingURL=api.js.map
|
package/src/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO;AACP,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI7C,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,SAAS;AACT,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,QAAQ;AACR,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGjF,yBAAyB;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,WAAW;AACX,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,4CAA4C;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO;AACP,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI7C,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,SAAS;AACT,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,QAAQ;AACR,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGjF,yBAAyB;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,qFAAqF;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAQtD,WAAW;AACX,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,4CAA4C;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
package/src/api.ts
CHANGED
|
@@ -43,6 +43,15 @@ export type {
|
|
|
43
43
|
} from "./publish/publish-flow.js";
|
|
44
44
|
export { createGithubPublisher } from "./publish/github.js";
|
|
45
45
|
|
|
46
|
+
// Install (bootstrap a demos project: scaffold + add deps + run the package manager)
|
|
47
|
+
export { runInstall } from "./install/run-install.js";
|
|
48
|
+
export type {
|
|
49
|
+
RunInstallOptions,
|
|
50
|
+
RunInstallResult,
|
|
51
|
+
ParsedSpec,
|
|
52
|
+
PackageManager,
|
|
53
|
+
} from "./install/run-install.js";
|
|
54
|
+
|
|
46
55
|
// Validate
|
|
47
56
|
export { validateScenario } from "./validate/scenario-validator.js";
|
|
48
57
|
export { loadScenarioYaml } from "./util/load-yaml.js";
|
|
@@ -50,6 +59,6 @@ export { loadScenarioYaml } from "./util/load-yaml.js";
|
|
|
50
59
|
// Bundle helpers (viewport + embed snippet)
|
|
51
60
|
export { readBundleViewport } from "./bundle/read-viewport.js";
|
|
52
61
|
export type { BundleViewport } from "./bundle/read-viewport.js";
|
|
53
|
-
export { buildEmbedSnippet } from "./
|
|
62
|
+
export { buildEmbedSnippet } from "./embed/embed-snippet.js";
|
|
54
63
|
export { DEFAULT_VIEWPORT, parseViewport } from "./pack/viewport.js";
|
|
55
64
|
export type { Viewport } from "./pack/viewport.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/commands/install.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+C7D"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { runInstall } from "../install/run-install.js";
|
|
3
|
+
const PACKAGE_MANAGERS = ["npm", "yarn", "pnpm"];
|
|
4
|
+
export function registerInstallCommand(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("install")
|
|
7
|
+
.description("Bootstrap a Scenar demos project in one step.\n\n" +
|
|
8
|
+
"Scaffolds a package.json and a runnable starter tour under\n" +
|
|
9
|
+
"tours/example-tour/ if the directory is empty, adds the given\n" +
|
|
10
|
+
"component packages as ordinary dependencies, and runs your package\n" +
|
|
11
|
+
"manager. Re-run any time — existing files are never overwritten, so\n" +
|
|
12
|
+
"your authored tours are always preserved.\n\n" +
|
|
13
|
+
"Component packages are consumed as normal dependencies — import and\n" +
|
|
14
|
+
"compose them into the tours you author under tours/. Specs are\n" +
|
|
15
|
+
"resolver-agnostic: a registry version (@stigmer/react@1.2.0),\n" +
|
|
16
|
+
"workspace:*, file:../pkg, or a git URL all work; resolution is your\n" +
|
|
17
|
+
"package manager's job.\n\n" +
|
|
18
|
+
"Inside a monorepo, the project is detected as a workspace member and\n" +
|
|
19
|
+
"the install runs at the workspace root.")
|
|
20
|
+
.argument("[packages...]", "component packages to add as dependencies (e.g. @stigmer/react)")
|
|
21
|
+
.option("--dir <path>", "project directory (default: current directory)")
|
|
22
|
+
.option("--no-install", "scaffold and record dependencies but skip the install")
|
|
23
|
+
.option("--package-manager <pm>", "force npm | yarn | pnpm instead of auto-detecting")
|
|
24
|
+
.action(async (packages, options) => {
|
|
25
|
+
try {
|
|
26
|
+
const cwd = path.resolve(options.dir ?? process.cwd());
|
|
27
|
+
const installResult = runInstall({
|
|
28
|
+
cwd,
|
|
29
|
+
packages: packages ?? [],
|
|
30
|
+
onLog: (line) => process.stderr.write(`${line}\n`),
|
|
31
|
+
skipInstall: options.install === false,
|
|
32
|
+
packageManager: parsePackageManager(options.packageManager),
|
|
33
|
+
});
|
|
34
|
+
printNextSteps(cwd, installResult.installRan);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
38
|
+
process.stderr.write(`\x1b[31mError:\x1b[0m ${msg}\n`);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function parsePackageManager(value) {
|
|
44
|
+
if (value === undefined)
|
|
45
|
+
return undefined;
|
|
46
|
+
if (PACKAGE_MANAGERS.includes(value)) {
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`invalid --package-manager "${value}"; expected one of ${PACKAGE_MANAGERS.join(", ")}.`);
|
|
50
|
+
}
|
|
51
|
+
function printNextSteps(cwd, installRan) {
|
|
52
|
+
const rel = path.relative(process.cwd(), cwd);
|
|
53
|
+
// Prefer a short relative path, but fall back to the absolute path when the
|
|
54
|
+
// target is outside the current directory (avoids a wall of "../").
|
|
55
|
+
const where = rel === "" ? "." : rel.startsWith("..") ? cwd : rel;
|
|
56
|
+
process.stderr.write(`\n\x1b[32m✓\x1b[0m Scenar demos project ready in ${where}/\n`);
|
|
57
|
+
if (!installRan) {
|
|
58
|
+
process.stderr.write(` \x1b[33m●\x1b[0m Install skipped — run your package manager before packing.\n`);
|
|
59
|
+
}
|
|
60
|
+
process.stderr.write(` Next:\n`);
|
|
61
|
+
process.stderr.write(` 1. \`scenar pack tours/example-tour\` to preview the starter tour.\n`);
|
|
62
|
+
process.stderr.write(` 2. Edit tours/example-tour/index.tsx — swap the shells for your\n`);
|
|
63
|
+
process.stderr.write(` real components (add them with \`scenar install <your-pkg>\`).\n`);
|
|
64
|
+
process.stderr.write(` 3. Wire any data they fetch in tours/example-tour/.scenar/providers.tsx.\n`);
|
|
65
|
+
process.stderr.write(` 4. \`scenar pack\` then \`scenar publish\` to ship the embed.\n`);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/commands/install.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,UAAU,EAAuB,MAAM,2BAA2B,CAAC;AAQ5E,MAAM,gBAAgB,GAA8B,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE5E,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CACV,mDAAmD;QACjD,8DAA8D;QAC9D,iEAAiE;QACjE,sEAAsE;QACtE,uEAAuE;QACvE,+CAA+C;QAC/C,uEAAuE;QACvE,kEAAkE;QAClE,iEAAiE;QACjE,uEAAuE;QACvE,4BAA4B;QAC5B,wEAAwE;QACxE,yCAAyC,CAC5C;SACA,QAAQ,CACP,eAAe,EACf,iEAAiE,CAClE;SACA,MAAM,CAAC,cAAc,EAAE,gDAAgD,CAAC;SACxE,MAAM,CAAC,cAAc,EAAE,uDAAuD,CAAC;SAC/E,MAAM,CACL,wBAAwB,EACxB,mDAAmD,CACpD;SACA,MAAM,CAAC,KAAK,EAAE,QAAkB,EAAE,OAA8B,EAAE,EAAE;QACnE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YAEvD,MAAM,aAAa,GAAG,UAAU,CAAC;gBAC/B,GAAG;gBACH,QAAQ,EAAE,QAAQ,IAAI,EAAE;gBACxB,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC;gBAClD,WAAW,EAAE,OAAO,CAAC,OAAO,KAAK,KAAK;gBACtC,cAAc,EAAE,mBAAmB,CAAC,OAAO,CAAC,cAAc,CAAC;aAC5D,CAAC,CAAC;YAEH,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAAC;YACvD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAyB;IACpD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAK,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,KAAuB,CAAC;IACjC,CAAC;IACD,MAAM,IAAI,KAAK,CACb,8BAA8B,KAAK,sBAAsB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACxF,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,GAAW,EAAE,UAAmB;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,4EAA4E;IAC5E,oEAAoE;IACpE,MAAM,KAAK,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAClE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oDAAoD,KAAK,KAAK,CAAC,CAAC;IACrF,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iFAAiF,CAClF,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0EAA0E,CAAC,CAAC;IACjG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;IAC9F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAChG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gFAAgF,CAAC,CAAC;IACvG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qEAAqE,CAAC,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { runInstall, type PackageManager } from "../install/run-install.js";
|
|
4
|
+
|
|
5
|
+
interface InstallCommandOptions {
|
|
6
|
+
dir?: string;
|
|
7
|
+
install?: boolean; // commander sets this to false for --no-install
|
|
8
|
+
packageManager?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const PACKAGE_MANAGERS: readonly PackageManager[] = ["npm", "yarn", "pnpm"];
|
|
12
|
+
|
|
13
|
+
export function registerInstallCommand(program: Command): void {
|
|
14
|
+
program
|
|
15
|
+
.command("install")
|
|
16
|
+
.description(
|
|
17
|
+
"Bootstrap a Scenar demos project in one step.\n\n" +
|
|
18
|
+
"Scaffolds a package.json and a runnable starter tour under\n" +
|
|
19
|
+
"tours/example-tour/ if the directory is empty, adds the given\n" +
|
|
20
|
+
"component packages as ordinary dependencies, and runs your package\n" +
|
|
21
|
+
"manager. Re-run any time — existing files are never overwritten, so\n" +
|
|
22
|
+
"your authored tours are always preserved.\n\n" +
|
|
23
|
+
"Component packages are consumed as normal dependencies — import and\n" +
|
|
24
|
+
"compose them into the tours you author under tours/. Specs are\n" +
|
|
25
|
+
"resolver-agnostic: a registry version (@stigmer/react@1.2.0),\n" +
|
|
26
|
+
"workspace:*, file:../pkg, or a git URL all work; resolution is your\n" +
|
|
27
|
+
"package manager's job.\n\n" +
|
|
28
|
+
"Inside a monorepo, the project is detected as a workspace member and\n" +
|
|
29
|
+
"the install runs at the workspace root.",
|
|
30
|
+
)
|
|
31
|
+
.argument(
|
|
32
|
+
"[packages...]",
|
|
33
|
+
"component packages to add as dependencies (e.g. @stigmer/react)",
|
|
34
|
+
)
|
|
35
|
+
.option("--dir <path>", "project directory (default: current directory)")
|
|
36
|
+
.option("--no-install", "scaffold and record dependencies but skip the install")
|
|
37
|
+
.option(
|
|
38
|
+
"--package-manager <pm>",
|
|
39
|
+
"force npm | yarn | pnpm instead of auto-detecting",
|
|
40
|
+
)
|
|
41
|
+
.action(async (packages: string[], options: InstallCommandOptions) => {
|
|
42
|
+
try {
|
|
43
|
+
const cwd = path.resolve(options.dir ?? process.cwd());
|
|
44
|
+
|
|
45
|
+
const installResult = runInstall({
|
|
46
|
+
cwd,
|
|
47
|
+
packages: packages ?? [],
|
|
48
|
+
onLog: (line) => process.stderr.write(`${line}\n`),
|
|
49
|
+
skipInstall: options.install === false,
|
|
50
|
+
packageManager: parsePackageManager(options.packageManager),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
printNextSteps(cwd, installResult.installRan);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
56
|
+
process.stderr.write(`\x1b[31mError:\x1b[0m ${msg}\n`);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function parsePackageManager(value: string | undefined): PackageManager | undefined {
|
|
63
|
+
if (value === undefined) return undefined;
|
|
64
|
+
if ((PACKAGE_MANAGERS as readonly string[]).includes(value)) {
|
|
65
|
+
return value as PackageManager;
|
|
66
|
+
}
|
|
67
|
+
throw new Error(
|
|
68
|
+
`invalid --package-manager "${value}"; expected one of ${PACKAGE_MANAGERS.join(", ")}.`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function printNextSteps(cwd: string, installRan: boolean): void {
|
|
73
|
+
const rel = path.relative(process.cwd(), cwd);
|
|
74
|
+
// Prefer a short relative path, but fall back to the absolute path when the
|
|
75
|
+
// target is outside the current directory (avoids a wall of "../").
|
|
76
|
+
const where = rel === "" ? "." : rel.startsWith("..") ? cwd : rel;
|
|
77
|
+
process.stderr.write(`\n\x1b[32m✓\x1b[0m Scenar demos project ready in ${where}/\n`);
|
|
78
|
+
if (!installRan) {
|
|
79
|
+
process.stderr.write(
|
|
80
|
+
` \x1b[33m●\x1b[0m Install skipped — run your package manager before packing.\n`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
process.stderr.write(` Next:\n`);
|
|
84
|
+
process.stderr.write(` 1. \`scenar pack tours/example-tour\` to preview the starter tour.\n`);
|
|
85
|
+
process.stderr.write(` 2. Edit tours/example-tour/index.tsx — swap the shells for your\n`);
|
|
86
|
+
process.stderr.write(` real components (add them with \`scenar install <your-pkg>\`).\n`);
|
|
87
|
+
process.stderr.write(` 3. Wire any data they fetch in tours/example-tour/.scenar/providers.tsx.\n`);
|
|
88
|
+
process.stderr.write(` 4. \`scenar pack\` then \`scenar publish\` to ship the embed.\n`);
|
|
89
|
+
}
|
package/src/commands/pack.js
CHANGED
|
@@ -8,11 +8,11 @@ export function registerPackCommand(program) {
|
|
|
8
8
|
program
|
|
9
9
|
.command("pack")
|
|
10
10
|
.description("Bundle a scenario into a self-contained, hosted embed.\n\n" +
|
|
11
|
-
"Accepts the same scenario directory as `render
|
|
11
|
+
"Accepts the same scenario directory as `render`\n" +
|
|
12
12
|
"(steps.ts + an index.tsx that exports renderStep, plus an\n" +
|
|
13
13
|
"optional .scenar/providers.tsx and narration/). Produces a static\n" +
|
|
14
14
|
"bundle that boots ScenarioPlayer in the browser, ready for\n" +
|
|
15
|
-
"`scenar serve
|
|
15
|
+
"`scenar serve` or `scenar publish`.\n\n" +
|
|
16
16
|
"The bundle contains index.html, hashed JS/CSS, a scenario.json\n" +
|
|
17
17
|
"descriptor, and a pack-manifest.json listing every file with its\n" +
|
|
18
18
|
"lowercase-hex sha256 and content type. Output stays within the\n" +
|
package/src/commands/pack.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../../../src/commands/pack.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,yEAAyE;AACzE,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC;AAE7C,0CAA0C;AAC1C,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,MAAM,CAAC;AASrD,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CACV,4DAA4D;QAC1D,
|
|
1
|
+
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../../../src/commands/pack.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,yEAAyE;AACzE,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC;AAE7C,0CAA0C;AAC1C,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,MAAM,CAAC;AASrD,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CACV,4DAA4D;QAC1D,mDAAmD;QACnD,6DAA6D;QAC7D,qEAAqE;QACrE,8DAA8D;QAC9D,yCAAyC;QACzC,kEAAkE;QAClE,oEAAoE;QACpE,kEAAkE;QAClE,oEAAoE;QACpE,oEAAoE;QACpE,yDAAyD;QACzD,mEAAmE,CACtE;SACA,QAAQ,CAAC,OAAO,EAAE,sDAAsD,CAAC;SACzE,MAAM,CAAC,cAAc,EAAE,iCAAiC,CAAC;SACzD,MAAM,CAAC,kBAAkB,EAAE,4CAA4C,aAAa,GAAG,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;SAC/G,MAAM,CACL,yBAAyB,EACzB,gCAAgC,oBAAoB,GAAG,EACvD,MAAM,CAAC,oBAAoB,CAAC,CAC7B;SACA,MAAM,CAAC,aAAa,EAAE,kDAAkD,CAAC;SACzE,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,OAAoB,EAAE,EAAE;QAClD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;gBAC3B,WAAW,EAAE,GAAG;gBAChB,MAAM,EAAE,OAAO,CAAC,GAAG;gBACnB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,aAAa;gBAC7C,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,oBAAoB;gBAChE,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC;aACzD,CAAC,CAAC;YAEH,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6BAA6B,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS;gBAChE,IAAI,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,MAAM,CAAC,MAAM,IAAI,CAC9D,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAAC;YACvD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IACnE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AACrD,CAAC"}
|