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/README.md +71 -19
- package/dist/bin.js +109 -55
- package/dist/index.js +109 -55
- package/dist/shell/assets/{index-r7sGM7WL.js → index-Bl87Vq9G.js} +2 -2
- package/dist/shell/index.html +1 -1
- package/package.json +1 -1
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
|
|
629
|
-
already running, tell the user to run
|
|
630
|
-
rather than when the set is done: the rail picks up each
|
|
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.
|
|
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
|
|
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
|
|
1436
|
-
const candidate = join6(dir,
|
|
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
|
|
1450
|
-
const isRoot =
|
|
1451
|
-
return serveFrom(res, shellDir, isRoot ? "index.html" :
|
|
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
|
|
1549
|
+
errors
|
|
1511
1550
|
});
|
|
1512
1551
|
}).catch(() => sendJson(res, 200, {
|
|
1513
1552
|
project,
|
|
1514
1553
|
devServer: target,
|
|
1515
1554
|
previews: boot,
|
|
1516
|
-
errors
|
|
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
|
|
1629
|
+
let relative4 = slash === -1 ? "" : rest.slice(slash + 1);
|
|
1591
1630
|
try {
|
|
1592
|
-
|
|
1631
|
+
relative4 = decodeURIComponent(relative4);
|
|
1593
1632
|
} catch {
|
|
1594
|
-
|
|
1633
|
+
relative4 = "";
|
|
1595
1634
|
}
|
|
1596
1635
|
const dir = fileMounts.get(slug);
|
|
1597
|
-
if (dir !== void 0 &&
|
|
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
|
|
2027
|
-
else
|
|
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
|
|
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" :
|
|
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)"}`
|