@delt/tester-mcp 0.1.0 → 0.1.1
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/cli.js +19 -19
- package/dist/init.js +11 -11
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -15,18 +15,18 @@ import { captureEnv } from "./env/captureEnv.js";
|
|
|
15
15
|
import { makeRunId } from "./util/runId.js";
|
|
16
16
|
import { loadGuide } from "./guide/loadGuide.js";
|
|
17
17
|
const program = new Command();
|
|
18
|
-
program.name("tester-mcp").description("Opus+Haiku+Chrome
|
|
19
|
-
// [확장5] validate/report/diff
|
|
18
|
+
program.name("tester-mcp").description("Opus + Haiku + Chrome screen E2E test orchestrator");
|
|
19
|
+
// [확장5] add validate/report/diff commands here.
|
|
20
20
|
program
|
|
21
21
|
.command("run")
|
|
22
|
-
.argument("<scenarios...>", "
|
|
23
|
-
.option("-c, --config <path>", "
|
|
24
|
-
.option("--secrets <path>", "
|
|
25
|
-
.option("--front-dir <path>", "frontend git
|
|
26
|
-
.option("--timeout <ms>", "executor
|
|
27
|
-
.option("--concurrency <n>",
|
|
28
|
-
.option("--verbose", "executor
|
|
29
|
-
.option("--out-dir <path>", "
|
|
22
|
+
.argument("<scenarios...>", "scenario YAML path(s) (files or directories; multiple allowed)")
|
|
23
|
+
.option("-c, --config <path>", "config file", "tester-mcp.config.yaml")
|
|
24
|
+
.option("--secrets <path>", "secrets file", "tester-mcp.secrets.yaml")
|
|
25
|
+
.option("--front-dir <path>", "frontend git dir (for commit capture)")
|
|
26
|
+
.option("--timeout <ms>", "executor hard timeout (ms; overrides config runner.timeout_ms)")
|
|
27
|
+
.option("--concurrency <n>", `parallel executor count (1-${MAX_CONCURRENCY}, default min(scenario count, ${MAX_CONCURRENCY}))`)
|
|
28
|
+
.option("--verbose", "stream executor tool activity to the console")
|
|
29
|
+
.option("--out-dir <path>", "output base dir for results/logs (default runs)", "runs")
|
|
30
30
|
.action(async (scenarioPaths, opts) => {
|
|
31
31
|
try {
|
|
32
32
|
const config = loadConfig(resolve(opts.config));
|
|
@@ -39,7 +39,7 @@ program
|
|
|
39
39
|
const timeoutMs = opts.timeout ? Number(opts.timeout) : config.runner.timeout_ms;
|
|
40
40
|
const concurrency = clampConcurrency(opts.concurrency ? Number(opts.concurrency) : undefined, scenarios.length);
|
|
41
41
|
if (scenarios.length > 1)
|
|
42
|
-
console.log(
|
|
42
|
+
console.log(`${scenarios.length} scenarios · concurrency ${concurrency}`);
|
|
43
43
|
// Compute secret values before run so they can be redacted in streaming logs.
|
|
44
44
|
const secretValues = collectSecretValues({ secrets, env: process.env });
|
|
45
45
|
const results = await runScenarios(scenarios, {
|
|
@@ -64,25 +64,25 @@ program
|
|
|
64
64
|
process.exit(ok ? 0 : 1);
|
|
65
65
|
}
|
|
66
66
|
catch (err) {
|
|
67
|
-
console.error("
|
|
67
|
+
console.error("run error:", err instanceof Error ? err.message : err);
|
|
68
68
|
process.exit(2);
|
|
69
69
|
}
|
|
70
70
|
});
|
|
71
71
|
program
|
|
72
72
|
.command("init")
|
|
73
|
-
.description("
|
|
74
|
-
.option("--global", "
|
|
75
|
-
.option("--project [path]", "
|
|
73
|
+
.description("Setup wizard: installs the skill and scaffolds config + a secrets example")
|
|
74
|
+
.option("--global", "install the skill globally (~/.claude/skills)")
|
|
75
|
+
.option("--project [path]", "install the skill in a project (<path>/.claude/skills, default cwd)")
|
|
76
76
|
.option("--frontend <url>", "frontend URL")
|
|
77
|
-
.option("--backend <url>", "backend URL(
|
|
78
|
-
.option("--model <m>", "executor
|
|
79
|
-
.option("--yes", "
|
|
77
|
+
.option("--backend <url>", "backend URL (optional)")
|
|
78
|
+
.option("--model <m>", "executor model")
|
|
79
|
+
.option("--yes", "non-interactive (use defaults/flags)")
|
|
80
80
|
.action(async (opts) => {
|
|
81
81
|
try {
|
|
82
82
|
await runInit(opts);
|
|
83
83
|
}
|
|
84
84
|
catch (err) {
|
|
85
|
-
console.error("init
|
|
85
|
+
console.error("init error:", err instanceof Error ? err.message : err);
|
|
86
86
|
process.exit(2);
|
|
87
87
|
}
|
|
88
88
|
});
|
package/dist/init.js
CHANGED
|
@@ -54,12 +54,12 @@ export async function runInit(opts) {
|
|
|
54
54
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
55
55
|
try {
|
|
56
56
|
if (!opts.global && opts.project === undefined) {
|
|
57
|
-
const ans = (await rl.question("
|
|
57
|
+
const ans = (await rl.question("Skill install scope [project/global] (project): ")).trim();
|
|
58
58
|
if (ans === "global")
|
|
59
59
|
scope = "global";
|
|
60
60
|
}
|
|
61
61
|
if (scope === "project" && typeof opts.project !== "string") {
|
|
62
|
-
const ans = (await rl.question(
|
|
62
|
+
const ans = (await rl.question(`Project path (${projectPath}): `)).trim();
|
|
63
63
|
if (ans)
|
|
64
64
|
projectPath = ans;
|
|
65
65
|
}
|
|
@@ -68,7 +68,7 @@ export async function runInit(opts) {
|
|
|
68
68
|
frontend = ans || "http://localhost:5173";
|
|
69
69
|
}
|
|
70
70
|
if (backend === undefined) {
|
|
71
|
-
const ans = (await rl.question("backend URL (
|
|
71
|
+
const ans = (await rl.question("backend URL (optional, leave blank to skip): ")).trim();
|
|
72
72
|
backend = ans || undefined;
|
|
73
73
|
}
|
|
74
74
|
if (model === undefined) {
|
|
@@ -94,20 +94,20 @@ export async function runInit(opts) {
|
|
|
94
94
|
if (bundled) {
|
|
95
95
|
mkdirSync(dirname(destSkill), { recursive: true });
|
|
96
96
|
writeFileSync(destSkill, readFileSync(bundled, "utf8"), "utf8");
|
|
97
|
-
console.log(
|
|
97
|
+
console.log(`Skill copied: ${destSkill}`);
|
|
98
98
|
}
|
|
99
99
|
else {
|
|
100
|
-
console.warn("
|
|
100
|
+
console.warn("Warning: bundled skill (skills/tester-mcp/SKILL.md) not found; skipping skill copy.");
|
|
101
101
|
}
|
|
102
102
|
// 2) Write config.
|
|
103
103
|
const configPath = join(configDir, "tester-mcp.config.yaml");
|
|
104
104
|
mkdirSync(dirname(configPath), { recursive: true });
|
|
105
105
|
writeFileSync(configPath, renderConfigYaml({ frontend, backend, model }), "utf8");
|
|
106
|
-
console.log(
|
|
106
|
+
console.log(`Config written: ${configPath}`);
|
|
107
107
|
// 3) Scaffold secrets example + ensure .gitignore.
|
|
108
108
|
const examplePath = join(cwd, "tester-mcp.secrets.example.yaml");
|
|
109
109
|
writeFileSync(examplePath, secretsExampleYaml(), "utf8");
|
|
110
|
-
console.log(
|
|
110
|
+
console.log(`Secrets example written: ${examplePath}`);
|
|
111
111
|
const gitignorePath = join(cwd, ".gitignore");
|
|
112
112
|
const entry = "tester-mcp.secrets.yaml";
|
|
113
113
|
let gi = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf8") : "";
|
|
@@ -116,12 +116,12 @@ export async function runInit(opts) {
|
|
|
116
116
|
gi += "\n";
|
|
117
117
|
gi += entry + "\n";
|
|
118
118
|
writeFileSync(gitignorePath, gi, "utf8");
|
|
119
|
-
console.log(`.gitignore
|
|
119
|
+
console.log(`.gitignore updated: added ${entry}`);
|
|
120
120
|
}
|
|
121
121
|
// 4) Next steps.
|
|
122
|
-
console.log("\
|
|
122
|
+
console.log("\nNext steps:");
|
|
123
123
|
console.log(` 1) cp tester-mcp.secrets.example.yaml tester-mcp.secrets.yaml`);
|
|
124
|
-
console.log(` →
|
|
125
|
-
console.log(` 2)
|
|
124
|
+
console.log(` → fill in the test account (username/password). (this file is gitignored)`);
|
|
125
|
+
console.log(` 2) Write a scenario, then run:`);
|
|
126
126
|
console.log(` tester-mcp run scenarios/<area>/<id>.yaml -c ${join(configDir, "tester-mcp.config.yaml")}`);
|
|
127
127
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delt/tester-mcp",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Opus(planner) + Haiku(executor) + Chrome
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Opus (planner) + Haiku (executor) + Chrome screen E2E test orchestrator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": { "tester-mcp": "bin/tester-mcp.js" },
|
|
7
7
|
"files": ["dist", "bin", "skills"],
|