trend2trial 0.1.1 → 1.0.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/dist/__tests__/cli-integration.test.d.ts +2 -0
- package/dist/__tests__/cli-integration.test.d.ts.map +1 -0
- package/dist/__tests__/cli-integration.test.js +117 -0
- package/dist/__tests__/cli-integration.test.js.map +1 -0
- package/dist/__tests__/e2e-smoke.test.d.ts +2 -0
- package/dist/__tests__/e2e-smoke.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-smoke.test.js +66 -0
- package/dist/__tests__/e2e-smoke.test.js.map +1 -0
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +6 -5
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/recipe.d.ts +5 -1
- package/dist/commands/recipe.d.ts.map +1 -1
- package/dist/commands/recipe.js +71 -23
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/trends.d.ts +6 -0
- package/dist/commands/trends.d.ts.map +1 -0
- package/dist/commands/trends.js +40 -0
- package/dist/commands/trends.js.map +1 -0
- package/dist/main.js +128 -33
- package/dist/main.js.map +1 -1
- package/dist/ui.d.ts +27 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +71 -0
- package/dist/ui.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli-integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { resolve, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const CLI_BIN = resolve(__dirname, "../../bin/trend2trial.js");
|
|
7
|
+
function run(args, timeoutMs = 10000) {
|
|
8
|
+
return new Promise((res) => {
|
|
9
|
+
const child = execFile("node", [CLI_BIN, ...args], { timeout: timeoutMs, env: { ...process.env, NO_COLOR: "1" } }, (error, stdout, stderr) => {
|
|
10
|
+
const exitCode = error ? (child.exitCode ?? 1) : 0;
|
|
11
|
+
res({ stdout, stderr, exitCode });
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
describe("CLI --version", () => {
|
|
16
|
+
it("prints version string and exits 0", async () => {
|
|
17
|
+
const { stdout, exitCode } = await run(["--version"]);
|
|
18
|
+
expect(exitCode).toBe(0);
|
|
19
|
+
expect(stdout).toMatch(/^trend2trial v\d+\.\d+\.\d+/);
|
|
20
|
+
});
|
|
21
|
+
it("also works with -v short flag", async () => {
|
|
22
|
+
const { stdout, exitCode } = await run(["-v"]);
|
|
23
|
+
expect(exitCode).toBe(0);
|
|
24
|
+
expect(stdout).toMatch(/^trend2trial v/);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe("CLI --help", () => {
|
|
28
|
+
it("prints help text and exits 0", async () => {
|
|
29
|
+
const { stdout, exitCode } = await run(["--help"]);
|
|
30
|
+
expect(exitCode).toBe(0);
|
|
31
|
+
expect(stdout).toContain("trend2trial");
|
|
32
|
+
expect(stdout).toContain("Usage:");
|
|
33
|
+
expect(stdout).toContain("Commands:");
|
|
34
|
+
expect(stdout).toContain("build");
|
|
35
|
+
expect(stdout).toContain("recipe");
|
|
36
|
+
expect(stdout).toContain("trends");
|
|
37
|
+
});
|
|
38
|
+
it("also works with -h short flag", async () => {
|
|
39
|
+
const { stdout, exitCode } = await run(["-h"]);
|
|
40
|
+
expect(exitCode).toBe(0);
|
|
41
|
+
expect(stdout).toContain("Usage:");
|
|
42
|
+
});
|
|
43
|
+
it("shows help when called with no arguments", async () => {
|
|
44
|
+
const { stdout, exitCode } = await run([]);
|
|
45
|
+
expect(exitCode).toBe(0);
|
|
46
|
+
expect(stdout).toContain("Usage:");
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe("CLI unknown command", () => {
|
|
50
|
+
it("exits with code 2 for unknown command", async () => {
|
|
51
|
+
const { exitCode, stderr } = await run(["foobar"]);
|
|
52
|
+
expect(exitCode).toBe(2);
|
|
53
|
+
expect(stderr).toContain("Unknown command: foobar");
|
|
54
|
+
});
|
|
55
|
+
it("suggests similar command on typo", async () => {
|
|
56
|
+
const { exitCode, stderr } = await run(["bild"]);
|
|
57
|
+
expect(exitCode).toBe(2);
|
|
58
|
+
expect(stderr).toContain("Did you mean");
|
|
59
|
+
expect(stderr).toContain("build");
|
|
60
|
+
});
|
|
61
|
+
it("exits with code 2 for unknown recipe subcommand", async () => {
|
|
62
|
+
const { exitCode, stderr } = await run(["recipe", "foobar"]);
|
|
63
|
+
expect(exitCode).toBe(2);
|
|
64
|
+
expect(stderr).toContain("Unknown recipe subcommand: foobar");
|
|
65
|
+
});
|
|
66
|
+
it("suggests similar recipe subcommand on typo", async () => {
|
|
67
|
+
const { exitCode, stderr } = await run(["recipe", "lst"]);
|
|
68
|
+
expect(exitCode).toBe(2);
|
|
69
|
+
expect(stderr).toContain("Did you mean");
|
|
70
|
+
expect(stderr).toContain("list");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe("CLI recipe list", () => {
|
|
74
|
+
it("lists available recipes", async () => {
|
|
75
|
+
const { stdout, exitCode } = await run(["recipe", "list"]);
|
|
76
|
+
expect(exitCode).toBe(0);
|
|
77
|
+
// Should show at least the known recipes from local repo
|
|
78
|
+
expect(stdout).toContain("serving-latency");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe("CLI recipe init — validation", () => {
|
|
82
|
+
it("exits with code 2 when name is missing", async () => {
|
|
83
|
+
const { exitCode, stderr } = await run(["recipe", "init"]);
|
|
84
|
+
expect(exitCode).toBe(2);
|
|
85
|
+
expect(stderr).toContain("Missing arguments");
|
|
86
|
+
});
|
|
87
|
+
it("exits with code 2 when dest is missing", async () => {
|
|
88
|
+
const { exitCode, stderr } = await run(["recipe", "init", "serving-latency"]);
|
|
89
|
+
expect(exitCode).toBe(2);
|
|
90
|
+
expect(stderr).toContain("Missing arguments");
|
|
91
|
+
});
|
|
92
|
+
it("exits with code 2 for invalid recipe name", async () => {
|
|
93
|
+
const { exitCode, stderr } = await run(["recipe", "init", "INVALID_NAME!", "/tmp/test"]);
|
|
94
|
+
expect(exitCode).toBe(2);
|
|
95
|
+
expect(stderr).toContain("Invalid recipe name");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("CLI recipe run — validation", () => {
|
|
99
|
+
it("exits with code 2 when dest is missing", async () => {
|
|
100
|
+
const { exitCode, stderr } = await run(["recipe", "run"]);
|
|
101
|
+
expect(exitCode).toBe(2);
|
|
102
|
+
expect(stderr).toContain("Missing argument");
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe("CLI trends — validation", () => {
|
|
106
|
+
it("exits with code 2 for unknown trends subcommand", async () => {
|
|
107
|
+
const { exitCode, stderr } = await run(["trends", "foobar"]);
|
|
108
|
+
expect(exitCode).toBe(2);
|
|
109
|
+
expect(stderr).toContain("Unknown trends subcommand: foobar");
|
|
110
|
+
});
|
|
111
|
+
it("exits with code 2 when no subcommand given", async () => {
|
|
112
|
+
const { exitCode, stderr } = await run(["trends"]);
|
|
113
|
+
expect(exitCode).toBe(2);
|
|
114
|
+
expect(stderr).toContain("Unknown trends subcommand: (none)");
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=cli-integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2e-smoke.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/e2e-smoke.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { mkdtemp, rm, readFile, stat } from "node:fs/promises";
|
|
4
|
+
import { join, resolve, dirname } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const CLI_BIN = resolve(__dirname, "../../bin/trend2trial.js");
|
|
9
|
+
function run(args, timeoutMs = 30000) {
|
|
10
|
+
return new Promise((res) => {
|
|
11
|
+
const child = execFile("node", [CLI_BIN, ...args], { timeout: timeoutMs, env: { ...process.env, NO_COLOR: "1" } }, (error, stdout, stderr) => {
|
|
12
|
+
const exitCode = error ? (child.exitCode ?? 1) : 0;
|
|
13
|
+
res({ stdout, stderr, exitCode });
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
describe("E2E: recipe init -> run -> REPORT.md", () => {
|
|
18
|
+
let tempDir;
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
tempDir = await mkdtemp(join(tmpdir(), "t2t-e2e-"));
|
|
21
|
+
});
|
|
22
|
+
afterEach(async () => {
|
|
23
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
24
|
+
});
|
|
25
|
+
it("initializes, runs, and produces REPORT.md for serving-latency", async () => {
|
|
26
|
+
const dest = join(tempDir, "my-trial");
|
|
27
|
+
// Step 1: recipe init
|
|
28
|
+
const initResult = await run(["recipe", "init", "serving-latency", dest]);
|
|
29
|
+
expect(initResult.exitCode).toBe(0);
|
|
30
|
+
expect(initResult.stdout).toContain("initialized at");
|
|
31
|
+
// Verify scaffold was copied
|
|
32
|
+
const tasksYaml = await stat(join(dest, "tasks.yaml"));
|
|
33
|
+
expect(tasksYaml.isFile()).toBe(true);
|
|
34
|
+
const rubricYaml = await stat(join(dest, "rubric.yaml"));
|
|
35
|
+
expect(rubricYaml.isFile()).toBe(true);
|
|
36
|
+
const scaffoldDir = await stat(join(dest, "scaffold"));
|
|
37
|
+
expect(scaffoldDir.isDirectory()).toBe(true);
|
|
38
|
+
// Step 2: recipe run with --yes (no interactive prompt)
|
|
39
|
+
const runResult = await run(["recipe", "run", dest, "--yes"], 60000);
|
|
40
|
+
// The recipe may or may not fully succeed depending on environment,
|
|
41
|
+
// but REPORT.md should always be generated
|
|
42
|
+
// exitCode 0 = all steps passed, exitCode 3 = some steps failed
|
|
43
|
+
expect([0, 3]).toContain(runResult.exitCode);
|
|
44
|
+
expect(runResult.stdout).toContain("Report written to");
|
|
45
|
+
// Step 3: verify REPORT.md exists and has content
|
|
46
|
+
const reportPath = join(dest, "REPORT.md");
|
|
47
|
+
const reportStat = await stat(reportPath);
|
|
48
|
+
expect(reportStat.isFile()).toBe(true);
|
|
49
|
+
const reportContent = await readFile(reportPath, "utf-8");
|
|
50
|
+
expect(reportContent).toContain("Serving Latency Benchmark");
|
|
51
|
+
expect(reportContent).toContain("# REPORT");
|
|
52
|
+
}, 90000);
|
|
53
|
+
it("recipe init creates a directory with expected files", async () => {
|
|
54
|
+
const dest = join(tempDir, "quick-trial");
|
|
55
|
+
const result = await run(["recipe", "init", "serving-latency", dest]);
|
|
56
|
+
expect(result.exitCode).toBe(0);
|
|
57
|
+
// Verify key files
|
|
58
|
+
const tasks = await readFile(join(dest, "tasks.yaml"), "utf-8");
|
|
59
|
+
expect(tasks).toContain("serving-latency");
|
|
60
|
+
expect(tasks).toContain("tasks:");
|
|
61
|
+
const rubric = await readFile(join(dest, "rubric.yaml"), "utf-8");
|
|
62
|
+
expect(rubric).toContain("metrics:");
|
|
63
|
+
expect(rubric).toContain("pass_criteria:");
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=e2e-smoke.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2e-smoke.test.js","sourceRoot":"","sources":["../../src/__tests__/e2e-smoke.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAKA,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBpF"}
|
package/dist/commands/build.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { loadTrendsFromFile, renderCardToMarkdown, renderCardsToList } from "trend2trial-core";
|
|
4
|
+
import { pathStr, success, header, dim, createSpinner } from "../ui.js";
|
|
4
5
|
export async function buildCards(inputPath, outputDir) {
|
|
5
6
|
const absInput = resolve(inputPath);
|
|
6
7
|
const absOutput = resolve(outputDir);
|
|
7
|
-
|
|
8
|
+
const spinner = createSpinner(`Reading trends from ${pathStr(absInput)}`);
|
|
8
9
|
const cards = await loadTrendsFromFile(absInput);
|
|
9
|
-
|
|
10
|
+
spinner.stop(`Found ${header(String(cards.length))} valid trend cards`);
|
|
10
11
|
await mkdir(absOutput, { recursive: true });
|
|
11
12
|
for (const card of cards) {
|
|
12
13
|
const filePath = join(absOutput, `${card.id}.md`);
|
|
13
14
|
await writeFile(filePath, renderCardToMarkdown(card), "utf-8");
|
|
14
|
-
console.log(` → ${filePath}`);
|
|
15
|
+
console.log(` ${dim("→")} ${pathStr(filePath)}`);
|
|
15
16
|
}
|
|
16
17
|
const indexPath = join(absOutput, "INDEX.md");
|
|
17
18
|
await writeFile(indexPath, renderCardsToList(cards), "utf-8");
|
|
18
|
-
console.log(` → ${indexPath}`);
|
|
19
|
-
console.log(`\
|
|
19
|
+
console.log(` ${dim("→")} ${pathStr(indexPath)}`);
|
|
20
|
+
console.log(`\n${success("Done!")} Generated ${header(String(cards.length))} cards + INDEX.md in ${pathStr(absOutput)}`);
|
|
20
21
|
}
|
|
21
22
|
//# sourceMappingURL=build.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAExE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,SAAiB,EAAE,SAAiB;IACnE,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAErC,MAAM,OAAO,GAAG,aAAa,CAAC,uBAAuB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACjD,OAAO,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC;IAExE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;QAClD,MAAM,SAAS,CAAC,QAAQ,EAAE,oBAAoB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC9C,MAAM,SAAS,CAAC,SAAS,EAAE,iBAAiB,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAEnD,OAAO,CAAC,GAAG,CACT,KAAK,OAAO,CAAC,OAAO,CAAC,cAAc,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,wBAAwB,OAAO,CAAC,SAAS,CAAC,EAAE,CAC5G,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export declare function recipeList(root: string | undefined): Promise<void>;
|
|
2
2
|
export declare function recipeInit(root: string | undefined, name: string, dest: string): Promise<void>;
|
|
3
|
-
export
|
|
3
|
+
export interface RecipeRunFlags {
|
|
4
|
+
yes?: boolean;
|
|
5
|
+
noFailFast?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function recipeRun(dest: string, flags?: RecipeRunFlags): Promise<void>;
|
|
4
8
|
//# sourceMappingURL=recipe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recipe.d.ts","sourceRoot":"","sources":["../../src/commands/recipe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"recipe.d.ts","sourceRoot":"","sources":["../../src/commands/recipe.ts"],"names":[],"mappings":"AA2BA,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCxE;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAqBf;AAYD,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDvF"}
|
package/dist/commands/recipe.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
2
3
|
import { writeFile } from "node:fs/promises";
|
|
3
|
-
import { copyScaffold, runRecipe, loadRecipe, generateReport, findLocalRecipesDir, resolveRecipeList, resolveRecipeDir, } from "trend2trial-core";
|
|
4
|
+
import { copyScaffold, runRecipe, loadRecipe, generateReport, findLocalRecipesDir, resolveRecipeList, resolveRecipeDir, previewCommands, } from "trend2trial-core";
|
|
5
|
+
import { EXIT_RECIPE_FAIL, pathStr, success, error, header, dim, categoryBadge, exitWithUsageError, createSpinner, } from "../ui.js";
|
|
6
|
+
const RECIPE_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
4
7
|
export async function recipeList(root) {
|
|
5
8
|
const localRecipesDir = findLocalRecipesDir(root);
|
|
6
9
|
const recipes = await resolveRecipeList({ localRecipesDir });
|
|
@@ -9,49 +12,94 @@ export async function recipeList(root) {
|
|
|
9
12
|
return;
|
|
10
13
|
}
|
|
11
14
|
console.log("");
|
|
12
|
-
console.log("Available recipes:");
|
|
15
|
+
console.log(header("Available recipes:"));
|
|
13
16
|
console.log("");
|
|
14
|
-
console.log("Name".padEnd(35) +
|
|
15
|
-
"Category".padEnd(12) +
|
|
16
|
-
"Hours".padEnd(8) +
|
|
17
|
-
"Title");
|
|
18
|
-
console.log("-".repeat(80));
|
|
17
|
+
console.log(header("Name".padEnd(35)) +
|
|
18
|
+
header("Category".padEnd(12)) +
|
|
19
|
+
header("Hours".padEnd(8)) +
|
|
20
|
+
header("Title"));
|
|
21
|
+
console.log(dim("-".repeat(80)));
|
|
19
22
|
for (const r of recipes) {
|
|
20
23
|
console.log(r.name.padEnd(35) +
|
|
21
|
-
r.category.padEnd(12) +
|
|
22
|
-
r.estimated_hours.padEnd(8) +
|
|
24
|
+
categoryBadge(r.category).padEnd(12 + (categoryBadge(r.category).length - r.category.length)) +
|
|
25
|
+
dim(r.estimated_hours).padEnd(8 + (dim(r.estimated_hours).length - r.estimated_hours.length)) +
|
|
23
26
|
r.title);
|
|
24
27
|
}
|
|
25
28
|
console.log("");
|
|
26
29
|
}
|
|
27
30
|
export async function recipeInit(root, name, dest) {
|
|
31
|
+
if (!RECIPE_NAME_RE.test(name)) {
|
|
32
|
+
exitWithUsageError(`Invalid recipe name "${name}". Names must match [a-z0-9-] (e.g. "serving-latency").`);
|
|
33
|
+
}
|
|
34
|
+
const absDest = resolve(dest);
|
|
35
|
+
if (absDest.includes("\0")) {
|
|
36
|
+
exitWithUsageError(`Invalid destination path: "${dest}"`);
|
|
37
|
+
}
|
|
28
38
|
const localRecipesDir = findLocalRecipesDir(root);
|
|
29
39
|
const recipeDir = await resolveRecipeDir(name, { localRecipesDir });
|
|
30
|
-
const absDest = resolve(dest);
|
|
31
40
|
await copyScaffold(recipeDir, absDest);
|
|
32
|
-
console.log(`Recipe "${name}" initialized at ${absDest}`);
|
|
41
|
+
console.log(success(`Recipe "${name}" initialized at ${pathStr(absDest)}`));
|
|
33
42
|
console.log("");
|
|
34
|
-
console.log("Next steps:");
|
|
35
|
-
console.log(` cd ${absDest}`);
|
|
36
|
-
console.log(` trend2trial recipe run ${absDest}`);
|
|
43
|
+
console.log(header("Next steps:"));
|
|
44
|
+
console.log(` cd ${pathStr(absDest)}`);
|
|
45
|
+
console.log(` trend2trial recipe run ${pathStr(absDest)}`);
|
|
37
46
|
}
|
|
38
|
-
|
|
47
|
+
function askConfirmation(question) {
|
|
48
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
rl.question(question, (answer) => {
|
|
51
|
+
rl.close();
|
|
52
|
+
resolve(answer.toLowerCase() === "y");
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
export async function recipeRun(dest, flags = {}) {
|
|
39
57
|
const absDest = resolve(dest);
|
|
40
|
-
|
|
58
|
+
if (absDest.includes("\0")) {
|
|
59
|
+
exitWithUsageError(`Invalid destination path: "${dest}"`);
|
|
60
|
+
}
|
|
61
|
+
const recipe = await loadRecipe(absDest);
|
|
62
|
+
const commands = previewCommands(recipe);
|
|
63
|
+
console.log(`Recipe ${header(recipe.title)} will run ${header(String(commands.length))} commands:`);
|
|
41
64
|
console.log("");
|
|
42
|
-
const
|
|
65
|
+
for (const cmd of commands) {
|
|
66
|
+
console.log(` ${dim("$")} ${cmd}`);
|
|
67
|
+
}
|
|
68
|
+
console.log("");
|
|
69
|
+
if (!flags.yes) {
|
|
70
|
+
const confirmed = await askConfirmation("Proceed? [y/N] ");
|
|
71
|
+
if (!confirmed) {
|
|
72
|
+
console.log("Aborted.");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.log("");
|
|
76
|
+
}
|
|
77
|
+
const spinner = createSpinner("Running recipe steps...");
|
|
78
|
+
const result = await runRecipe(absDest, {
|
|
79
|
+
confirmed: true,
|
|
80
|
+
failFast: !flags.noFailFast,
|
|
81
|
+
});
|
|
82
|
+
spinner.stop();
|
|
83
|
+
let hasFailure = false;
|
|
43
84
|
for (const step of result.steps) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
85
|
+
if (step.exitCode === 0) {
|
|
86
|
+
console.log(` ${success("[OK]")} ${header(step.name)} ${dim(`(${step.durationMs}ms)`)}`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
hasFailure = true;
|
|
90
|
+
console.log(` ${error("[FAIL]")} ${header(step.name)} ${dim(`(${step.durationMs}ms)`)}`);
|
|
91
|
+
if (step.stderr) {
|
|
92
|
+
console.log(` ${dim("stderr:")} ${step.stderr.slice(0, 200)}`);
|
|
93
|
+
}
|
|
48
94
|
}
|
|
49
95
|
}
|
|
50
96
|
console.log("");
|
|
51
|
-
const recipe = await loadRecipe(absDest);
|
|
52
97
|
const report = generateReport(recipe, result);
|
|
53
98
|
const reportPath = resolve(absDest, "REPORT.md");
|
|
54
99
|
await writeFile(reportPath, report, "utf-8");
|
|
55
|
-
console.log(`Report written to ${reportPath}`);
|
|
100
|
+
console.log(`Report written to ${pathStr(reportPath)}`);
|
|
101
|
+
if (hasFailure) {
|
|
102
|
+
process.exit(EXIT_RECIPE_FAIL);
|
|
103
|
+
}
|
|
56
104
|
}
|
|
57
105
|
//# sourceMappingURL=recipe.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recipe.js","sourceRoot":"","sources":["../../src/commands/recipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,SAAS,EACT,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"recipe.js","sourceRoot":"","sources":["../../src/commands/recipe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trends.d.ts","sourceRoot":"","sources":["../../src/commands/trends.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,WAAW,CAAC,KAAK,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB7E"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { fetchTrendCards, writeTrends } from "trend2trial-core";
|
|
3
|
+
import { pathStr, success, header, dim, categoryBadge, createSpinner } from "../ui.js";
|
|
4
|
+
export async function trendsFetch(flags = {}) {
|
|
5
|
+
const spinner = createSpinner("Fetching trends from adapters...");
|
|
6
|
+
const cards = await fetchTrendCards();
|
|
7
|
+
spinner.stop(`Fetched ${header(String(cards.length))} trend cards`);
|
|
8
|
+
if (flags.output) {
|
|
9
|
+
const absOutput = resolve(flags.output);
|
|
10
|
+
await writeTrends(cards, absOutput);
|
|
11
|
+
console.log(`${success("Saved")} trends to ${pathStr(absOutput)}`);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (flags.json) {
|
|
15
|
+
console.log(JSON.stringify(cards, null, 2));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
printTrendsTable(cards);
|
|
19
|
+
}
|
|
20
|
+
function printTrendsTable(cards) {
|
|
21
|
+
if (cards.length === 0) {
|
|
22
|
+
console.log("No trends found.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log("");
|
|
26
|
+
console.log(header("Score".padEnd(8)) +
|
|
27
|
+
header("Category".padEnd(12)) +
|
|
28
|
+
header("Date".padEnd(13)) +
|
|
29
|
+
header("Title"));
|
|
30
|
+
console.log(dim("-".repeat(80)));
|
|
31
|
+
for (const c of cards) {
|
|
32
|
+
console.log(String(c.relevanceScore).padEnd(8) +
|
|
33
|
+
categoryBadge(c.category).padEnd(12 + (categoryBadge(c.category).length - c.category.length)) +
|
|
34
|
+
dim(c.date).padEnd(13 + (dim(c.date).length - c.date.length)) +
|
|
35
|
+
c.title);
|
|
36
|
+
}
|
|
37
|
+
console.log("");
|
|
38
|
+
console.log(dim(`${cards.length} trends total`));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=trends.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trends.js","sourceRoot":"","sources":["../../src/commands/trends.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEhE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAOvF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAA0B,EAAE;IAC5D,MAAM,OAAO,GAAG,aAAa,CAAC,kCAAkC,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAEpE,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACnE,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,gBAAgB,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAkB;IAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzB,MAAM,CAAC,OAAO,CAAC,CAClB,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YAChC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAC9B,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC5D;YACD,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7D,CAAC,CAAC,KAAK,CACV,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,eAAe,CAAC,CAAC,CAAC;AACnD,CAAC"}
|
package/dist/main.js
CHANGED
|
@@ -1,43 +1,96 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
2
|
import { resolve, dirname } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { buildCards } from "./commands/build.js";
|
|
6
6
|
import { recipeList, recipeInit, recipeRun } from "./commands/recipe.js";
|
|
7
|
+
import { trendsFetch } from "./commands/trends.js";
|
|
8
|
+
import pc from "picocolors";
|
|
9
|
+
import { EXIT_SUCCESS, EXIT_INTERNAL, EXIT_USAGE, header, dim, printError } from "./ui.js";
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
/** Read CLI version from package.json at build-relative path. */
|
|
12
|
+
function getVersion() {
|
|
13
|
+
const pkgPath = resolve(__dirname, "../package.json");
|
|
14
|
+
try {
|
|
15
|
+
const raw = readFileSync(pkgPath, "utf-8");
|
|
16
|
+
const pkg = JSON.parse(raw);
|
|
17
|
+
return pkg.version;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return "unknown";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
7
23
|
/**
|
|
8
24
|
* Attempt to find the monorepo root (for local dev / cloned repo).
|
|
9
25
|
* Returns undefined when running via npx (no local recipes/ dir).
|
|
10
26
|
*/
|
|
11
27
|
function findLocalRoot() {
|
|
12
28
|
// CLI dist lives at packages/cli/dist — root is three levels up
|
|
13
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
29
|
const candidate = resolve(__dirname, "../../..");
|
|
15
30
|
if (existsSync(resolve(candidate, "recipes"))) {
|
|
16
31
|
return candidate;
|
|
17
32
|
}
|
|
18
33
|
return undefined;
|
|
19
34
|
}
|
|
35
|
+
const KNOWN_COMMANDS = ["build", "recipe", "trends"];
|
|
36
|
+
const KNOWN_RECIPE_SUBS = ["list", "init", "run"];
|
|
37
|
+
function levenshtein(a, b) {
|
|
38
|
+
const m = a.length;
|
|
39
|
+
const n = b.length;
|
|
40
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
41
|
+
for (let i = 0; i <= m; i++)
|
|
42
|
+
dp[i][0] = i;
|
|
43
|
+
for (let j = 0; j <= n; j++)
|
|
44
|
+
dp[0][j] = j;
|
|
45
|
+
for (let i = 1; i <= m; i++) {
|
|
46
|
+
for (let j = 1; j <= n; j++) {
|
|
47
|
+
dp[i][j] =
|
|
48
|
+
a[i - 1] === b[j - 1]
|
|
49
|
+
? dp[i - 1][j - 1]
|
|
50
|
+
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return dp[m][n];
|
|
54
|
+
}
|
|
55
|
+
function suggest(input, candidates) {
|
|
56
|
+
let best;
|
|
57
|
+
let bestDist = Infinity;
|
|
58
|
+
for (const c of candidates) {
|
|
59
|
+
const d = levenshtein(input, c);
|
|
60
|
+
if (d < bestDist && d <= 3) {
|
|
61
|
+
bestDist = d;
|
|
62
|
+
best = c;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return best;
|
|
66
|
+
}
|
|
20
67
|
function printHelp() {
|
|
21
68
|
console.log(`
|
|
22
|
-
trend2trial — Trend Radar + Trial Playground
|
|
69
|
+
${header("trend2trial")} ${dim("— Trend Radar + Trial Playground")}
|
|
23
70
|
|
|
24
|
-
Usage:
|
|
25
|
-
trend2trial build [--input <path>] [--output <dir>]
|
|
26
|
-
trend2trial recipe list
|
|
27
|
-
trend2trial recipe init <name> <dest>
|
|
28
|
-
trend2trial recipe run <dest>
|
|
29
|
-
trend2trial --
|
|
71
|
+
${header("Usage:")}
|
|
72
|
+
trend2trial ${pc.cyan("build")} [--input <path>] [--output <dir>]
|
|
73
|
+
trend2trial ${pc.cyan("recipe list")}
|
|
74
|
+
trend2trial ${pc.cyan("recipe init")} <name> <dest>
|
|
75
|
+
trend2trial ${pc.cyan("recipe run")} <dest> [--yes] [--no-fail-fast]
|
|
76
|
+
trend2trial ${pc.cyan("trends fetch")} [--json] [--output <path>]
|
|
77
|
+
trend2trial ${pc.cyan("--help")} | ${pc.cyan("--version")}
|
|
30
78
|
|
|
31
|
-
Commands:
|
|
32
|
-
build
|
|
33
|
-
recipe list
|
|
34
|
-
recipe init
|
|
35
|
-
recipe run
|
|
79
|
+
${header("Commands:")}
|
|
80
|
+
${pc.cyan("build")} Read trends from JSON and generate Markdown cards
|
|
81
|
+
${pc.cyan("recipe list")} List available recipes
|
|
82
|
+
${pc.cyan("recipe init")} Initialize a recipe into a working directory
|
|
83
|
+
${pc.cyan("recipe run")} Run a recipe and generate REPORT.md
|
|
84
|
+
${pc.cyan("trends fetch")} Fetch latest trends from all adapters
|
|
36
85
|
|
|
37
|
-
Options:
|
|
38
|
-
--input
|
|
39
|
-
--output
|
|
40
|
-
--
|
|
86
|
+
${header("Options:")}
|
|
87
|
+
--input Path to trends JSON file ${dim("(default: data/sample.json)")}
|
|
88
|
+
--output Output directory for cards ${dim("(default: docs/cards)")}
|
|
89
|
+
--json Output trends as JSON ${dim("(trends fetch only)")}
|
|
90
|
+
--yes, -y Skip confirmation prompt for recipe run
|
|
91
|
+
--no-fail-fast Continue running steps after a failure
|
|
92
|
+
--help, -h Show this help message
|
|
93
|
+
--version, -v Show version number
|
|
41
94
|
`);
|
|
42
95
|
}
|
|
43
96
|
async function main() {
|
|
@@ -53,18 +106,39 @@ async function main() {
|
|
|
53
106
|
type: "string",
|
|
54
107
|
default: root ? resolve(root, "docs/cards") : "docs/cards",
|
|
55
108
|
},
|
|
56
|
-
|
|
109
|
+
json: { type: "boolean", default: false },
|
|
110
|
+
yes: { type: "boolean", short: "y", default: false },
|
|
111
|
+
"no-fail-fast": { type: "boolean", default: false },
|
|
112
|
+
help: { type: "boolean", short: "h", default: false },
|
|
113
|
+
version: { type: "boolean", short: "v", default: false },
|
|
57
114
|
},
|
|
58
115
|
});
|
|
116
|
+
if (values.version) {
|
|
117
|
+
console.log(`trend2trial v${getVersion()}`);
|
|
118
|
+
process.exit(EXIT_SUCCESS);
|
|
119
|
+
}
|
|
59
120
|
if (values.help || positionals.length === 0) {
|
|
60
121
|
printHelp();
|
|
61
|
-
process.exit(
|
|
122
|
+
process.exit(EXIT_SUCCESS);
|
|
62
123
|
}
|
|
63
124
|
const command = positionals[0];
|
|
64
125
|
switch (command) {
|
|
65
126
|
case "build":
|
|
66
127
|
await buildCards(values.input, values.output);
|
|
67
128
|
break;
|
|
129
|
+
case "trends": {
|
|
130
|
+
const sub = positionals[1];
|
|
131
|
+
if (sub !== "fetch") {
|
|
132
|
+
printError(`Unknown trends subcommand: ${sub ?? "(none)"}`);
|
|
133
|
+
console.error(`\n Usage: trend2trial trends fetch [--json] [--output <path>]\n`);
|
|
134
|
+
process.exit(EXIT_USAGE);
|
|
135
|
+
}
|
|
136
|
+
await trendsFetch({
|
|
137
|
+
json: values.json,
|
|
138
|
+
output: values.output,
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
68
142
|
case "recipe": {
|
|
69
143
|
const sub = positionals[1];
|
|
70
144
|
switch (sub) {
|
|
@@ -75,8 +149,9 @@ async function main() {
|
|
|
75
149
|
const name = positionals[2];
|
|
76
150
|
const dest = positionals[3];
|
|
77
151
|
if (!name || !dest) {
|
|
78
|
-
|
|
79
|
-
|
|
152
|
+
printError("Missing arguments for recipe init");
|
|
153
|
+
console.error(`\n Usage: trend2trial recipe init <name> <dest>\n`);
|
|
154
|
+
process.exit(EXIT_USAGE);
|
|
80
155
|
}
|
|
81
156
|
await recipeInit(root, name, dest);
|
|
82
157
|
break;
|
|
@@ -84,27 +159,47 @@ async function main() {
|
|
|
84
159
|
case "run": {
|
|
85
160
|
const runDest = positionals[2];
|
|
86
161
|
if (!runDest) {
|
|
87
|
-
|
|
88
|
-
|
|
162
|
+
printError("Missing argument for recipe run");
|
|
163
|
+
console.error(`\n Usage: trend2trial recipe run <dest>\n`);
|
|
164
|
+
process.exit(EXIT_USAGE);
|
|
89
165
|
}
|
|
90
|
-
await recipeRun(runDest
|
|
166
|
+
await recipeRun(runDest, {
|
|
167
|
+
yes: values.yes,
|
|
168
|
+
noFailFast: values["no-fail-fast"],
|
|
169
|
+
});
|
|
91
170
|
break;
|
|
92
171
|
}
|
|
93
|
-
default:
|
|
94
|
-
|
|
172
|
+
default: {
|
|
173
|
+
const hint = sub ? suggest(sub, KNOWN_RECIPE_SUBS) : undefined;
|
|
174
|
+
printError(`Unknown recipe subcommand: ${sub ?? "(none)"}`);
|
|
175
|
+
if (hint)
|
|
176
|
+
console.error(` Did you mean ${pc.cyan(`recipe ${hint}`)}?\n`);
|
|
95
177
|
printHelp();
|
|
96
|
-
process.exit(
|
|
178
|
+
process.exit(EXIT_USAGE);
|
|
179
|
+
}
|
|
97
180
|
}
|
|
98
181
|
break;
|
|
99
182
|
}
|
|
100
|
-
default:
|
|
101
|
-
|
|
183
|
+
default: {
|
|
184
|
+
const hint = suggest(command, KNOWN_COMMANDS);
|
|
185
|
+
printError(`Unknown command: ${command}`);
|
|
186
|
+
if (hint)
|
|
187
|
+
console.error(` Did you mean ${pc.cyan(hint)}?\n`);
|
|
102
188
|
printHelp();
|
|
103
|
-
process.exit(
|
|
189
|
+
process.exit(EXIT_USAGE);
|
|
190
|
+
}
|
|
104
191
|
}
|
|
105
192
|
}
|
|
106
193
|
main().catch((err) => {
|
|
107
|
-
|
|
108
|
-
|
|
194
|
+
if (err instanceof Error) {
|
|
195
|
+
printError(err.message);
|
|
196
|
+
if (process.env["DEBUG"]) {
|
|
197
|
+
console.error(dim(err.stack ?? ""));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
printError(String(err));
|
|
202
|
+
}
|
|
203
|
+
process.exit(EXIT_INTERNAL);
|
|
109
204
|
});
|
|
110
205
|
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Exit code constants following Unix conventions. */
|
|
2
|
+
export declare const EXIT_SUCCESS = 0;
|
|
3
|
+
export declare const EXIT_INTERNAL = 1;
|
|
4
|
+
export declare const EXIT_USAGE = 2;
|
|
5
|
+
export declare const EXIT_RECIPE_FAIL = 3;
|
|
6
|
+
/** Color a file path for terminal display. */
|
|
7
|
+
export declare function pathStr(p: string): string;
|
|
8
|
+
/** Format a success message. */
|
|
9
|
+
export declare function success(msg: string): string;
|
|
10
|
+
/** Format an error message. */
|
|
11
|
+
export declare function error(msg: string): string;
|
|
12
|
+
/** Format a bold header. */
|
|
13
|
+
export declare function header(msg: string): string;
|
|
14
|
+
/** Format a dim/secondary string (e.g. durations). */
|
|
15
|
+
export declare function dim(msg: string): string;
|
|
16
|
+
/** Color a category badge for terminal display. */
|
|
17
|
+
export declare function categoryBadge(category: string): string;
|
|
18
|
+
/** Simple progress spinner for long-running operations. */
|
|
19
|
+
export interface Spinner {
|
|
20
|
+
stop(finalMsg?: string): void;
|
|
21
|
+
}
|
|
22
|
+
export declare function createSpinner(message: string): Spinner;
|
|
23
|
+
/** Print a formatted error to stderr with a red "error:" prefix. */
|
|
24
|
+
export declare function printError(msg: string): void;
|
|
25
|
+
/** Print a formatted error to stderr and exit. */
|
|
26
|
+
export declare function exitWithUsageError(msg: string): never;
|
|
27
|
+
//# sourceMappingURL=ui.d.ts.map
|
package/dist/ui.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAEA,sDAAsD;AACtD,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,8CAA8C;AAC9C,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,gCAAgC;AAChC,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,+BAA+B;AAC/B,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,4BAA4B;AAC5B,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED,sDAAsD;AACtD,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,mDAAmD;AACnD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWtD;AAED,2DAA2D;AAC3D,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAID,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAqBtD;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,kDAAkD;AAClD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAGrD"}
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
/** Exit code constants following Unix conventions. */
|
|
3
|
+
export const EXIT_SUCCESS = 0;
|
|
4
|
+
export const EXIT_INTERNAL = 1;
|
|
5
|
+
export const EXIT_USAGE = 2;
|
|
6
|
+
export const EXIT_RECIPE_FAIL = 3;
|
|
7
|
+
/** Color a file path for terminal display. */
|
|
8
|
+
export function pathStr(p) {
|
|
9
|
+
return pc.cyan(p);
|
|
10
|
+
}
|
|
11
|
+
/** Format a success message. */
|
|
12
|
+
export function success(msg) {
|
|
13
|
+
return pc.green(msg);
|
|
14
|
+
}
|
|
15
|
+
/** Format an error message. */
|
|
16
|
+
export function error(msg) {
|
|
17
|
+
return pc.red(msg);
|
|
18
|
+
}
|
|
19
|
+
/** Format a bold header. */
|
|
20
|
+
export function header(msg) {
|
|
21
|
+
return pc.bold(msg);
|
|
22
|
+
}
|
|
23
|
+
/** Format a dim/secondary string (e.g. durations). */
|
|
24
|
+
export function dim(msg) {
|
|
25
|
+
return pc.dim(msg);
|
|
26
|
+
}
|
|
27
|
+
/** Color a category badge for terminal display. */
|
|
28
|
+
export function categoryBadge(category) {
|
|
29
|
+
switch (category) {
|
|
30
|
+
case "serving":
|
|
31
|
+
return pc.blue(category);
|
|
32
|
+
case "rag":
|
|
33
|
+
return pc.magenta(category);
|
|
34
|
+
case "llmops":
|
|
35
|
+
return pc.yellow(category);
|
|
36
|
+
default:
|
|
37
|
+
return category;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const FRAMES = ["|", "/", "-", "\\"];
|
|
41
|
+
export function createSpinner(message) {
|
|
42
|
+
const isTTY = process.stderr.isTTY;
|
|
43
|
+
if (!isTTY) {
|
|
44
|
+
process.stderr.write(`${message}\n`);
|
|
45
|
+
return { stop() { } };
|
|
46
|
+
}
|
|
47
|
+
let frame = 0;
|
|
48
|
+
const id = setInterval(() => {
|
|
49
|
+
const f = FRAMES[frame % FRAMES.length];
|
|
50
|
+
process.stderr.write(`\r${pc.cyan(f)} ${message}`);
|
|
51
|
+
frame++;
|
|
52
|
+
}, 80);
|
|
53
|
+
return {
|
|
54
|
+
stop(finalMsg) {
|
|
55
|
+
clearInterval(id);
|
|
56
|
+
process.stderr.write(`\r${" ".repeat(message.length + 3)}\r`);
|
|
57
|
+
if (finalMsg)
|
|
58
|
+
process.stderr.write(`${finalMsg}\n`);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Print a formatted error to stderr with a red "error:" prefix. */
|
|
63
|
+
export function printError(msg) {
|
|
64
|
+
console.error(`${pc.red(pc.bold("error:"))} ${msg}`);
|
|
65
|
+
}
|
|
66
|
+
/** Print a formatted error to stderr and exit. */
|
|
67
|
+
export function exitWithUsageError(msg) {
|
|
68
|
+
printError(msg);
|
|
69
|
+
process.exit(EXIT_USAGE);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=ui.js.map
|
package/dist/ui.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trend2trial",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI Infra trend radar + runnable trial recipes (Serving, RAG, LLMOps)",
|
|
6
6
|
"repository": {
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"trend2trial": "./bin/trend2trial.js"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"
|
|
24
|
+
"picocolors": "^1.1.0",
|
|
25
|
+
"trend2trial-core": "1.0.0"
|
|
25
26
|
},
|
|
26
27
|
"files": [
|
|
27
28
|
"dist",
|