@kadj-amoah/showrunner 1.1.5 → 1.1.6
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/CHANGELOG.md +19 -0
- package/dist/cli.js +85 -8
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Showrunner are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project tracks loose semver — minor bumps for new capability, patch for fixes.
|
|
4
4
|
|
|
5
|
+
## [1.1.6] — 2026-05-24
|
|
6
|
+
|
|
7
|
+
Closes a long-latent gap: `showrunner understand` now has an `--agent` mode that delegates codebase exploration to the local `claude` CLI rather than relying on `comprehension.sources` to be set up correctly.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`showrunner understand --agent`** — when set, Showrunner skips the `comprehension.sources` reading path entirely and hands the project off to the local `claude` agent (spawned via `claude -p --output-format json` from `process.cwd()`). The agent uses its native Read/Glob/Grep tools to explore the repository, identify the product, and synthesize a `product_model.json` matching the existing schema. Validated against `productModelSchema` like every other path; retries on schema-violation just like the doc-driven path.
|
|
12
|
+
- Mutually exclusive with `--interactive`. Errors clearly if `claude` isn't on PATH.
|
|
13
|
+
|
|
14
|
+
### Why this matters
|
|
15
|
+
|
|
16
|
+
Until v1.1.5, the `comprehension.sources` config accepted `type: codebase` with `include`/`exclude` globs, but the implementation (`src/commands/understand.ts:71-88`) called `readFile()` directly on `src.path` for every source type, treating directories as files (which silently fail with `EISDIR`) and ignoring the glob fields entirely. `--agent` sidesteps this: instead of teaching Showrunner to walk codebases itself (which would mean micromatch, fast-glob, binary filters, file caps, vendored-dir defaults), it lets the agent — which already has those capabilities — do the discovery.
|
|
17
|
+
|
|
18
|
+
The `codebase` source type in `comprehension.sources` is **still non-functional** when passed to `understand` without `--agent` (treated as single file → silently skipped). Wiring real codebase support to the document path remains a candidate for a future release, but `--agent` is the recommended path now.
|
|
19
|
+
|
|
20
|
+
### Updated error messages
|
|
21
|
+
|
|
22
|
+
- When `comprehension.sources` is empty, the error now mentions all three escape hatches: add sources, `--interactive`, or `--agent`.
|
|
23
|
+
|
|
5
24
|
## [1.1.5] — 2026-05-24
|
|
6
25
|
|
|
7
26
|
**Phase B + Phase C of the interactive-setup overhaul shipped together.** When the wizard's URL probe fails, it now tries progressively smarter strategies before falling back to a warning.
|
package/dist/cli.js
CHANGED
|
@@ -7587,6 +7587,71 @@ Regenerate the product_model strictly matching the schema.`
|
|
|
7587
7587
|
}
|
|
7588
7588
|
}
|
|
7589
7589
|
|
|
7590
|
+
// src/productModel/generateViaAgent.ts
|
|
7591
|
+
var DEFAULT_MAX_TOKENS5 = 8e3;
|
|
7592
|
+
var AGENT_SYSTEM_PROMPT = [
|
|
7593
|
+
"You are helping Showrunner build a product_model.json for a product demo recording.",
|
|
7594
|
+
"",
|
|
7595
|
+
"You have read-only filesystem tools (Read, Glob, Grep) and can explore the project freely.",
|
|
7596
|
+
"Use them \u2014 do NOT guess from the prompt alone.",
|
|
7597
|
+
"",
|
|
7598
|
+
"What to look for, in order:",
|
|
7599
|
+
" 1. package.json (or pyproject.toml, Cargo.toml, etc.) \u2014 name, description, scripts, deps",
|
|
7600
|
+
" 2. README.md / README.* at the project root \u2014 product description, primary user, features",
|
|
7601
|
+
" 3. docs/PRD.md or similar \u2014 explicit product brief if present",
|
|
7602
|
+
" 4. src/ tree (sample a few files) \u2014 what the product actually DOES, names of routes/pages/components",
|
|
7603
|
+
" 5. .env.example \u2014 hints at integrations and external services",
|
|
7604
|
+
" 6. Any framework config (next.config, vite.config, astro.config, etc.) \u2014 confirms what kind of app this is",
|
|
7605
|
+
"",
|
|
7606
|
+
"When you have enough signal, synthesize a product_model.json matching the requested schema.",
|
|
7607
|
+
"",
|
|
7608
|
+
"Rules:",
|
|
7609
|
+
' - product_name: short, exact product name as branded. Take this from package.json "name" only if it looks human, else from README.',
|
|
7610
|
+
" - tagline: one sentence, 8\u201315 words, plain language. Derived from README/PRD, not invented.",
|
|
7611
|
+
` - primary_user: one short phrase. Inferred from the README's "who is this for" framing if explicit, else from the product's shape.`,
|
|
7612
|
+
" - core_flows: 2\u20134 user flows. Each has id (kebab-case), name, 3\u20136 imperative steps from the user's POV, optional entry_url. Ground these in the actual routes/pages the codebase exposes.",
|
|
7613
|
+
" - key_features: 3\u20136 short bullets. No marketing fluff.",
|
|
7614
|
+
" - demo_recommendation.suggested_flows: ids from core_flows, in demo order.",
|
|
7615
|
+
" - demo_recommendation.suggested_duration_seconds: 60\u201390 typical.",
|
|
7616
|
+
" - confidence: 'high' if you found explicit, clear sources; 'medium' if you had to infer; 'low' if the codebase was sparse and you mostly guessed.",
|
|
7617
|
+
" - source: always 'documents' (this path counts as document-driven, just agentically discovered).",
|
|
7618
|
+
" - generated_at: ISO-8601 timestamp.",
|
|
7619
|
+
"",
|
|
7620
|
+
"Output exactly the structured JSON. No prose, no commentary, no markdown fence outside the JSON."
|
|
7621
|
+
].join("\n");
|
|
7622
|
+
async function generateProductModelViaAgent(opts) {
|
|
7623
|
+
const provider = new AgentBridgeLLMProvider({
|
|
7624
|
+
mode: "spawn",
|
|
7625
|
+
command: opts.command ?? "claude",
|
|
7626
|
+
args: opts.args ?? ["-p", "--output-format", "json"],
|
|
7627
|
+
timeoutMs: opts.timeoutMs ?? 18e4,
|
|
7628
|
+
cwd: opts.projectDir
|
|
7629
|
+
});
|
|
7630
|
+
const userPrompt = [
|
|
7631
|
+
`Project directory: ${opts.projectDir}`,
|
|
7632
|
+
"",
|
|
7633
|
+
"Explore this directory with your filesystem tools, then synthesize a product_model.json."
|
|
7634
|
+
].join("\n");
|
|
7635
|
+
logger.debug("Generating product_model via agent", { projectDir: opts.projectDir });
|
|
7636
|
+
try {
|
|
7637
|
+
return await generateWithRetry(provider, {
|
|
7638
|
+
systemPrompt: AGENT_SYSTEM_PROMPT,
|
|
7639
|
+
userPrompt,
|
|
7640
|
+
schema: productModelSchema,
|
|
7641
|
+
schemaName: "product_model",
|
|
7642
|
+
maxTokens: DEFAULT_MAX_TOKENS5,
|
|
7643
|
+
retryRenderer: (errorText, prevUserPrompt) => `${prevUserPrompt}
|
|
7644
|
+
|
|
7645
|
+
Your previous output failed validation with this error:
|
|
7646
|
+
${errorText}
|
|
7647
|
+
|
|
7648
|
+
Regenerate the product_model strictly matching the schema.`
|
|
7649
|
+
});
|
|
7650
|
+
} catch (err) {
|
|
7651
|
+
throw new ProductModelGenerationError(err instanceof Error ? err.message : String(err));
|
|
7652
|
+
}
|
|
7653
|
+
}
|
|
7654
|
+
|
|
7590
7655
|
// src/productModel/interactive.ts
|
|
7591
7656
|
import { createInterface as createInterface2 } from "readline";
|
|
7592
7657
|
var LineReader = class {
|
|
@@ -7675,6 +7740,10 @@ function clamp(n, lo, hi) {
|
|
|
7675
7740
|
|
|
7676
7741
|
// src/commands/understand.ts
|
|
7677
7742
|
async function understandCommand(opts) {
|
|
7743
|
+
if (opts.interactive && opts.agent) {
|
|
7744
|
+
logger.error("--interactive and --agent are mutually exclusive. Pick one.");
|
|
7745
|
+
process.exit(2);
|
|
7746
|
+
}
|
|
7678
7747
|
let configDir = process.cwd();
|
|
7679
7748
|
let outputRel = opts.output ?? "./product_model.json";
|
|
7680
7749
|
let sources = [];
|
|
@@ -7705,16 +7774,20 @@ async function understandCommand(opts) {
|
|
|
7705
7774
|
const outputPath = isAbsolute13(outputRel) ? outputRel : resolve25(configDir, outputRel);
|
|
7706
7775
|
await mkdir15(dirname13(outputPath), { recursive: true });
|
|
7707
7776
|
let productModel;
|
|
7708
|
-
const provider = resolveDefaultLLMProvider({ configDir, llm: llmConfig });
|
|
7709
7777
|
try {
|
|
7710
|
-
if (opts.
|
|
7778
|
+
if (opts.agent) {
|
|
7779
|
+
const projectDir = process.cwd();
|
|
7780
|
+
logger.info("Generating product_model via local `claude` agent", { projectDir });
|
|
7781
|
+
productModel = await generateProductModelViaAgent({ projectDir });
|
|
7782
|
+
} else if (opts.interactive) {
|
|
7711
7783
|
const answers = await runInteractiveQA();
|
|
7712
7784
|
logger.info("Generating product_model from interactive answers");
|
|
7785
|
+
const provider = resolveDefaultLLMProvider({ configDir, llm: llmConfig });
|
|
7713
7786
|
productModel = await generateProductModelFromInteractive({ answers, provider });
|
|
7714
7787
|
} else {
|
|
7715
7788
|
if (sources.length === 0) {
|
|
7716
7789
|
logger.error(
|
|
7717
|
-
"No `comprehension.sources` configured in demo.yaml. Add at least one source (prd, readme, codebase, etc.) or re-run with --
|
|
7790
|
+
"No `comprehension.sources` configured in demo.yaml. Add at least one source (prd, readme, codebase, etc.), re-run with --interactive (Q&A), or re-run with --agent (the local `claude` CLI explores your repo)."
|
|
7718
7791
|
);
|
|
7719
7792
|
process.exit(2);
|
|
7720
7793
|
}
|
|
@@ -7736,6 +7809,7 @@ async function understandCommand(opts) {
|
|
|
7736
7809
|
logger.info("Generating product_model from documents", {
|
|
7737
7810
|
sources: docs.map((d) => d.path)
|
|
7738
7811
|
});
|
|
7812
|
+
const provider = resolveDefaultLLMProvider({ configDir, llm: llmConfig });
|
|
7739
7813
|
productModel = await generateProductModelFromDocs({ sources: docs, provider });
|
|
7740
7814
|
}
|
|
7741
7815
|
} catch (err) {
|
|
@@ -7832,7 +7906,7 @@ function pickAttr(node, attr) {
|
|
|
7832
7906
|
|
|
7833
7907
|
// src/instrument/suggest.ts
|
|
7834
7908
|
import { z as z10 } from "zod";
|
|
7835
|
-
var
|
|
7909
|
+
var DEFAULT_MAX_TOKENS6 = 8e3;
|
|
7836
7910
|
var suggestionSchema = z10.object({
|
|
7837
7911
|
suggestions: z10.array(
|
|
7838
7912
|
z10.object({
|
|
@@ -7878,7 +7952,7 @@ For each, return {file, line, original (exact source line), replacement (source
|
|
|
7878
7952
|
userPrompt,
|
|
7879
7953
|
schema: suggestionSchema,
|
|
7880
7954
|
schemaName: "instrument_suggestions",
|
|
7881
|
-
maxTokens:
|
|
7955
|
+
maxTokens: DEFAULT_MAX_TOKENS6
|
|
7882
7956
|
});
|
|
7883
7957
|
return result.suggestions;
|
|
7884
7958
|
} catch (err) {
|
|
@@ -8368,7 +8442,7 @@ async function fileExists10(path) {
|
|
|
8368
8442
|
|
|
8369
8443
|
// src/cli.ts
|
|
8370
8444
|
var program = new Command();
|
|
8371
|
-
program.name("showrunner").description("Automated product demo recording & production tool").version("1.1.
|
|
8445
|
+
program.name("showrunner").description("Automated product demo recording & production tool").version("1.1.6").option("--json", "emit structured JSON logs to stdout").option("--log-level <level>", "log level (debug|info|warn|error)").hook("preAction", (thisCmd) => {
|
|
8372
8446
|
const opts = thisCmd.opts();
|
|
8373
8447
|
if (opts.json) logger.setJson(true);
|
|
8374
8448
|
if (opts.logLevel) logger.setLevel(opts.logLevel);
|
|
@@ -8405,7 +8479,10 @@ program.command("set-target").description("Update demo.yaml's recording.target_u
|
|
|
8405
8479
|
program.command("install-browser").description("Install the Playwright browser binary (chromium by default) \u2014 wraps playwright-core install").option("--browser <name>", "browser to install: chromium | firefox | webkit", "chromium").action(installBrowserCommand);
|
|
8406
8480
|
program.command("doctor").description("Run preflight checks on the current config + environment").requiredOption("-c, --config <path>", "path to demo.yaml").option("--json", "emit results as JSON instead of human-readable rows").action(doctorCommand);
|
|
8407
8481
|
program.command("validate").description("Validate a demo.yaml config file").requiredOption("-c, --config <path>", "path to demo.yaml").option("--strict", "exit nonzero on any warning (e.g. missing provider env var)").action(validateCommand);
|
|
8408
|
-
program.command("understand").description("Build product_model.json from documents
|
|
8482
|
+
program.command("understand").description("Build product_model.json from documents, interactive Q&A, or agent-driven repo exploration").option("-c, --config <path>", "path to demo.yaml").option("--interactive", "use interactive Q&A mode (5 prompts, no LLM)").option(
|
|
8483
|
+
"--agent",
|
|
8484
|
+
"delegate to the local `claude` CLI: it explores the current directory with its read tools and synthesizes the product model. Closes the type=codebase gap in demo.yaml sources."
|
|
8485
|
+
).option("--output <path>", "output path for product_model.json").action(understandCommand);
|
|
8409
8486
|
program.command("instrument").description("Suggest data-testid attributes for a codebase").requiredOption("-c, --config <path>", "path to demo.yaml").requiredOption("--output <path>", "unified diff output path").option("--glob <pattern>", "override comprehension.sources with an ad-hoc glob (relative to configDir)").action(instrumentCommand);
|
|
8410
8487
|
program.command("record-actions").description("Author manifest actions by demonstrating them in a live browser").requiredOption("-c, --config <path>", "path to demo.yaml").option("--segment <id>", "replace actions for an existing segment id").option("--output <path>", "manifest output path (default ./scripts/manifest.json)").action(recordActionsCommand);
|
|
8411
8488
|
program.command("preview").description("Preview the generated Playwright script in UI Mode").requiredOption("-c, --config <path>", "path to demo.yaml").action(previewCommand);
|
|
@@ -8430,7 +8507,7 @@ async function printWelcome() {
|
|
|
8430
8507
|
} catch {
|
|
8431
8508
|
}
|
|
8432
8509
|
const browserMissing = await isChromiumMissing();
|
|
8433
|
-
const lines = ["", `Showrunner v1.1.
|
|
8510
|
+
const lines = ["", `Showrunner v1.1.6`, ""];
|
|
8434
8511
|
if (browserMissing) {
|
|
8435
8512
|
lines.push(`Showrunner records using Chromium. You haven't installed it yet.`);
|
|
8436
8513
|
lines.push(``);
|