leglas 0.2.0 → 0.3.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/index.js CHANGED
@@ -45,7 +45,7 @@ function parseNew(rest) {
45
45
  if (surface === void 0) {
46
46
  return {
47
47
  kind: "error",
48
- message: "leglas new needs a surface name, for example: leglas new hero"
48
+ message: "leglas new needs a surface name, for example: npx leglas new hero"
49
49
  };
50
50
  }
51
51
  return { kind: "new", surface, print, json, from };
@@ -128,7 +128,7 @@ function parseClassify(rest) {
128
128
  if (changes.length === 0) {
129
129
  return {
130
130
  kind: "error",
131
- message: "leglas classify needs what the direction will touch, for example: leglas classify --change package.json --rewrite src/theme.css"
131
+ message: "leglas classify needs what the direction will touch, for example: npx leglas classify --change package.json --rewrite src/theme.css"
132
132
  };
133
133
  }
134
134
  return { kind: "classify", changes, json };
@@ -203,7 +203,7 @@ function parseArgs(argv) {
203
203
  if (title === void 0) {
204
204
  return {
205
205
  kind: "error",
206
- message: 'leglas keep needs a direction title, for example: leglas keep "Aurora" --to src/components/hero.tsx'
206
+ message: 'leglas keep needs a direction title, for example: npx leglas keep "Aurora" --to src/components/hero.tsx'
207
207
  };
208
208
  }
209
209
  if (to === void 0) {
@@ -253,7 +253,7 @@ function parseArgs(argv) {
253
253
  if (surface === void 0) {
254
254
  return {
255
255
  kind: "error",
256
- message: "leglas explore needs a surface name, for example: leglas explore hero --count 6"
256
+ message: "leglas explore needs a surface name, for example: npx leglas explore hero --count 6"
257
257
  };
258
258
  }
259
259
  return { kind: "explore", surface, count, basedOn, json };
@@ -294,7 +294,7 @@ function parseArgs(argv) {
294
294
  if (title === void 0) {
295
295
  return {
296
296
  kind: "error",
297
- message: 'leglas show needs a direction title, for example: leglas show "Aurora" --json'
297
+ message: 'leglas show needs a direction title, for example: npx leglas show "Aurora" --json'
298
298
  };
299
299
  }
300
300
  return { kind: "show", title, json };
@@ -556,8 +556,8 @@ The set exists to be chosen from, and the choice only means something if the dir
556
556
  One trap, seen every time this goes wrong: a set collapses toward whichever direction is built first. Decide all ${count} before building any, and if two would read as the same direction at a glance, replace one of them.` : `Build ${count} variations of the "${basedOn}" direction for "${surface}".
557
557
 
558
558
  The set exists to pick a variant of a direction already chosen, so every variation must stay recognisably that direction. The trap here is drift: change enough and the comparison stops being about the variant. Vary each one deliberately and hold everything else still; if a variation grows into a new direction, it belongs in its own exploration instead.`;
559
- const register = basedOn === null ? ` leglas add --title "<name>" --url "/?v-${slug}=<key>" --note "<the idea, one line>"` : ` leglas add --title "<name>" --url "/?v-${slug}=<key>" --based-on ${JSON.stringify(basedOn)} --note "<the idea, one line>"`;
560
- const mechanics = `Each one is its own file under .leglas/variants/${slug}/, listed in the DIRECTIONS map in that folder's switch file. If there is no switch file yet, run \`leglas new ${slug}\` first. Register each one the moment it renders, not the set at the end. The interface picks a registration up within seconds, so whoever asked watches the set fill in:
559
+ const register = basedOn === null ? ` npx leglas add --title "<name>" --url "/?v-${slug}=<key>" --note "<the idea, one line>"` : ` npx leglas add --title "<name>" --url "/?v-${slug}=<key>" --based-on ${JSON.stringify(basedOn)} --note "<the idea, one line>"`;
560
+ const mechanics = `Each one is its own file under .leglas/variants/${slug}/, listed in the DIRECTIONS map in that folder's switch file. If there is no switch file yet, run \`npx leglas new ${slug}\` first. Register each one the moment it renders, not the set at the end. The interface picks a registration up within seconds, so whoever asked watches the set fill in:
561
561
 
562
562
  ${register}
563
563
 
@@ -609,46 +609,48 @@ When asked for design variations, alternatives, or "a few options":
609
609
  If a direction cannot be additive, because it must change dependencies,
610
610
  change build configuration, or rewrite an existing file's behaviour, ask
611
611
  where it should live before writing it:
612
- \`leglas classify --change package.json --rewrite src/theme.css --json\`.
612
+ \`npx leglas classify --change package.json --rewrite src/theme.css --json\`.
613
613
  When the answer is \`checkout\`, build the direction on its own git branch
614
- and register it with \`leglas add --title "\u2026" --url "/" --branch <branch>\`
614
+ and register it with \`npx leglas add --title "\u2026" --url "/" --branch <branch>\`
615
615
  (the config needs \`devCommand\` with \`{port}\`). Everything below is the
616
616
  ordinary, in-app path.
617
- 2. Run \`leglas explore <surface> --count <n>\` first, adding
617
+ 2. Run \`npx leglas explore <surface> --count <n>\` first, adding
618
618
  \`--based-on "<title>"\` when the user wants variations of a direction they
619
619
  already like. It prints what the set needs and how to register it. In
620
620
  short: new directions must genuinely disagree with each other, variants of
621
621
  one must not, and either way decide the whole set before building any of
622
622
  it. The designs themselves are yours.
623
623
  3. If the surface has no switcher yet, run
624
- \`leglas new <surface> --from <the component that renders it today>\`. It
624
+ \`npx leglas new <surface> --from <the component that renders it today>\`. It
625
625
  writes one under \`.leglas/variants/<surface>/\` and prints the single line
626
626
  to add where that surface renders. \`--from\` makes the baseline re-export
627
627
  the real component rather than copying it, so it stays live.
628
- 4. Before building, make sure the interface is up. If \`leglas\` is not
629
- already running, tell the user to run it, and hand them the URL now
630
- rather than when the set is done: the rail picks up each registration
631
- within seconds, so they get to watch the exploration fill in.
628
+ 4. Before building, make sure the interface is up. If Leglas is not
629
+ already running, tell the user to run \`npx leglas\`, and hand them the
630
+ URL now rather than when the set is done: the rail picks up each
631
+ registration within seconds, so they get to watch the exploration fill in.
632
632
  5. Build one direction at a time: its own file beside the others in
633
633
  \`.leglas/variants/<surface>/\`, listed in the \`DIRECTIONS\` map in that
634
634
  folder's \`switch\` file, then registered the moment it renders:
635
- \`leglas add --title "Aurora" --url "/?v-<surface>=aurora" --note "One line on the idea."\`
635
+ \`npx leglas add --title "Aurora" --url "/?v-<surface>=aurora" --note "One line on the idea."\`
636
636
  Register each direction as it lands, never the whole set at the end. To
637
637
  the user watching the rail, a batch at the end is minutes of nothing and
638
638
  then everything at once.
639
639
 
640
- When the user asks to change one direction, check \`leglas requests --json\`
640
+ When the user asks to change one direction, check \`npx leglas requests --json\`
641
641
  first: they may have described it from the interface, and the request names the
642
- exact file. Clear the queue with \`leglas requests --clear\` once done.
642
+ exact file. Acknowledge them with \`npx leglas requests --clear\` once done: it
643
+ drops what you collected and reports anything the user typed while you worked,
644
+ which is yours to collect and do next.
643
645
 
644
646
  If the user wants requests handled the moment they are typed, without relaying
645
- each one, tell them about \`leglas watch --run "claude -p {prompt}"\` (any
647
+ each one, tell them about \`npx leglas watch --run "claude -p {prompt}"\` (any
646
648
  agent command works; {prompt} receives the request). It runs in their
647
649
  terminal, hands each request to that command as it arrives, and the interface
648
650
  shows the request's progress.
649
651
 
650
652
  When the user picks a winner, run
651
- \`leglas keep "<title>" --to <path in real source>\`. It moves that direction
653
+ \`npx leglas keep "<title>" --to <path in real source>\`. It moves that direction
652
654
  out of the ignored directory, deletes the rest of the exploration, and drops
653
655
  them from the rail. Then change their component to use the kept component
654
656
  instead of the switcher.
@@ -659,14 +661,14 @@ Useful to know:
659
661
  ships. Move a direction into real source only when it wins.
660
662
  - If the project has no running app yet, a direction can be a plain HTML
661
663
  file: write it under \`.leglas/pages/\` and register it with
662
- \`leglas add --title "Aurora" --file .leglas/pages/aurora.html\`. Leglas
664
+ \`npx leglas add --title "Aurora" --file .leglas/pages/aurora.html\`. Leglas
663
665
  serves the file itself, so no dev server is needed. Sibling assets in the
664
666
  same directory resolve normally.
665
667
  - Titles identify previews and must be unique. The user may rename one in the
666
668
  rail, which renames it on their machine only; the commands answer to either
667
669
  name, so use whichever they said.
668
- - \`leglas list\` shows every direction, shared and local.
669
- - \`leglas show "<title>" --json\` answers for one of them: the file behind it,
670
+ - \`npx leglas list\` shows every direction, shared and local.
671
+ - \`npx leglas show "<title>" --json\` answers for one of them: the file behind it,
670
672
  the variants based on it, what it is being compared against, and anything
671
673
  they have asked for that is not done yet. Run it when handed a direction you
672
674
  did not register yourself.
@@ -676,7 +678,7 @@ Useful to know:
676
678
  ${AGENTS_MARKER_END}
677
679
  `;
678
680
  var STARTER_CONFIG = `// Previews are URLs of your own app. Add one per direction you want to
679
- // compare, then run \`leglas\`.
681
+ // compare, then run \`npx leglas\`.
680
682
  export default {
681
683
  // Where your dev server is. Override at the command line with --user-port.
682
684
  devServer: "http://localhost:3000",
@@ -880,12 +882,12 @@ function isExplorationFile(path) {
880
882
  }
881
883
  var CHECKOUT_STEPS = [
882
884
  "Build the direction on its own branch: git switch -c <branch>, commit it there, switch back.",
883
- 'Register it: leglas add --title "<title>" --url "/" --branch <branch>.',
885
+ 'Register it: npx leglas add --title "<title>" --url "/" --branch <branch>.',
884
886
  "Make sure the config sets devCommand (with {port}), so Leglas can start the checkout."
885
887
  ];
886
888
  var IN_APP_STEPS = [
887
889
  "Author it additively under .leglas/variants/<surface>/, beside the existing directions.",
888
- 'Register it: leglas add --title "<title>" --url "/?v-<surface>=<direction>".'
890
+ 'Register it: npx leglas add --title "<title>" --url "/?v-<surface>=<direction>".'
889
891
  ];
890
892
  function classifyDirection(input) {
891
893
  const checkout = (reason) => ({ level: "checkout", reason, steps: CHECKOUT_STEPS });
@@ -1341,7 +1343,12 @@ async function removeRequest(cwd, id) {
1341
1343
  return true;
1342
1344
  }
1343
1345
  async function clearRequests(cwd) {
1344
- await writeQueue(cwd, []);
1346
+ const requests = await readRequests(cwd);
1347
+ const pending = requests.filter((request) => request.status !== "picked-up");
1348
+ const cleared = requests.length - pending.length;
1349
+ if (cleared > 0)
1350
+ await writeQueue(cwd, pending);
1351
+ return { cleared, pending: pending.length };
1345
1352
  }
1346
1353
 
1347
1354
  // ../server/dist/renames.js
@@ -1380,7 +1387,7 @@ function resolveTitle(input, titles, renames) {
1380
1387
  import { createReadStream, existsSync as existsSync2, statSync } from "fs";
1381
1388
  import http2 from "http";
1382
1389
  import net3 from "net";
1383
- import { extname, join as join6, normalize } from "path";
1390
+ import { extname, join as join6, normalize, relative as relative2 } from "path";
1384
1391
  var LEGLAS_PREFIX = "/leglas";
1385
1392
  var DEFAULT_PORT = 4100;
1386
1393
  var PORT_ATTEMPTS = 20;
@@ -1432,8 +1439,8 @@ function probe(target, timeoutMs = 1e3) {
1432
1439
  });
1433
1440
  }
1434
1441
  function serveFrom(res, dir, relativePath) {
1435
- const relative3 = normalize(relativePath).replace(/^(\.\.[/\\])+/, "");
1436
- const candidate = join6(dir, relative3);
1442
+ const relative4 = normalize(relativePath).replace(/^(\.\.[/\\])+/, "");
1443
+ const candidate = join6(dir, relative4);
1437
1444
  if (!candidate.startsWith(dir))
1438
1445
  return false;
1439
1446
  if (!existsSync2(candidate) || !statSync(candidate).isFile())
@@ -1446,9 +1453,36 @@ function serveFrom(res, dir, relativePath) {
1446
1453
  return true;
1447
1454
  }
1448
1455
  function serveShellFile(res, shellDir, urlPath) {
1449
- const relative3 = normalize(urlPath.slice(LEGLAS_PREFIX.length)).replace(/^(\.\.[/\\])+/, "");
1450
- const isRoot = relative3 === "" || relative3 === "." || relative3 === "/";
1451
- return serveFrom(res, shellDir, isRoot ? "index.html" : relative3);
1456
+ const relative4 = normalize(urlPath.slice(LEGLAS_PREFIX.length)).replace(/^(\.\.[/\\])+/, "");
1457
+ const isRoot = relative4 === "" || relative4 === "." || relative4 === "/";
1458
+ return serveFrom(res, shellDir, isRoot ? "index.html" : relative4);
1459
+ }
1460
+ function snapshotConfig(cwd) {
1461
+ const path = findConfigFile(cwd);
1462
+ if (path === null)
1463
+ return null;
1464
+ try {
1465
+ return { path, mtimeMs: statSync(path).mtimeMs };
1466
+ } catch {
1467
+ return null;
1468
+ }
1469
+ }
1470
+ function configStalenessNotice(cwd, boot, current) {
1471
+ if (boot === null && current === null)
1472
+ return null;
1473
+ if (boot === null && current !== null) {
1474
+ const label = relative2(cwd, current.path) || current.path;
1475
+ return `${label} appeared after Leglas started. Restart leglas to pick it up.`;
1476
+ }
1477
+ if (boot !== null && current === null) {
1478
+ const label = relative2(cwd, boot.path) || boot.path;
1479
+ return `${label} was removed after Leglas started. Restart leglas to run without it.`;
1480
+ }
1481
+ if (boot !== null && current !== null && (boot.path !== current.path || boot.mtimeMs !== current.mtimeMs)) {
1482
+ const label = relative2(cwd, current.path) || current.path;
1483
+ return `${label} changed after Leglas started. Restart leglas to pick it up.`;
1484
+ }
1485
+ return null;
1452
1486
  }
1453
1487
  var PLACEHOLDER = `<!doctype html>
1454
1488
  <meta charset="utf-8">
@@ -1494,12 +1528,17 @@ async function startServer(options) {
1494
1528
  const { config, configErrors = [], shellDir = null, project = "", cwd = process.cwd(), fileMounts = /* @__PURE__ */ new Map() } = options;
1495
1529
  const target = config?.devServer ?? "http://localhost:3000";
1496
1530
  const proxy = createProxyHandler({ target });
1531
+ const bootConfigSnapshot = snapshotConfig(cwd);
1497
1532
  let lastSeen = null;
1498
1533
  const server = http2.createServer((req, res) => {
1499
1534
  const url = req.url ?? "/";
1500
1535
  const path = url.split("?")[0] ?? "/";
1501
1536
  if (path === `${LEGLAS_PREFIX}/api/config`) {
1502
1537
  const boot = config?.previews ?? [];
1538
+ const errors = [...configErrors];
1539
+ const notice = configStalenessNotice(cwd, bootConfigSnapshot, snapshotConfig(cwd));
1540
+ if (notice !== null)
1541
+ errors.push(notice);
1503
1542
  return void readLocalPreviews(cwd).then(({ previews: local }) => {
1504
1543
  const known = new Set(boot.map((preview) => preview.title));
1505
1544
  const fresh = local.filter((preview) => !known.has(preview.title) && preview.branch === void 0 && preview.file === void 0);
@@ -1507,13 +1546,13 @@ async function startServer(options) {
1507
1546
  project,
1508
1547
  devServer: target,
1509
1548
  previews: [...boot, ...fresh],
1510
- errors: configErrors
1549
+ errors
1511
1550
  });
1512
1551
  }).catch(() => sendJson(res, 200, {
1513
1552
  project,
1514
1553
  devServer: target,
1515
1554
  previews: boot,
1516
- errors: configErrors
1555
+ errors
1517
1556
  }));
1518
1557
  }
1519
1558
  if (path === `${LEGLAS_PREFIX}/api/request` && req.method === "POST") {
@@ -1587,21 +1626,28 @@ async function startServer(options) {
1587
1626
  const rest = path.slice(FILES_PREFIX.length + 1);
1588
1627
  const slash = rest.indexOf("/");
1589
1628
  const slug = slash === -1 ? rest : rest.slice(0, slash);
1590
- let relative3 = slash === -1 ? "" : rest.slice(slash + 1);
1629
+ let relative4 = slash === -1 ? "" : rest.slice(slash + 1);
1591
1630
  try {
1592
- relative3 = decodeURIComponent(relative3);
1631
+ relative4 = decodeURIComponent(relative4);
1593
1632
  } catch {
1594
- relative3 = "";
1633
+ relative4 = "";
1595
1634
  }
1596
1635
  const dir = fileMounts.get(slug);
1597
- if (dir !== void 0 && relative3 !== "" && serveFrom(res, dir, relative3))
1636
+ if (dir !== void 0 && relative4 !== "" && serveFrom(res, dir, relative4))
1598
1637
  return;
1599
1638
  res.writeHead(404, { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" });
1600
1639
  return res.end("Leglas: no such preview file.");
1601
1640
  }
1641
+ if (path.startsWith(`${LEGLAS_PREFIX}/api/`)) {
1642
+ return sendJson(res, 404, { error: "No such Leglas API path." });
1643
+ }
1602
1644
  if (path === LEGLAS_PREFIX || path.startsWith(`${LEGLAS_PREFIX}/`)) {
1603
1645
  if (shellDir !== null && serveShellFile(res, shellDir, path))
1604
1646
  return;
1647
+ if (shellDir !== null) {
1648
+ res.writeHead(404, { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" });
1649
+ return res.end("Leglas: no such path.");
1650
+ }
1605
1651
  res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
1606
1652
  return res.end(PLACEHOLDER);
1607
1653
  }
@@ -1650,7 +1696,7 @@ function planKeep(options) {
1650
1696
  if (!winner) {
1651
1697
  return {
1652
1698
  ok: false,
1653
- error: `No direction called ${JSON.stringify(options.title)}. Run leglas list to see them.`
1699
+ error: `No direction called ${JSON.stringify(options.title)}. Run npx leglas list to see them.`
1654
1700
  };
1655
1701
  }
1656
1702
  const from = targetFor(winner.url);
@@ -1745,7 +1791,7 @@ function resolveOrExplain(input, titles, renames) {
1745
1791
  }
1746
1792
  return {
1747
1793
  ok: false,
1748
- error: `No direction called ${JSON.stringify(input)}. Renaming one in the rail only renames it here, and it still answers to its title in the config, which its reference block quotes. leglas list shows every title.`
1794
+ error: `No direction called ${JSON.stringify(input)}. Renaming one in the rail only renames it here, and it still answers to its title in the config, which its reference block quotes. npx leglas list shows every title.`
1749
1795
  };
1750
1796
  }
1751
1797
 
@@ -1895,7 +1941,7 @@ async function runNew(options, deps) {
1895
1941
  deps.log("Then register them so they appear in the interface:");
1896
1942
  deps.log("");
1897
1943
  for (const preview of plan.previews) {
1898
- deps.log(` leglas add --title ${JSON.stringify(preview.title)} --url ${JSON.stringify(preview.url)}`);
1944
+ deps.log(` npx leglas add --title ${JSON.stringify(preview.title)} --url ${JSON.stringify(preview.url)}`);
1899
1945
  }
1900
1946
  return { exitCode: 0, written };
1901
1947
  }
@@ -1924,7 +1970,7 @@ async function runAdd(options, deps) {
1924
1970
  const local = await readLocalPreviews(options.cwd);
1925
1971
  const titles = new Set([...shared, ...local.previews].map((preview) => preview.title));
1926
1972
  if (!titles.has(options.preview.basedOn)) {
1927
- const error = `--based-on names ${JSON.stringify(options.preview.basedOn)}, which is not a registered direction. leglas list shows what exists.`;
1973
+ const error = `--based-on names ${JSON.stringify(options.preview.basedOn)}, which is not a registered direction. npx leglas list shows what exists.`;
1928
1974
  if (options.json) envelope(deps, false, { error });
1929
1975
  else deps.error(error);
1930
1976
  return { exitCode: 1 };
@@ -1957,6 +2003,7 @@ async function runAdd(options, deps) {
1957
2003
  local: true,
1958
2004
  ...options.preview.branch === void 0 ? {} : { branch: options.preview.branch },
1959
2005
  ...options.preview.file === void 0 ? {} : { file: options.preview.file },
2006
+ note: options.preview.branch === void 0 && options.preview.file === void 0 ? "A running interface picks this up within seconds." : "Restart Leglas to see this preview: branch checkouts and file mounts are built when Leglas starts.",
1960
2007
  ...needsDevCommand ? { warning: "The config sets no devCommand, so Leglas cannot start this branch yet. Add devCommand (with {port}) to the config." } : {}
1961
2008
  });
1962
2009
  } else {
@@ -1972,7 +2019,7 @@ async function runAdd(options, deps) {
1972
2019
  if (options.preview.branch === void 0 && options.preview.file === void 0) {
1973
2020
  deps.log("Local to this machine. A running interface picks it up within seconds.");
1974
2021
  } else {
1975
- deps.log("Local to this machine. Restart Leglas to see it, or run leglas list.");
2022
+ deps.log("Local to this machine. Restart Leglas to see it, or run npx leglas list.");
1976
2023
  }
1977
2024
  }
1978
2025
  return { exitCode: 0 };
@@ -2007,7 +2054,7 @@ async function runList(options, deps) {
2007
2054
  return { exitCode: errors.length === 0 ? 0 : 1 };
2008
2055
  }
2009
2056
  if (previews.length === 0) {
2010
- deps.log("No previews yet. Add one with leglas add, or list them in leglas.config.ts.");
2057
+ deps.log("No previews yet. Add one with npx leglas add, or list them in leglas.config.ts.");
2011
2058
  } else {
2012
2059
  const width = Math.max(...previews.map((preview) => preview.title.length));
2013
2060
  for (const preview of previews) {
@@ -2022,9 +2069,16 @@ async function runList(options, deps) {
2022
2069
  }
2023
2070
  async function runRequests(options, deps) {
2024
2071
  if (options.clear) {
2025
- await clearRequests(options.cwd);
2026
- if (options.json) envelope(deps, true, { cleared: true });
2027
- else deps.log("Queue cleared.");
2072
+ const { cleared, pending } = await clearRequests(options.cwd);
2073
+ if (options.json) envelope(deps, true, { cleared, pending });
2074
+ else {
2075
+ deps.log(cleared === 1 ? "Cleared 1 request." : `Cleared ${cleared} requests.`);
2076
+ if (pending > 0) {
2077
+ deps.log(
2078
+ `${pending} arrived while you worked. Run npx leglas requests to collect ${pending === 1 ? "it" : "them"}.`
2079
+ );
2080
+ }
2081
+ }
2028
2082
  return { exitCode: 0 };
2029
2083
  }
2030
2084
  const requests = await collectRequests(options.cwd);
@@ -2041,7 +2095,7 @@ async function runRequests(options, deps) {
2041
2095
  if (request.target !== null) deps.log(` ${request.target}`);
2042
2096
  }
2043
2097
  deps.log("");
2044
- deps.log("Run leglas requests --json to get the full prompts, then --clear when done.");
2098
+ deps.log("Run npx leglas requests --json to get the full prompts, then --clear when done.");
2045
2099
  return { exitCode: 0 };
2046
2100
  }
2047
2101
 
@@ -2067,7 +2121,7 @@ function planShow({ title, previews, requests }) {
2067
2121
  if (!found) {
2068
2122
  return {
2069
2123
  ok: false,
2070
- error: `No direction called ${JSON.stringify(title)}. Run leglas list to see them.`
2124
+ error: `No direction called ${JSON.stringify(title)}. Run npx leglas list to see them.`
2071
2125
  };
2072
2126
  }
2073
2127
  const variants = previews.filter((preview) => preview.basedOn === title).map(describe);
@@ -2146,7 +2200,7 @@ async function runShow(options, deps) {
2146
2200
  deps.log(` Pending, not yet done (${plan.requests.length}):`);
2147
2201
  for (const request of plan.requests) deps.log(` ${request.status} ${request.intent}`);
2148
2202
  deps.log("");
2149
- deps.log(" Run leglas requests --json for the full prompts.");
2203
+ deps.log(" Run npx leglas requests --json for the full prompts.");
2150
2204
  }
2151
2205
  return { exitCode: 0 };
2152
2206
  }
@@ -2154,7 +2208,7 @@ async function runShow(options, deps) {
2154
2208
  // src/watch.ts
2155
2209
  var WATCH_PATH = ".leglas/watch.json";
2156
2210
  var PROMPT_TOKEN = "{prompt}";
2157
- var EXAMPLE = `leglas watch --run "claude -p ${PROMPT_TOKEN}"`;
2211
+ var EXAMPLE = `npx leglas watch --run "claude -p ${PROMPT_TOKEN}"`;
2158
2212
  function tokenize(template) {
2159
2213
  const tokens = [];
2160
2214
  let current = "";
@@ -2269,7 +2323,7 @@ async function runWatch(options, deps) {
2269
2323
  const raw = options.run ?? saved;
2270
2324
  if (raw === null) {
2271
2325
  deps.error(
2272
- 'Watch needs an agent command the first time: leglas watch --run "claude -p {prompt}"'
2326
+ 'Watch needs an agent command the first time: npx leglas watch --run "claude -p {prompt}"'
2273
2327
  );
2274
2328
  return { exitCode: 1 };
2275
2329
  }
@@ -2388,7 +2442,7 @@ async function runClassify(options, deps) {
2388
2442
  // src/run.ts
2389
2443
  import { existsSync as existsSync5 } from "fs";
2390
2444
  import { createRequire } from "module";
2391
- import { basename as basename3, dirname as dirname8, join as join13, relative as relative2 } from "path";
2445
+ import { basename as basename3, dirname as dirname8, join as join13, relative as relative3 } from "path";
2392
2446
  import { fileURLToPath } from "url";
2393
2447
  function findShellDir() {
2394
2448
  const bundled = join13(dirname8(fileURLToPath(import.meta.url)), "shell");
@@ -2501,7 +2555,7 @@ async function run2(options, deps) {
2501
2555
  })
2502
2556
  );
2503
2557
  } else {
2504
- const configLabel = loaded.path === null ? "no config file, previewing the app root" : relative2(options.cwd, loaded.path) || loaded.path;
2558
+ const configLabel = loaded.path === null ? "no config file, previewing the app root" : relative3(options.cwd, loaded.path) || loaded.path;
2505
2559
  deps.log(`Leglas ${url}`);
2506
2560
  deps.log(
2507
2561
  `app ${devServer}${app !== null ? " (started by Leglas)" : health.reachable ? "" : " (not reachable)"}`