terminal-pilot 0.0.16 → 0.0.17

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 CHANGED
@@ -1,65 +1,68 @@
1
1
  #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
2
7
 
3
8
  // src/cli.ts
4
9
  import { realpath } from "node:fs/promises";
5
- import path12 from "node:path";
10
+ import path14 from "node:path";
6
11
  import { fileURLToPath as fileURLToPath5 } from "node:url";
7
12
 
8
13
  // ../toolcraft/src/cli.ts
9
- import { access as access2, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
10
- import path7 from "node:path";
11
- import { Command as CommanderCommand, CommanderError, InvalidArgumentError, Option } from "commander";
14
+ import { access as access2, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
15
+ import path9 from "node:path";
16
+ import {
17
+ Command as CommanderCommand,
18
+ CommanderError,
19
+ InvalidArgumentError,
20
+ Option
21
+ } from "commander";
12
22
 
13
23
  // ../design-system/src/tokens/colors.ts
14
24
  import chalk from "chalk";
15
25
  var dark = {
16
- header: (text4) => chalk.magentaBright.bold(text4),
17
- divider: (text4) => chalk.dim(text4),
18
- prompt: (text4) => chalk.cyan(text4),
19
- number: (text4) => chalk.cyanBright(text4),
20
- intro: (text4) => chalk.bgMagenta.white(` Poe - ${text4} `),
26
+ header: (text5) => chalk.magentaBright.bold(text5),
27
+ divider: (text5) => chalk.dim(text5),
28
+ prompt: (text5) => chalk.cyan(text5),
29
+ number: (text5) => chalk.cyanBright(text5),
30
+ intro: (text5) => chalk.bgMagenta.white(` Poe - ${text5} `),
21
31
  resolvedSymbol: chalk.magenta("\u25C7"),
22
32
  errorSymbol: chalk.red("\u25A0"),
23
- accent: (text4) => chalk.cyan(text4),
24
- muted: (text4) => chalk.dim(text4),
25
- success: (text4) => chalk.green(text4),
26
- warning: (text4) => chalk.yellow(text4),
27
- error: (text4) => chalk.red(text4),
28
- info: (text4) => chalk.magenta(text4),
29
- badge: (text4) => chalk.bgYellow.black(` ${text4} `)
33
+ accent: (text5) => chalk.cyan(text5),
34
+ muted: (text5) => chalk.dim(text5),
35
+ success: (text5) => chalk.green(text5),
36
+ warning: (text5) => chalk.yellow(text5),
37
+ error: (text5) => chalk.red(text5),
38
+ info: (text5) => chalk.magenta(text5),
39
+ badge: (text5) => chalk.bgYellow.black(` ${text5} `)
30
40
  };
31
41
  var light = {
32
- header: (text4) => chalk.hex("#a200ff").bold(text4),
33
- divider: (text4) => chalk.hex("#666666")(text4),
34
- prompt: (text4) => chalk.hex("#006699").bold(text4),
35
- number: (text4) => chalk.hex("#0077cc").bold(text4),
36
- intro: (text4) => chalk.bgHex("#a200ff").white(` Poe - ${text4} `),
42
+ header: (text5) => chalk.hex("#a200ff").bold(text5),
43
+ divider: (text5) => chalk.hex("#666666")(text5),
44
+ prompt: (text5) => chalk.hex("#006699").bold(text5),
45
+ number: (text5) => chalk.hex("#0077cc").bold(text5),
46
+ intro: (text5) => chalk.bgHex("#a200ff").white(` Poe - ${text5} `),
37
47
  resolvedSymbol: chalk.hex("#a200ff")("\u25C7"),
38
48
  errorSymbol: chalk.hex("#cc0000")("\u25A0"),
39
- accent: (text4) => chalk.hex("#006699").bold(text4),
40
- muted: (text4) => chalk.hex("#666666")(text4),
41
- success: (text4) => chalk.hex("#008800")(text4),
42
- warning: (text4) => chalk.hex("#cc6600")(text4),
43
- error: (text4) => chalk.hex("#cc0000")(text4),
44
- info: (text4) => chalk.hex("#a200ff")(text4),
45
- badge: (text4) => chalk.bgHex("#cc6600").white(` ${text4} `)
49
+ accent: (text5) => chalk.hex("#006699").bold(text5),
50
+ muted: (text5) => chalk.hex("#666666")(text5),
51
+ success: (text5) => chalk.hex("#008800")(text5),
52
+ warning: (text5) => chalk.hex("#cc6600")(text5),
53
+ error: (text5) => chalk.hex("#cc0000")(text5),
54
+ info: (text5) => chalk.hex("#a200ff")(text5),
55
+ badge: (text5) => chalk.bgHex("#cc6600").white(` ${text5} `)
46
56
  };
47
57
 
48
58
  // ../design-system/src/tokens/typography.ts
49
59
  import chalk2 from "chalk";
50
60
  var typography = {
51
- bold: (text4) => chalk2.bold(text4),
52
- dim: (text4) => chalk2.dim(text4),
53
- italic: (text4) => chalk2.italic(text4),
54
- underline: (text4) => chalk2.underline(text4),
55
- strikethrough: (text4) => chalk2.strikethrough(text4)
56
- };
57
-
58
- // ../design-system/src/tokens/widths.ts
59
- var widths = {
60
- header: 60,
61
- helpColumn: 24,
62
- maxLine: 80
61
+ bold: (text5) => chalk2.bold(text5),
62
+ dim: (text5) => chalk2.dim(text5),
63
+ italic: (text5) => chalk2.italic(text5),
64
+ underline: (text5) => chalk2.underline(text5),
65
+ strikethrough: (text5) => chalk2.strikethrough(text5)
63
66
  };
64
67
 
65
68
  // ../design-system/src/components/text.ts
@@ -153,6 +156,12 @@ var text = {
153
156
  if (format === "markdown") return `**${content}**`;
154
157
  return typography.bold(content);
155
158
  },
159
+ sectionHeader(content) {
160
+ const format = resolveOutputFormat();
161
+ if (format === "json") return content;
162
+ if (format === "markdown") return `## ${content}`;
163
+ return typography.bold(content.toUpperCase());
164
+ },
156
165
  command(content) {
157
166
  const format = resolveOutputFormat();
158
167
  if (format === "json") return content;
@@ -465,19 +474,248 @@ function createLogger(emitter) {
465
474
  var logger = createLogger();
466
475
 
467
476
  // ../design-system/src/components/help-formatter.ts
468
- function formatCommand(name, description) {
469
- const paddedName = name.padEnd(widths.helpColumn);
470
- return ` ${text.command(paddedName)} ${description}`;
477
+ function stripAnsi2(value) {
478
+ let output = "";
479
+ for (let index = 0; index < value.length; index += 1)
480
+ if (value[index] === "\x1B" && value[index + 1] === "[")
481
+ while (index < value.length && value[index] !== "m") index += 1;
482
+ else output += value[index];
483
+ return output;
484
+ }
485
+ function visibleWidth(value) {
486
+ return stripAnsi2(value).length;
487
+ }
488
+ function clamp(value, min, max) {
489
+ return Math.min(Math.max(value, min), max);
490
+ }
491
+ function padEndVisible(value, width) {
492
+ return value + " ".repeat(Math.max(0, width - visibleWidth(value)));
493
+ }
494
+ function isWhitespace(char) {
495
+ return char === " " || char === "\n" || char === " " || char === "\r";
496
+ }
497
+ function splitWords(value) {
498
+ const words = [];
499
+ let word = "";
500
+ for (const char of value) {
501
+ if (isWhitespace(char)) {
502
+ if (word) {
503
+ words.push(word);
504
+ word = "";
505
+ }
506
+ continue;
507
+ }
508
+ word += char;
509
+ }
510
+ if (word) {
511
+ words.push(word);
512
+ }
513
+ return words;
514
+ }
515
+ function wrapWords(value, width) {
516
+ const words = splitWords(value);
517
+ if (words.length === 0) {
518
+ return [""];
519
+ }
520
+ const lines = [];
521
+ let line = "";
522
+ for (const word of words) {
523
+ if (!line) {
524
+ line = word;
525
+ continue;
526
+ }
527
+ if (visibleWidth(line) + 1 + visibleWidth(word) <= width) {
528
+ line += ` ${word}`;
529
+ continue;
530
+ }
531
+ lines.push(line);
532
+ line = word;
533
+ }
534
+ lines.push(line);
535
+ return lines;
471
536
  }
472
- function formatOption(flags, description) {
473
- const paddedFlags = flags.padEnd(widths.helpColumn);
474
- return ` ${text.option(paddedFlags)} ${description}`;
537
+ function formatColumns(opts) {
538
+ const { rows } = opts;
539
+ if (rows.length === 0) {
540
+ return "";
541
+ }
542
+ const totalWidth = opts.totalWidth ?? process.stdout.columns ?? 100;
543
+ const minLeftWidth = opts.minLeftWidth ?? 12;
544
+ const maxLeftWidth = opts.maxLeftWidth ?? 32;
545
+ const gap = opts.gap ?? 3;
546
+ const indent = opts.indent ?? 2;
547
+ const maxLeftContentWidth = Math.max(...rows.map((row) => visibleWidth(row.left)));
548
+ const leftWidth = clamp(maxLeftContentWidth + gap, minLeftWidth, maxLeftWidth);
549
+ const rightWidth = Math.max(20, totalWidth - leftWidth - indent);
550
+ const firstIndent = " ".repeat(indent);
551
+ const continuationIndent = " ".repeat(indent + leftWidth);
552
+ return rows.flatMap((row) => {
553
+ if (row.right.length === 0) {
554
+ return [`${firstIndent}${row.left}`];
555
+ }
556
+ const rightLines = wrapWords(row.right, rightWidth);
557
+ if (visibleWidth(row.left) > leftWidth) {
558
+ return [
559
+ `${firstIndent}${row.left}`,
560
+ ...rightLines.map((line) => `${continuationIndent}${line}`)
561
+ ];
562
+ }
563
+ const firstLine = `${firstIndent}${padEndVisible(row.left, leftWidth)}${rightLines[0]}`;
564
+ const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
565
+ return [firstLine, ...continuationLines];
566
+ }).join("\n");
475
567
  }
476
568
  function formatCommandList(commands) {
477
- return commands.map((cmd) => formatCommand(cmd.name, cmd.description)).join("\n");
569
+ return formatColumns({
570
+ rows: commands.map((cmd) => ({
571
+ left: text.command(cmd.name),
572
+ right: cmd.description
573
+ }))
574
+ });
478
575
  }
479
576
  function formatOptionList(options) {
480
- return options.map((opt) => formatOption(opt.flags, opt.description)).join("\n");
577
+ return formatColumns({
578
+ rows: options.map((opt) => ({
579
+ left: text.option(opt.flags),
580
+ right: opt.description
581
+ }))
582
+ });
583
+ }
584
+
585
+ // ../design-system/src/components/help-formatter-plain.ts
586
+ var help_formatter_plain_exports = {};
587
+ __export(help_formatter_plain_exports, {
588
+ formatColumns: () => formatColumns2,
589
+ formatCommandList: () => formatCommandList2,
590
+ formatOptionList: () => formatOptionList2
591
+ });
592
+ function stripAnsi3(value) {
593
+ let output = "";
594
+ for (let index = 0; index < value.length; index += 1) {
595
+ if (value[index] === "\x1B") {
596
+ if (value[index + 1] === "[") {
597
+ index += 2;
598
+ while (index < value.length) {
599
+ const code = value.charCodeAt(index);
600
+ if (code >= 64 && code <= 126) {
601
+ break;
602
+ }
603
+ index += 1;
604
+ }
605
+ }
606
+ continue;
607
+ }
608
+ output += value[index];
609
+ }
610
+ return output;
611
+ }
612
+ function toAscii(value) {
613
+ let output = "";
614
+ const stripped = stripAnsi3(value);
615
+ for (let index = 0; index < stripped.length; index += 1) {
616
+ const code = stripped.charCodeAt(index);
617
+ output += code <= 127 ? stripped[index] : "?";
618
+ }
619
+ return output;
620
+ }
621
+ function clamp2(value, min, max) {
622
+ return Math.min(Math.max(value, min), max);
623
+ }
624
+ function padEndVisible2(value, width) {
625
+ return value + " ".repeat(Math.max(0, width - value.length));
626
+ }
627
+ function isWhitespace2(char) {
628
+ return char === " " || char === "\n" || char === " " || char === "\r";
629
+ }
630
+ function splitWords2(value) {
631
+ const words = [];
632
+ let word = "";
633
+ for (const char of value) {
634
+ if (isWhitespace2(char)) {
635
+ if (word) {
636
+ words.push(word);
637
+ word = "";
638
+ }
639
+ continue;
640
+ }
641
+ word += char;
642
+ }
643
+ if (word) {
644
+ words.push(word);
645
+ }
646
+ return words;
647
+ }
648
+ function wrapWords2(value, width) {
649
+ const words = splitWords2(value);
650
+ if (words.length === 0) {
651
+ return [""];
652
+ }
653
+ const lines = [];
654
+ let line = "";
655
+ for (const word of words) {
656
+ if (!line) {
657
+ line = word;
658
+ continue;
659
+ }
660
+ if (line.length + 1 + word.length <= width) {
661
+ line += ` ${word}`;
662
+ continue;
663
+ }
664
+ lines.push(line);
665
+ line = word;
666
+ }
667
+ lines.push(line);
668
+ return lines;
669
+ }
670
+ function formatColumns2(opts) {
671
+ const rows = opts.rows.map((row) => ({
672
+ left: toAscii(row.left),
673
+ right: toAscii(row.right)
674
+ }));
675
+ if (rows.length === 0) {
676
+ return "";
677
+ }
678
+ const totalWidth = opts.totalWidth ?? process.stdout.columns ?? 100;
679
+ const minLeftWidth = opts.minLeftWidth ?? 12;
680
+ const maxLeftWidth = opts.maxLeftWidth ?? 32;
681
+ const gap = opts.gap ?? 3;
682
+ const indent = opts.indent ?? 2;
683
+ const maxLeftContentWidth = Math.max(...rows.map((row) => row.left.length));
684
+ const leftWidth = clamp2(maxLeftContentWidth + gap, minLeftWidth, maxLeftWidth);
685
+ const rightWidth = Math.max(20, totalWidth - leftWidth - indent);
686
+ const firstIndent = " ".repeat(indent);
687
+ const continuationIndent = " ".repeat(indent + leftWidth);
688
+ return rows.flatMap((row) => {
689
+ if (row.right.length === 0) {
690
+ return [`${firstIndent}${row.left}`];
691
+ }
692
+ const rightLines = wrapWords2(row.right, rightWidth);
693
+ if (row.left.length > leftWidth) {
694
+ return [
695
+ `${firstIndent}${row.left}`,
696
+ ...rightLines.map((line) => `${continuationIndent}${line}`)
697
+ ];
698
+ }
699
+ const firstLine = `${firstIndent}${padEndVisible2(row.left, leftWidth)}${rightLines[0]}`;
700
+ const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
701
+ return [firstLine, ...continuationLines];
702
+ }).join("\n");
703
+ }
704
+ function formatCommandList2(commands) {
705
+ return formatColumns2({
706
+ rows: commands.map((cmd) => ({
707
+ left: cmd.name,
708
+ right: cmd.description
709
+ }))
710
+ });
711
+ }
712
+ function formatOptionList2(options) {
713
+ return formatColumns2({
714
+ rows: options.map((opt) => ({
715
+ left: opt.flags,
716
+ right: opt.description
717
+ }))
718
+ });
481
719
  }
482
720
 
483
721
  // ../design-system/src/components/table.ts
@@ -1330,134 +1568,1124 @@ function getCommandSourcePath(command) {
1330
1568
  // ../task-list/src/open.ts
1331
1569
  import * as fsPromises2 from "node:fs/promises";
1332
1570
 
1333
- // ../task-list/src/backends/markdown-dir.ts
1334
- import path3 from "node:path";
1335
-
1336
- // ../file-lock/src/lock.ts
1337
- import * as fsPromises from "node:fs/promises";
1338
- import * as os from "node:os";
1339
- var LockTimeoutError = class extends Error {
1340
- constructor(message2) {
1341
- super(message2);
1342
- this.name = "LockTimeoutError";
1343
- }
1344
- };
1345
- function createAbortError() {
1346
- const error2 = new Error("The operation was aborted.");
1347
- error2.name = "AbortError";
1348
- return error2;
1571
+ // ../task-list/src/state-machine.ts
1572
+ function isRecord(value) {
1573
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1349
1574
  }
1350
- function throwIfAborted(signal) {
1351
- if (signal?.aborted) {
1352
- throw createAbortError();
1575
+ function isStateList(value) {
1576
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
1577
+ }
1578
+ function canFireFromState(event, fromState) {
1579
+ if (event.from === "*") {
1580
+ return event.to !== fromState;
1353
1581
  }
1582
+ return event.from.includes(fromState);
1354
1583
  }
1355
- function sleep(ms, signal) {
1356
- if (!signal) {
1357
- return new Promise((resolve) => setTimeout(resolve, ms));
1584
+ function validateMachine(machine) {
1585
+ if (!isRecord(machine)) {
1586
+ throw new TypeError("State machine must be an object.");
1358
1587
  }
1359
- if (signal.aborted) {
1360
- return Promise.reject(createAbortError());
1588
+ if (!isStateList(machine.states)) {
1589
+ throw new TypeError("State machine states must be a string array.");
1361
1590
  }
1362
- return new Promise((resolve, reject) => {
1363
- const timeoutId = setTimeout(() => {
1364
- signal.removeEventListener("abort", onAbort);
1365
- resolve();
1366
- }, ms);
1367
- const onAbort = () => {
1368
- clearTimeout(timeoutId);
1369
- signal.removeEventListener("abort", onAbort);
1370
- reject(createAbortError());
1371
- };
1372
- signal.addEventListener("abort", onAbort, { once: true });
1373
- });
1374
- }
1375
- function backoff(attempt, minTimeout, maxTimeout) {
1376
- const delay = Math.min(maxTimeout, minTimeout * 2 ** attempt);
1377
- return delay + Math.random() * delay * 0.1;
1378
- }
1379
- function hasErrorCode(error2, code) {
1380
- return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === code;
1381
- }
1382
- function hasAnyErrorCode(error2, codes) {
1383
- return codes.some((code) => hasErrorCode(error2, code));
1384
- }
1385
- function isPidRunning(pid) {
1386
- try {
1387
- process.kill(pid, 0);
1388
- return true;
1389
- } catch (error2) {
1390
- return !hasErrorCode(error2, "ESRCH");
1591
+ const states = new Set(machine.states);
1592
+ if (typeof machine.initial !== "string") {
1593
+ throw new TypeError("State machine initial must be a string.");
1391
1594
  }
1392
- }
1393
- function createDefaultFs() {
1394
- return {
1395
- open: (path13, flags) => fsPromises.open(path13, flags),
1396
- readFile: (path13, encoding) => fsPromises.readFile(path13, encoding),
1397
- stat: fsPromises.stat,
1398
- unlink: fsPromises.unlink
1399
- };
1400
- }
1401
- async function removeLockFile(fs2, lockPath, signal) {
1402
- for (let attempt = 0; attempt <= 4; attempt += 1) {
1403
- throwIfAborted(signal);
1404
- try {
1405
- await fs2.unlink(lockPath);
1406
- return;
1407
- } catch (error2) {
1408
- if (hasErrorCode(error2, "ENOENT")) {
1409
- return;
1410
- }
1411
- if (!hasAnyErrorCode(error2, ["EPERM", "EBUSY"]) || attempt === 4) {
1412
- throw error2;
1595
+ if (!states.has(machine.initial)) {
1596
+ throw new Error(`Initial state "${machine.initial}" is not declared.`);
1597
+ }
1598
+ if (!isRecord(machine.events)) {
1599
+ throw new TypeError("State machine events must be an object.");
1600
+ }
1601
+ for (const [eventName, event] of Object.entries(machine.events)) {
1602
+ if (!isRecord(event)) {
1603
+ throw new TypeError(`Event "${eventName}" must be an object.`);
1604
+ }
1605
+ if (event.from !== "*" && !isStateList(event.from)) {
1606
+ throw new TypeError(`Event "${eventName}" has an invalid "from" definition.`);
1607
+ }
1608
+ if (typeof event.to !== "string") {
1609
+ throw new TypeError(`Event "${eventName}" target state must be a string.`);
1610
+ }
1611
+ if (!states.has(event.to)) {
1612
+ throw new Error(`Event "${eventName}" references unknown target state "${event.to}".`);
1613
+ }
1614
+ if (event.from !== "*") {
1615
+ for (const fromState of event.from) {
1616
+ if (!states.has(fromState)) {
1617
+ throw new Error(`Event "${eventName}" references unknown source state "${fromState}".`);
1618
+ }
1413
1619
  }
1414
1620
  }
1415
- await sleep(25 * 2 ** attempt, signal);
1416
1621
  }
1417
1622
  }
1418
- function parseLockMetadata(content) {
1419
- try {
1420
- const parsed = JSON.parse(content);
1421
- if (!parsed || typeof parsed !== "object" || !("host" in parsed) || !("pid" in parsed)) {
1422
- return void 0;
1423
- }
1424
- const { host, pid } = parsed;
1425
- if (typeof host === "string" && typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0) {
1426
- return {
1427
- host,
1428
- pid
1429
- };
1623
+ function eventsFromState(machine, fromState) {
1624
+ const events = [];
1625
+ for (const [eventName, event] of Object.entries(machine.events)) {
1626
+ if (canFireFromState(event, fromState)) {
1627
+ events.push(eventName);
1430
1628
  }
1431
- } catch (ignoredError) {
1432
- void ignoredError;
1433
1629
  }
1434
- return void 0;
1630
+ return events;
1435
1631
  }
1436
- async function readLockMetadata(fs2, lockPath) {
1437
- if (!fs2.readFile) {
1438
- return void 0;
1439
- }
1440
- try {
1441
- return parseLockMetadata(await fs2.readFile(lockPath, "utf8"));
1442
- } catch (error2) {
1443
- if (hasErrorCode(error2, "ENOENT")) {
1444
- return null;
1445
- }
1632
+ function findEvent(machine, fromState, eventName) {
1633
+ const event = machine.events[eventName];
1634
+ if (event === void 0) {
1446
1635
  return void 0;
1447
1636
  }
1637
+ return canFireFromState(event, fromState) ? event : void 0;
1448
1638
  }
1449
- async function shouldReclaimLock(options) {
1450
- const metadata = await readLockMetadata(options.fs, options.lockPath);
1451
- if (metadata === null) {
1452
- return "missing";
1639
+
1640
+ // ../task-list/src/types.ts
1641
+ var TaskNotFoundError = class extends Error {
1642
+ constructor(message2 = "Task not found.") {
1643
+ super(message2);
1644
+ this.name = "TaskNotFoundError";
1453
1645
  }
1454
- if (metadata?.host === os.hostname()) {
1455
- return !options.isPidRunning(metadata.pid);
1646
+ };
1647
+ var TaskAlreadyExistsError = class extends Error {
1648
+ constructor(message2 = "Task already exists.") {
1649
+ super(message2);
1650
+ this.name = "TaskAlreadyExistsError";
1456
1651
  }
1457
- return Date.now() - options.stat.mtimeMs > options.staleMs;
1458
- }
1459
- async function writeLockMetadata(handle) {
1460
- try {
1652
+ };
1653
+ var InvalidTransitionError = class extends Error {
1654
+ task;
1655
+ event;
1656
+ to;
1657
+ reason;
1658
+ constructor(messageOrOptions = "Invalid task transition.") {
1659
+ const options = typeof messageOrOptions === "string" ? {
1660
+ reason: messageOrOptions
1661
+ } : messageOrOptions;
1662
+ super(options.reason);
1663
+ this.name = "InvalidTransitionError";
1664
+ this.task = options.task;
1665
+ this.event = options.event;
1666
+ this.to = options.to;
1667
+ this.reason = options.reason;
1668
+ }
1669
+ };
1670
+ var MalformedTaskError = class extends Error {
1671
+ constructor(message2 = "Malformed task.") {
1672
+ super(message2);
1673
+ this.name = "MalformedTaskError";
1674
+ }
1675
+ };
1676
+ var OrderMismatchError = class extends Error {
1677
+ missing;
1678
+ extra;
1679
+ constructor(options) {
1680
+ const parts = [];
1681
+ if (options.missing.length > 0) {
1682
+ parts.push(`missing ${options.missing.map((id) => `"${id}"`).join(", ")}`);
1683
+ }
1684
+ if (options.extra.length > 0) {
1685
+ parts.push(`extra ${options.extra.map((id) => `"${id}"`).join(", ")}`);
1686
+ }
1687
+ super(`reorder requires the exact set of active task ids: ${parts.join("; ")}.`);
1688
+ this.name = "OrderMismatchError";
1689
+ this.missing = options.missing;
1690
+ this.extra = options.extra;
1691
+ }
1692
+ };
1693
+ var AnchorNotFoundError = class extends Error {
1694
+ anchor;
1695
+ constructor(anchor) {
1696
+ super(`Anchor task "${anchor}" not found.`);
1697
+ this.name = "AnchorNotFoundError";
1698
+ this.anchor = anchor;
1699
+ }
1700
+ };
1701
+
1702
+ // ../task-list/src/backends/gh-issues-client.ts
1703
+ import { text as text4 } from "node:stream/consumers";
1704
+
1705
+ // ../process-runner/src/docker/context.ts
1706
+ import { execSync } from "node:child_process";
1707
+
1708
+ // ../process-runner/src/docker/engine.ts
1709
+ import { execSync as execSync2 } from "node:child_process";
1710
+
1711
+ // ../process-runner/src/docker/docker-runner.ts
1712
+ import * as childProcess from "node:child_process";
1713
+ import { randomBytes } from "node:crypto";
1714
+
1715
+ // ../process-runner/src/docker/args.ts
1716
+ import path2 from "node:path";
1717
+
1718
+ // ../process-runner/src/docker/docker-execution-env.ts
1719
+ import { createHash, randomBytes as randomBytes2 } from "node:crypto";
1720
+ import { mkdtempSync, rmSync } from "node:fs";
1721
+ import { readFile } from "node:fs/promises";
1722
+ import { tmpdir } from "node:os";
1723
+ import path3 from "node:path";
1724
+
1725
+ // ../process-runner/src/host/host-runner.ts
1726
+ import { spawn as spawnChildProcess } from "node:child_process";
1727
+ function createHostRunner(options = {}) {
1728
+ const detached = options.detached === true;
1729
+ return {
1730
+ name: "host",
1731
+ exec(spec) {
1732
+ const stdinMode = spec.stdin ?? "ignore";
1733
+ const stdoutMode = spec.stdout ?? "pipe";
1734
+ const stderrMode = spec.stderr ?? "pipe";
1735
+ const stdio = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" ? "inherit" : [stdinMode, stdoutMode, stderrMode];
1736
+ const child = spawnChildProcess(spec.command, spec.args ?? [], {
1737
+ cwd: spec.cwd,
1738
+ env: spec.env,
1739
+ stdio,
1740
+ ...detached ? { detached: true } : {}
1741
+ });
1742
+ if (detached) {
1743
+ child.unref();
1744
+ }
1745
+ const kill = (signal) => {
1746
+ if (detached && process.platform !== "win32" && child.pid !== void 0) {
1747
+ process.kill(-child.pid, signal);
1748
+ return;
1749
+ }
1750
+ child.kill(signal);
1751
+ };
1752
+ let settled = false;
1753
+ let resolveResult = null;
1754
+ const result = new Promise((resolve) => {
1755
+ resolveResult = resolve;
1756
+ });
1757
+ const cleanupAbort = bindAbortSignal(spec.signal, () => {
1758
+ kill("SIGTERM");
1759
+ });
1760
+ child.once("close", (code) => {
1761
+ if (settled) return;
1762
+ settled = true;
1763
+ cleanupAbort();
1764
+ resolveResult?.({ exitCode: code ?? 1 });
1765
+ });
1766
+ child.once("error", () => {
1767
+ if (settled) return;
1768
+ settled = true;
1769
+ cleanupAbort();
1770
+ resolveResult?.({ exitCode: 1 });
1771
+ });
1772
+ return {
1773
+ pid: child.pid ?? null,
1774
+ stdin: child.stdin,
1775
+ stdout: child.stdout,
1776
+ stderr: child.stderr,
1777
+ result,
1778
+ kill
1779
+ };
1780
+ }
1781
+ };
1782
+ }
1783
+ function bindAbortSignal(signal, onAbort) {
1784
+ if (signal === void 0) {
1785
+ return () => {
1786
+ };
1787
+ }
1788
+ if (signal.aborted) {
1789
+ onAbort();
1790
+ return () => {
1791
+ };
1792
+ }
1793
+ signal.addEventListener("abort", onAbort, { once: true });
1794
+ return () => {
1795
+ signal.removeEventListener("abort", onAbort);
1796
+ };
1797
+ }
1798
+
1799
+ // ../process-runner/src/testing/mock-runner.ts
1800
+ import { Readable, Writable } from "node:stream";
1801
+
1802
+ // ../task-list/src/backends/gh-issues-client.ts
1803
+ var DEFAULT_ENDPOINT = "https://api.github.com/graphql";
1804
+ var USER_AGENT = "poe-code-task-list/0.0.1";
1805
+ var AUTH_ERROR = "gh auth token failed; install gh, run 'gh auth login', or pass auth: { token }";
1806
+ function createGhClient(options) {
1807
+ const fetchImpl = options.fetch ?? fetch;
1808
+ const endpoint = options.endpoint || DEFAULT_ENDPOINT;
1809
+ return {
1810
+ async graphql(query, variables) {
1811
+ const response = await fetchImpl(endpoint, {
1812
+ method: "POST",
1813
+ headers: {
1814
+ Authorization: `Bearer ${options.token}`,
1815
+ "Content-Type": "application/json",
1816
+ "User-Agent": USER_AGENT
1817
+ },
1818
+ body: JSON.stringify({ query, variables })
1819
+ });
1820
+ const body = await response.text();
1821
+ if (response.status !== 200) {
1822
+ throw new Error(`GitHub GraphQL request failed with status ${response.status}: ${body}`);
1823
+ }
1824
+ const parsed = JSON.parse(body);
1825
+ const firstError = parsed.errors?.[0];
1826
+ if (firstError !== void 0) {
1827
+ throw new Error(firstError.message ?? "GitHub GraphQL request failed");
1828
+ }
1829
+ return parsed.data;
1830
+ }
1831
+ };
1832
+ }
1833
+ async function resolveAuth(options) {
1834
+ if (options.explicitToken !== void 0) {
1835
+ return options.explicitToken;
1836
+ }
1837
+ const runner = options.runner ?? createHostRunner();
1838
+ const handle = runner.exec({
1839
+ command: "gh",
1840
+ args: ["auth", "token"],
1841
+ stdout: "pipe",
1842
+ stderr: "pipe"
1843
+ });
1844
+ const [stdout, , result] = await Promise.all([
1845
+ handle.stdout === null ? Promise.resolve("") : text4(handle.stdout),
1846
+ handle.stderr === null ? Promise.resolve("") : text4(handle.stderr),
1847
+ handle.result
1848
+ ]);
1849
+ const token = stdout.trim();
1850
+ if (result.exitCode !== 0 || token.length === 0) {
1851
+ throw new Error(AUTH_ERROR);
1852
+ }
1853
+ return token;
1854
+ }
1855
+ function resolveEndpoint(options = {}) {
1856
+ const env = options.env ?? process.env;
1857
+ const host = env.GH_HOST;
1858
+ if (host !== void 0 && host !== "" && host !== "github.com") {
1859
+ return `https://${host}/api/graphql`;
1860
+ }
1861
+ return DEFAULT_ENDPOINT;
1862
+ }
1863
+
1864
+ // ../task-list/src/backends/utils.ts
1865
+ import path4 from "node:path";
1866
+ function compareCreated(left, right) {
1867
+ const leftCreated = typeof left.raw.created === "string" ? left.raw.created : "";
1868
+ const rightCreated = typeof right.raw.created === "string" ? right.raw.created : "";
1869
+ if (leftCreated === "" && rightCreated === "") {
1870
+ return left.task.qualifiedId.localeCompare(right.task.qualifiedId);
1871
+ }
1872
+ if (leftCreated === "") return 1;
1873
+ if (rightCreated === "") return -1;
1874
+ return leftCreated.localeCompare(rightCreated);
1875
+ }
1876
+ function applyOrder(entries, order) {
1877
+ if (order === "alphabetical") {
1878
+ return sortTasks(entries.map((entry) => entry.task));
1879
+ }
1880
+ if (order === "created") {
1881
+ return [...entries].sort(compareCreated).map((entry) => entry.task);
1882
+ }
1883
+ return entries.map((entry) => entry.task);
1884
+ }
1885
+ var tmpFileCounter = 0;
1886
+ function hasErrorCode(error2, code) {
1887
+ return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === code;
1888
+ }
1889
+ function isRecord2(value) {
1890
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1891
+ }
1892
+ function sortStrings(values) {
1893
+ return [...values].sort((left, right) => left.localeCompare(right));
1894
+ }
1895
+ function sortTasks(tasks) {
1896
+ return [...tasks].sort((left, right) => left.qualifiedId.localeCompare(right.qualifiedId));
1897
+ }
1898
+ function validateTaskId(id) {
1899
+ if (id.length === 0 || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
1900
+ throw new Error(`Invalid task id "${id}".`);
1901
+ }
1902
+ return id;
1903
+ }
1904
+ async function statIfExists(fs2, filePath) {
1905
+ try {
1906
+ return await fs2.stat(filePath);
1907
+ } catch (error2) {
1908
+ if (hasErrorCode(error2, "ENOENT")) {
1909
+ return void 0;
1910
+ }
1911
+ throw error2;
1912
+ }
1913
+ }
1914
+ async function writeAtomically(fs2, filePath, content) {
1915
+ const tempPath = `${filePath}.tmp-${process.pid}-${tmpFileCounter}`;
1916
+ tmpFileCounter += 1;
1917
+ await fs2.mkdir(path4.dirname(filePath), { recursive: true });
1918
+ try {
1919
+ await fs2.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
1920
+ await fs2.rename(tempPath, filePath);
1921
+ } catch (error2) {
1922
+ try {
1923
+ await fs2.unlink(tempPath);
1924
+ } catch (unlinkError) {
1925
+ if (!hasErrorCode(unlinkError, "ENOENT")) {
1926
+ throw unlinkError;
1927
+ }
1928
+ }
1929
+ throw error2;
1930
+ }
1931
+ }
1932
+
1933
+ // ../task-list/src/backends/gh-issues.ts
1934
+ var PROJECT_ORGANIZATION_QUERY = `query Project($owner: String!, $number: Int!) {
1935
+ organization(login: $owner) {
1936
+ projectV2(number: $number) {
1937
+ id
1938
+ title
1939
+ field(name: "Status") {
1940
+ ... on ProjectV2SingleSelectField {
1941
+ id
1942
+ options { id name }
1943
+ }
1944
+ }
1945
+ }
1946
+ }
1947
+ }`;
1948
+ var PROJECT_USER_QUERY = `query Project($owner: String!, $number: Int!) {
1949
+ user(login: $owner) {
1950
+ projectV2(number: $number) {
1951
+ id
1952
+ title
1953
+ field(name: "Status") {
1954
+ ... on ProjectV2SingleSelectField {
1955
+ id
1956
+ options { id name }
1957
+ }
1958
+ }
1959
+ }
1960
+ }
1961
+ }`;
1962
+ var PROJECT_ITEMS_QUERY = `query Items($projectId: ID!, $after: String) {
1963
+ node(id: $projectId) {
1964
+ ... on ProjectV2 {
1965
+ items(first: 100, after: $after) {
1966
+ nodes {
1967
+ id
1968
+ content {
1969
+ __typename
1970
+ ... on Issue {
1971
+ number
1972
+ title
1973
+ body
1974
+ url
1975
+ createdAt
1976
+ labels(first: 50) { nodes { name } }
1977
+ assignees(first: 20) { nodes { login } }
1978
+ milestone { title }
1979
+ }
1980
+ }
1981
+ fieldValueByName(name: "Status") {
1982
+ ... on ProjectV2ItemFieldSingleSelectValue {
1983
+ name
1984
+ }
1985
+ }
1986
+ }
1987
+ pageInfo { hasNextPage endCursor }
1988
+ }
1989
+ }
1990
+ }
1991
+ }`;
1992
+ var ISSUE_QUERY = `query Issue($owner: String!, $repo: String!, $number: Int!) {
1993
+ repository(owner: $owner, name: $repo) {
1994
+ issue(number: $number) {
1995
+ number
1996
+ title
1997
+ body
1998
+ url
1999
+ createdAt
2000
+ labels(first: 50) { nodes { name } }
2001
+ assignees(first: 20) { nodes { login } }
2002
+ milestone { title }
2003
+ projectItems(first: 10) {
2004
+ nodes {
2005
+ id
2006
+ project { id }
2007
+ fieldValueByName(name: "Status") {
2008
+ ... on ProjectV2ItemFieldSingleSelectValue {
2009
+ name
2010
+ }
2011
+ }
2012
+ }
2013
+ }
2014
+ }
2015
+ }
2016
+ }`;
2017
+ var REPOSITORY_QUERY = `query Repository($owner: String!, $repo: String!) {
2018
+ repository(owner: $owner, name: $repo) {
2019
+ id
2020
+ }
2021
+ }`;
2022
+ var ISSUE_ID_QUERY = `query IssueId($owner: String!, $repo: String!, $number: Int!) {
2023
+ repository(owner: $owner, name: $repo) {
2024
+ issue(number: $number) {
2025
+ id
2026
+ }
2027
+ }
2028
+ }`;
2029
+ var ISSUE_PROJECT_ITEM_QUERY = `query IssueProjectItem($owner: String!, $repo: String!, $number: Int!) {
2030
+ repository(owner: $owner, name: $repo) {
2031
+ issue(number: $number) {
2032
+ id
2033
+ projectItems(first: 10) {
2034
+ nodes {
2035
+ id
2036
+ project { id }
2037
+ }
2038
+ }
2039
+ }
2040
+ }
2041
+ }`;
2042
+ var CREATE_ISSUE_MUTATION = `mutation CreateIssue($input: CreateIssueInput!) {
2043
+ createIssue(input: $input) {
2044
+ issue {
2045
+ id
2046
+ number
2047
+ }
2048
+ }
2049
+ }`;
2050
+ var ADD_PROJECT_ITEM_MUTATION = `mutation AddProjectItem($input: AddProjectV2ItemByIdInput!) {
2051
+ addProjectV2ItemById(input: $input) {
2052
+ item {
2053
+ id
2054
+ }
2055
+ }
2056
+ }`;
2057
+ var UPDATE_STATUS_MUTATION = `mutation UpdateProjectItemStatus($input: UpdateProjectV2ItemFieldValueInput!) {
2058
+ updateProjectV2ItemFieldValue(input: $input) {
2059
+ projectV2Item {
2060
+ id
2061
+ }
2062
+ }
2063
+ }`;
2064
+ var UPDATE_ISSUE_MUTATION = `mutation UpdateIssue($input: UpdateIssueInput!) {
2065
+ updateIssue(input: $input) {
2066
+ issue {
2067
+ id
2068
+ }
2069
+ }
2070
+ }`;
2071
+ var UPDATE_PROJECT_ITEM_POSITION_MUTATION = `mutation UpdateProjectItemPosition($input: UpdateProjectV2ItemPositionInput!) {
2072
+ updateProjectV2ItemPosition(input: $input) {
2073
+ clientMutationId
2074
+ }
2075
+ }`;
2076
+ var DELETE_PROJECT_ITEM_MUTATION = `mutation DeleteProjectItem($input: DeleteProjectV2ItemInput!) {
2077
+ deleteProjectV2Item(input: $input) {
2078
+ deletedItemId
2079
+ }
2080
+ }`;
2081
+ async function ghIssuesBackend(deps) {
2082
+ const client = createGhClient({
2083
+ token: deps.token,
2084
+ endpoint: deps.endpoint,
2085
+ fetch: deps.fetch
2086
+ });
2087
+ const listName = `${deps.project.owner}/${deps.project.number}`;
2088
+ const variables = {
2089
+ owner: deps.project.owner,
2090
+ number: deps.project.number
2091
+ };
2092
+ const organizationResult = await client.graphql(
2093
+ PROJECT_ORGANIZATION_QUERY,
2094
+ variables
2095
+ );
2096
+ let project = organizationResult.organization?.projectV2 ?? null;
2097
+ if (project === null) {
2098
+ const userResult = await client.graphql(PROJECT_USER_QUERY, variables);
2099
+ project = userResult.user?.projectV2 ?? null;
2100
+ }
2101
+ if (project === null) {
2102
+ throw new Error(`Project ${listName} not found or inaccessible.`);
2103
+ }
2104
+ const field = project.field;
2105
+ if (!isStatusField(field)) {
2106
+ throw new Error(`Project ${listName} has no Status field; gh-issues requires one.`);
2107
+ }
2108
+ if (field.options.length === 0) {
2109
+ throw new Error(`Project ${listName} Status field has no options.`);
2110
+ }
2111
+ const session = createSession(project, field);
2112
+ const repoParts = parseRepo(deps.repo);
2113
+ const context = {
2114
+ client,
2115
+ repoOwner: repoParts.owner,
2116
+ repoName: repoParts.name,
2117
+ issueIds: /* @__PURE__ */ new Map()
2118
+ };
2119
+ function list(name) {
2120
+ assertSingleList(name, listName);
2121
+ return createTasksView(listName, session, context);
2122
+ }
2123
+ return {
2124
+ list,
2125
+ async lists() {
2126
+ return [listName];
2127
+ },
2128
+ async allTasks(filter) {
2129
+ return list(listName).all(filter);
2130
+ },
2131
+ async get(qualifiedId) {
2132
+ const id = parseQualifiedId(qualifiedId, listName);
2133
+ return list(listName).get(id);
2134
+ },
2135
+ async moveBetweenLists(_qualifiedId, _targetList) {
2136
+ throw singleListError(listName);
2137
+ }
2138
+ };
2139
+ }
2140
+ function createSession(project, field) {
2141
+ const statusOptions = new Map(field.options.map((option) => [option.name, option.id]));
2142
+ const states = field.options.map((option) => option.name);
2143
+ const events = Object.fromEntries(
2144
+ states.map((state) => [state, Object.freeze({ from: "*", to: state })])
2145
+ );
2146
+ const stateMachine = Object.freeze({
2147
+ states: Object.freeze([...states]),
2148
+ initial: states[0],
2149
+ events: Object.freeze(events)
2150
+ });
2151
+ return Object.freeze({
2152
+ projectId: project.id,
2153
+ statusFieldId: field.id,
2154
+ statusOptions,
2155
+ stateMachine
2156
+ });
2157
+ }
2158
+ function createTasksView(name, session, context) {
2159
+ return {
2160
+ name,
2161
+ stateMachine: session.stateMachine,
2162
+ async all(filter) {
2163
+ if (filter?.includeArchived === true) {
2164
+ return [];
2165
+ }
2166
+ const tasks = await fetchProjectTasks(name, session, context);
2167
+ const filteredTasks = filter?.state === void 0 ? tasks : tasks.filter((task) => task.state === filter.state);
2168
+ if (filter?.order === "alphabetical") {
2169
+ return sortTasks(filteredTasks);
2170
+ }
2171
+ if (filter?.order === "created") {
2172
+ return applyOrder(
2173
+ filteredTasks.map((task) => ({
2174
+ task,
2175
+ raw: {
2176
+ created: task.metadata.created
2177
+ }
2178
+ })),
2179
+ "created"
2180
+ );
2181
+ }
2182
+ return filteredTasks;
2183
+ },
2184
+ async get(id) {
2185
+ return fetchIssueTask(id, name, session, context);
2186
+ },
2187
+ /**
2188
+ * GitHub Issues assigns the issue number, so TaskCreate.id is intentionally ignored.
2189
+ */
2190
+ async create(input) {
2191
+ const repositoryId = await resolveRepositoryId(context);
2192
+ const created = await context.client.graphql(CREATE_ISSUE_MUTATION, {
2193
+ input: {
2194
+ repositoryId,
2195
+ title: input.name,
2196
+ body: input.description ?? ""
2197
+ }
2198
+ });
2199
+ const issue = created.createIssue?.issue;
2200
+ const issueId = issue?.id ?? null;
2201
+ const issueNumber = issue?.number ?? null;
2202
+ if (issueId === null || issueNumber === null) {
2203
+ throw new Error("GitHub createIssue response did not include issue id and number.");
2204
+ }
2205
+ context.issueIds.set(issueNumber, issueId);
2206
+ const added = await context.client.graphql(
2207
+ ADD_PROJECT_ITEM_MUTATION,
2208
+ {
2209
+ input: {
2210
+ projectId: session.projectId,
2211
+ contentId: issueId
2212
+ }
2213
+ }
2214
+ );
2215
+ const projectItemId = added.addProjectV2ItemById?.item?.id ?? null;
2216
+ if (projectItemId === null) {
2217
+ throw new Error("GitHub addProjectV2ItemById response did not include project item id.");
2218
+ }
2219
+ await updateProjectItemStatus(projectItemId, session.stateMachine.initial, session, context);
2220
+ return fetchIssueTask(String(issueNumber), name, session, context);
2221
+ },
2222
+ async update(id, patch) {
2223
+ const input = {};
2224
+ if (patch.name !== void 0) {
2225
+ input.title = patch.name;
2226
+ }
2227
+ if (patch.description !== void 0) {
2228
+ input.body = patch.description;
2229
+ }
2230
+ if (Object.keys(input).length > 0) {
2231
+ input.id = await resolveIssueId(id, name, context);
2232
+ await context.client.graphql(UPDATE_ISSUE_MUTATION, {
2233
+ input
2234
+ });
2235
+ }
2236
+ return fetchIssueTask(id, name, session, context);
2237
+ },
2238
+ async fire(id, event, _opts) {
2239
+ if (!session.statusOptions.has(event)) {
2240
+ throw new InvalidTransitionError({
2241
+ event,
2242
+ to: event,
2243
+ reason: `Unknown gh-issues Status state "${event}".`
2244
+ });
2245
+ }
2246
+ const projectItemId = await resolveProjectItemId(id, name, session, context);
2247
+ await updateProjectItemStatus(projectItemId, event, session, context);
2248
+ return fetchIssueTask(id, name, session, context);
2249
+ },
2250
+ async canFire(id, event) {
2251
+ return findEvent(session.stateMachine, id, event) !== void 0;
2252
+ },
2253
+ async events(id) {
2254
+ return eventsFromState(session.stateMachine, id);
2255
+ },
2256
+ async delete(id) {
2257
+ const projectItemId = await resolveProjectItemId(id, name, session, context);
2258
+ await context.client.graphql(DELETE_PROJECT_ITEM_MUTATION, {
2259
+ input: {
2260
+ projectId: session.projectId,
2261
+ itemId: projectItemId
2262
+ }
2263
+ });
2264
+ },
2265
+ async move(id, anchor) {
2266
+ const projectItemId = await resolveProjectItemId(id, name, session, context);
2267
+ const afterId = await resolveMoveAfterId(id, anchor, name, session, context);
2268
+ await updateProjectItemPosition(projectItemId, afterId, session, context);
2269
+ return fetchIssueTask(id, name, session, context);
2270
+ },
2271
+ async reorder(ids) {
2272
+ const currentTasks = await fetchProjectTasks(name, session, context);
2273
+ const currentIds = currentTasks.map((task) => task.id);
2274
+ const currentSet = new Set(currentIds);
2275
+ const inputSet = new Set(ids);
2276
+ const seenInputIds = /* @__PURE__ */ new Set();
2277
+ const missing = currentIds.filter((id) => !inputSet.has(id));
2278
+ const extra = ids.filter((id) => {
2279
+ if (!currentSet.has(id)) {
2280
+ return true;
2281
+ }
2282
+ if (seenInputIds.has(id)) {
2283
+ return true;
2284
+ }
2285
+ seenInputIds.add(id);
2286
+ return false;
2287
+ });
2288
+ if (missing.length > 0 || extra.length > 0) {
2289
+ throw new OrderMismatchError({ missing, extra });
2290
+ }
2291
+ const itemIdsByTaskId = new Map(
2292
+ currentTasks.map((task) => [task.id, projectItemIdFromTask(task)])
2293
+ );
2294
+ let afterId = null;
2295
+ for (const id of ids) {
2296
+ const projectItemId = itemIdsByTaskId.get(id);
2297
+ if (projectItemId === void 0) {
2298
+ throw new OrderMismatchError({ missing: [id], extra: [] });
2299
+ }
2300
+ await updateProjectItemPosition(projectItemId, afterId, session, context);
2301
+ afterId = projectItemId;
2302
+ }
2303
+ return fetchProjectTasks(name, session, context);
2304
+ }
2305
+ };
2306
+ }
2307
+ async function resolveRepositoryId(context) {
2308
+ if (context.repositoryId !== void 0) {
2309
+ return context.repositoryId;
2310
+ }
2311
+ const result = await context.client.graphql(REPOSITORY_QUERY, {
2312
+ owner: context.repoOwner,
2313
+ repo: context.repoName
2314
+ });
2315
+ const repositoryId = result.repository?.id ?? null;
2316
+ if (repositoryId === null) {
2317
+ throw new Error(
2318
+ `Repository ${context.repoOwner}/${context.repoName} not found or inaccessible.`
2319
+ );
2320
+ }
2321
+ context.repositoryId = repositoryId;
2322
+ return repositoryId;
2323
+ }
2324
+ async function resolveIssueId(id, listName, context) {
2325
+ const issueNumber = parseIssueNumber(id, listName);
2326
+ const cachedIssueId = context.issueIds.get(issueNumber);
2327
+ if (cachedIssueId !== void 0) {
2328
+ return cachedIssueId;
2329
+ }
2330
+ const result = await context.client.graphql(ISSUE_ID_QUERY, {
2331
+ owner: context.repoOwner,
2332
+ repo: context.repoName,
2333
+ number: issueNumber
2334
+ });
2335
+ const issueId = result.repository?.issue?.id ?? null;
2336
+ if (issueId === null) {
2337
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
2338
+ }
2339
+ context.issueIds.set(issueNumber, issueId);
2340
+ return issueId;
2341
+ }
2342
+ async function resolveProjectItemId(id, listName, session, context) {
2343
+ const issueNumber = parseIssueNumber(id, listName);
2344
+ const result = await context.client.graphql(ISSUE_PROJECT_ITEM_QUERY, {
2345
+ owner: context.repoOwner,
2346
+ repo: context.repoName,
2347
+ number: issueNumber
2348
+ });
2349
+ const issue = result.repository?.issue ?? null;
2350
+ if (issue === null) {
2351
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
2352
+ }
2353
+ if (issue.id !== void 0 && issue.id !== null) {
2354
+ context.issueIds.set(issueNumber, issue.id);
2355
+ }
2356
+ const projectItem = issue.projectItems?.nodes?.find((item) => item.project?.id === session.projectId) ?? null;
2357
+ if (projectItem === null) {
2358
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
2359
+ }
2360
+ return projectItem.id;
2361
+ }
2362
+ async function updateProjectItemStatus(projectItemId, state, session, context) {
2363
+ const optionId = session.statusOptions.get(state);
2364
+ if (optionId === void 0) {
2365
+ throw new InvalidTransitionError({
2366
+ to: state,
2367
+ reason: `Unknown gh-issues Status state "${state}".`
2368
+ });
2369
+ }
2370
+ await context.client.graphql(UPDATE_STATUS_MUTATION, {
2371
+ input: {
2372
+ projectId: session.projectId,
2373
+ itemId: projectItemId,
2374
+ fieldId: session.statusFieldId,
2375
+ value: {
2376
+ singleSelectOptionId: optionId
2377
+ }
2378
+ }
2379
+ });
2380
+ }
2381
+ async function updateProjectItemPosition(projectItemId, afterId, session, context) {
2382
+ await context.client.graphql(UPDATE_PROJECT_ITEM_POSITION_MUTATION, {
2383
+ input: {
2384
+ projectId: session.projectId,
2385
+ itemId: projectItemId,
2386
+ afterId
2387
+ }
2388
+ });
2389
+ }
2390
+ async function resolveMoveAfterId(movingId, anchor, listName, session, context) {
2391
+ if ("position" in anchor) {
2392
+ if (anchor.position === "top") {
2393
+ return null;
2394
+ }
2395
+ const tasks2 = await fetchProjectTasks(listName, session, context);
2396
+ for (let index = tasks2.length - 1; index >= 0; index -= 1) {
2397
+ const task = tasks2[index];
2398
+ if (task.id !== movingId) {
2399
+ return projectItemIdFromTask(task);
2400
+ }
2401
+ }
2402
+ return null;
2403
+ }
2404
+ const anchorId = "before" in anchor ? anchor.before : anchor.after;
2405
+ let anchorProjectItemId;
2406
+ try {
2407
+ anchorProjectItemId = await resolveProjectItemId(anchorId, listName, session, context);
2408
+ } catch (error2) {
2409
+ if (error2 instanceof TaskNotFoundError) {
2410
+ throw new AnchorNotFoundError(anchorId);
2411
+ }
2412
+ throw error2;
2413
+ }
2414
+ if ("after" in anchor) {
2415
+ return anchorProjectItemId;
2416
+ }
2417
+ const tasks = await fetchProjectTasks(listName, session, context);
2418
+ const anchorIndex = tasks.findIndex((task) => task.id === anchorId);
2419
+ if (anchorIndex < 0) {
2420
+ throw new AnchorNotFoundError(anchorId);
2421
+ }
2422
+ for (let index = anchorIndex - 1; index >= 0; index -= 1) {
2423
+ const predecessor = tasks[index];
2424
+ if (predecessor.id !== movingId) {
2425
+ return projectItemIdFromTask(predecessor);
2426
+ }
2427
+ }
2428
+ return null;
2429
+ }
2430
+ async function fetchProjectTasks(listName, session, context) {
2431
+ const tasks = [];
2432
+ let after = null;
2433
+ do {
2434
+ const result = await context.client.graphql(
2435
+ PROJECT_ITEMS_QUERY,
2436
+ {
2437
+ projectId: session.projectId,
2438
+ after
2439
+ }
2440
+ );
2441
+ const items = result.node?.items;
2442
+ for (const item of items?.nodes ?? []) {
2443
+ const task = mapProjectItemToTask(item, listName, session);
2444
+ if (task !== null) {
2445
+ tasks.push(task);
2446
+ }
2447
+ }
2448
+ after = items?.pageInfo?.hasNextPage === true ? items.pageInfo.endCursor ?? null : null;
2449
+ } while (after !== null);
2450
+ return tasks;
2451
+ }
2452
+ async function fetchIssueTask(id, listName, session, context) {
2453
+ const issueNumber = parseIssueNumber(id, listName);
2454
+ const result = await context.client.graphql(ISSUE_QUERY, {
2455
+ owner: context.repoOwner,
2456
+ repo: context.repoName,
2457
+ number: issueNumber
2458
+ });
2459
+ const issue = result.repository?.issue ?? null;
2460
+ if (issue === null) {
2461
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
2462
+ }
2463
+ const projectItem = issue.projectItems?.nodes?.find((item) => item.project?.id === session.projectId) ?? null;
2464
+ if (projectItem === null) {
2465
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
2466
+ }
2467
+ return mapIssueToTask({
2468
+ issue,
2469
+ projectItemId: projectItem.id,
2470
+ statusName: projectItem.fieldValueByName?.name ?? null,
2471
+ listName,
2472
+ initialState: session.stateMachine.initial
2473
+ });
2474
+ }
2475
+ function parseIssueNumber(id, listName) {
2476
+ const issueNumber = Number(id);
2477
+ if (!Number.isInteger(issueNumber) || issueNumber < 1) {
2478
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
2479
+ }
2480
+ return issueNumber;
2481
+ }
2482
+ function mapProjectItemToTask(item, listName, session) {
2483
+ const content = item.content;
2484
+ if (!isIssueNode(content)) {
2485
+ return null;
2486
+ }
2487
+ return mapIssueToTask({
2488
+ issue: content,
2489
+ projectItemId: item.id,
2490
+ statusName: item.fieldValueByName?.name ?? null,
2491
+ listName,
2492
+ initialState: session.stateMachine.initial
2493
+ });
2494
+ }
2495
+ function isIssueNode(value) {
2496
+ return isRecord3(value) && value.__typename === "Issue" && typeof value.number === "number" && typeof value.title === "string" && typeof value.url === "string" && typeof value.createdAt === "string";
2497
+ }
2498
+ function mapIssueToTask(options) {
2499
+ const id = String(options.issue.number);
2500
+ const labels = (options.issue.labels?.nodes ?? []).filter((node) => node !== null).map((node) => node.name);
2501
+ const assignees = (options.issue.assignees?.nodes ?? []).filter((node) => node !== null).map((node) => node.login);
2502
+ return {
2503
+ list: options.listName,
2504
+ id,
2505
+ qualifiedId: `${options.listName}/${id}`,
2506
+ name: options.issue.title,
2507
+ description: options.issue.body ?? "",
2508
+ state: options.statusName ?? options.initialState,
2509
+ metadata: {
2510
+ url: options.issue.url,
2511
+ labels,
2512
+ assignees,
2513
+ milestone: options.issue.milestone?.title ?? null,
2514
+ projectItemId: options.projectItemId,
2515
+ created: options.issue.createdAt
2516
+ }
2517
+ };
2518
+ }
2519
+ function projectItemIdFromTask(task) {
2520
+ const projectItemId = task.metadata.projectItemId;
2521
+ if (typeof projectItemId !== "string") {
2522
+ throw new Error(`Task "${task.qualifiedId}" is missing GitHub project item metadata.`);
2523
+ }
2524
+ return projectItemId;
2525
+ }
2526
+ function parseRepo(repo) {
2527
+ const parts = repo.split("/");
2528
+ if (parts.length !== 2 || parts[0] === "" || parts[1] === "") {
2529
+ throw new Error(`Invalid GitHub repository "${repo}". Expected "owner/name".`);
2530
+ }
2531
+ return {
2532
+ owner: parts[0],
2533
+ name: parts[1]
2534
+ };
2535
+ }
2536
+ function isRecord3(value) {
2537
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2538
+ }
2539
+ function isStatusOption(value) {
2540
+ return isRecord3(value) && typeof value.id === "string" && typeof value.name === "string";
2541
+ }
2542
+ function isStatusField(value) {
2543
+ return isRecord3(value) && typeof value.id === "string" && Array.isArray(value.options) && value.options.every(isStatusOption);
2544
+ }
2545
+ function assertSingleList(name, listName) {
2546
+ if (name !== listName) {
2547
+ throw singleListError(listName);
2548
+ }
2549
+ }
2550
+ function singleListError(listName) {
2551
+ return new Error(`gh-issues backend has a single list ${listName}`);
2552
+ }
2553
+ function parseQualifiedId(qualifiedId, listName) {
2554
+ const prefix = `${listName}/`;
2555
+ if (!qualifiedId.startsWith(prefix) || qualifiedId.length === prefix.length) {
2556
+ throw new Error(`Invalid qualified task id "${qualifiedId}".`);
2557
+ }
2558
+ return qualifiedId.slice(prefix.length);
2559
+ }
2560
+
2561
+ // ../task-list/src/backends/markdown-dir.ts
2562
+ import path5 from "node:path";
2563
+
2564
+ // ../file-lock/src/lock.ts
2565
+ import * as fsPromises from "node:fs/promises";
2566
+ import * as os from "node:os";
2567
+ var LockTimeoutError = class extends Error {
2568
+ constructor(message2) {
2569
+ super(message2);
2570
+ this.name = "LockTimeoutError";
2571
+ }
2572
+ };
2573
+ function createAbortError() {
2574
+ const error2 = new Error("The operation was aborted.");
2575
+ error2.name = "AbortError";
2576
+ return error2;
2577
+ }
2578
+ function throwIfAborted(signal) {
2579
+ if (signal?.aborted) {
2580
+ throw createAbortError();
2581
+ }
2582
+ }
2583
+ function sleep(ms, signal) {
2584
+ if (!signal) {
2585
+ return new Promise((resolve) => setTimeout(resolve, ms));
2586
+ }
2587
+ if (signal.aborted) {
2588
+ return Promise.reject(createAbortError());
2589
+ }
2590
+ return new Promise((resolve, reject) => {
2591
+ const timeoutId = setTimeout(() => {
2592
+ signal.removeEventListener("abort", onAbort);
2593
+ resolve();
2594
+ }, ms);
2595
+ const onAbort = () => {
2596
+ clearTimeout(timeoutId);
2597
+ signal.removeEventListener("abort", onAbort);
2598
+ reject(createAbortError());
2599
+ };
2600
+ signal.addEventListener("abort", onAbort, { once: true });
2601
+ });
2602
+ }
2603
+ function backoff(attempt, minTimeout, maxTimeout) {
2604
+ const delay = Math.min(maxTimeout, minTimeout * 2 ** attempt);
2605
+ return delay + Math.random() * delay * 0.1;
2606
+ }
2607
+ function hasErrorCode2(error2, code) {
2608
+ return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === code;
2609
+ }
2610
+ function hasAnyErrorCode(error2, codes) {
2611
+ return codes.some((code) => hasErrorCode2(error2, code));
2612
+ }
2613
+ function isPidRunning(pid) {
2614
+ try {
2615
+ process.kill(pid, 0);
2616
+ return true;
2617
+ } catch (error2) {
2618
+ return !hasErrorCode2(error2, "ESRCH");
2619
+ }
2620
+ }
2621
+ function createDefaultFs() {
2622
+ return {
2623
+ open: (path15, flags) => fsPromises.open(path15, flags),
2624
+ readFile: (path15, encoding) => fsPromises.readFile(path15, encoding),
2625
+ stat: fsPromises.stat,
2626
+ unlink: fsPromises.unlink
2627
+ };
2628
+ }
2629
+ async function removeLockFile(fs2, lockPath, signal) {
2630
+ for (let attempt = 0; attempt <= 4; attempt += 1) {
2631
+ throwIfAborted(signal);
2632
+ try {
2633
+ await fs2.unlink(lockPath);
2634
+ return;
2635
+ } catch (error2) {
2636
+ if (hasErrorCode2(error2, "ENOENT")) {
2637
+ return;
2638
+ }
2639
+ if (!hasAnyErrorCode(error2, ["EPERM", "EBUSY"]) || attempt === 4) {
2640
+ throw error2;
2641
+ }
2642
+ }
2643
+ await sleep(25 * 2 ** attempt, signal);
2644
+ }
2645
+ }
2646
+ function parseLockMetadata(content) {
2647
+ try {
2648
+ const parsed = JSON.parse(content);
2649
+ if (!parsed || typeof parsed !== "object" || !("host" in parsed) || !("pid" in parsed)) {
2650
+ return void 0;
2651
+ }
2652
+ const { host, pid } = parsed;
2653
+ if (typeof host === "string" && typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0) {
2654
+ return {
2655
+ host,
2656
+ pid
2657
+ };
2658
+ }
2659
+ } catch (ignoredError) {
2660
+ void ignoredError;
2661
+ }
2662
+ return void 0;
2663
+ }
2664
+ async function readLockMetadata(fs2, lockPath) {
2665
+ if (!fs2.readFile) {
2666
+ return void 0;
2667
+ }
2668
+ try {
2669
+ return parseLockMetadata(await fs2.readFile(lockPath, "utf8"));
2670
+ } catch (error2) {
2671
+ if (hasErrorCode2(error2, "ENOENT")) {
2672
+ return null;
2673
+ }
2674
+ return void 0;
2675
+ }
2676
+ }
2677
+ async function shouldReclaimLock(options) {
2678
+ const metadata = await readLockMetadata(options.fs, options.lockPath);
2679
+ if (metadata === null) {
2680
+ return "missing";
2681
+ }
2682
+ if (metadata?.host === os.hostname()) {
2683
+ return !options.isPidRunning(metadata.pid);
2684
+ }
2685
+ return Date.now() - options.stat.mtimeMs > options.staleMs;
2686
+ }
2687
+ async function writeLockMetadata(handle) {
2688
+ try {
1461
2689
  await handle.writeFile(
1462
2690
  JSON.stringify({ pid: process.pid, host: os.hostname(), acquiredAt: (/* @__PURE__ */ new Date()).toISOString() }),
1463
2691
  { encoding: "utf8" }
@@ -1494,7 +2722,7 @@ async function acquireFileLock(filePath, options = {}) {
1494
2722
  await removeLockFile(fs2, lockPath, options.signal);
1495
2723
  };
1496
2724
  } catch (error2) {
1497
- if (!hasErrorCode(error2, "EEXIST")) {
2725
+ if (!hasErrorCode2(error2, "EEXIST")) {
1498
2726
  throw error2;
1499
2727
  }
1500
2728
  }
@@ -1502,7 +2730,7 @@ async function acquireFileLock(filePath, options = {}) {
1502
2730
  try {
1503
2731
  stat3 = await fs2.stat(lockPath);
1504
2732
  } catch (statError) {
1505
- if (hasErrorCode(statError, "ENOENT")) {
2733
+ if (hasErrorCode2(statError, "ENOENT")) {
1506
2734
  continue;
1507
2735
  }
1508
2736
  throw statError;
@@ -1568,112 +2796,6 @@ var task_schema_default = {
1568
2796
  additionalProperties: true
1569
2797
  };
1570
2798
 
1571
- // ../task-list/src/state-machine.ts
1572
- function isRecord(value) {
1573
- return typeof value === "object" && value !== null && !Array.isArray(value);
1574
- }
1575
- function isStateList(value) {
1576
- return Array.isArray(value) && value.every((entry) => typeof entry === "string");
1577
- }
1578
- function canFireFromState(event, fromState) {
1579
- if (event.from === "*") {
1580
- return event.to !== fromState;
1581
- }
1582
- return event.from.includes(fromState);
1583
- }
1584
- function validateMachine(machine) {
1585
- if (!isRecord(machine)) {
1586
- throw new TypeError("State machine must be an object.");
1587
- }
1588
- if (!isStateList(machine.states)) {
1589
- throw new TypeError("State machine states must be a string array.");
1590
- }
1591
- const states = new Set(machine.states);
1592
- if (typeof machine.initial !== "string") {
1593
- throw new TypeError("State machine initial must be a string.");
1594
- }
1595
- if (!states.has(machine.initial)) {
1596
- throw new Error(`Initial state "${machine.initial}" is not declared.`);
1597
- }
1598
- if (!isRecord(machine.events)) {
1599
- throw new TypeError("State machine events must be an object.");
1600
- }
1601
- for (const [eventName, event] of Object.entries(machine.events)) {
1602
- if (!isRecord(event)) {
1603
- throw new TypeError(`Event "${eventName}" must be an object.`);
1604
- }
1605
- if (event.from !== "*" && !isStateList(event.from)) {
1606
- throw new TypeError(`Event "${eventName}" has an invalid "from" definition.`);
1607
- }
1608
- if (typeof event.to !== "string") {
1609
- throw new TypeError(`Event "${eventName}" target state must be a string.`);
1610
- }
1611
- if (!states.has(event.to)) {
1612
- throw new Error(`Event "${eventName}" references unknown target state "${event.to}".`);
1613
- }
1614
- if (event.from !== "*") {
1615
- for (const fromState of event.from) {
1616
- if (!states.has(fromState)) {
1617
- throw new Error(`Event "${eventName}" references unknown source state "${fromState}".`);
1618
- }
1619
- }
1620
- }
1621
- }
1622
- }
1623
- function eventsFromState(machine, fromState) {
1624
- const events = [];
1625
- for (const [eventName, event] of Object.entries(machine.events)) {
1626
- if (canFireFromState(event, fromState)) {
1627
- events.push(eventName);
1628
- }
1629
- }
1630
- return events;
1631
- }
1632
- function findEvent(machine, fromState, eventName) {
1633
- const event = machine.events[eventName];
1634
- if (event === void 0) {
1635
- return void 0;
1636
- }
1637
- return canFireFromState(event, fromState) ? event : void 0;
1638
- }
1639
-
1640
- // ../task-list/src/types.ts
1641
- var TaskNotFoundError = class extends Error {
1642
- constructor(message2 = "Task not found.") {
1643
- super(message2);
1644
- this.name = "TaskNotFoundError";
1645
- }
1646
- };
1647
- var TaskAlreadyExistsError = class extends Error {
1648
- constructor(message2 = "Task already exists.") {
1649
- super(message2);
1650
- this.name = "TaskAlreadyExistsError";
1651
- }
1652
- };
1653
- var InvalidTransitionError = class extends Error {
1654
- task;
1655
- event;
1656
- to;
1657
- reason;
1658
- constructor(messageOrOptions = "Invalid task transition.") {
1659
- const options = typeof messageOrOptions === "string" ? {
1660
- reason: messageOrOptions
1661
- } : messageOrOptions;
1662
- super(options.reason);
1663
- this.name = "InvalidTransitionError";
1664
- this.task = options.task;
1665
- this.event = options.event;
1666
- this.to = options.to;
1667
- this.reason = options.reason;
1668
- }
1669
- };
1670
- var MalformedTaskError = class extends Error {
1671
- constructor(message2 = "Malformed task.") {
1672
- super(message2);
1673
- this.name = "MalformedTaskError";
1674
- }
1675
- };
1676
-
1677
2799
  // ../task-list/src/state.ts
1678
2800
  var defaultStateMachine = {
1679
2801
  initial: "draft",
@@ -1709,64 +2831,17 @@ function resolveStateMachine(stateMachine) {
1709
2831
  return stateMachine ?? defaultStateMachine;
1710
2832
  }
1711
2833
 
1712
- // ../task-list/src/backends/utils.ts
1713
- import path2 from "node:path";
1714
- var tmpFileCounter = 0;
1715
- function hasErrorCode2(error2, code) {
1716
- return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === code;
1717
- }
1718
- function isRecord2(value) {
1719
- return typeof value === "object" && value !== null && !Array.isArray(value);
1720
- }
1721
- function sortStrings(values) {
1722
- return [...values].sort((left, right) => left.localeCompare(right));
1723
- }
1724
- function sortTasks(tasks) {
1725
- return [...tasks].sort((left, right) => left.qualifiedId.localeCompare(right.qualifiedId));
1726
- }
1727
- function validateTaskId(id) {
1728
- if (id.length === 0 || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
1729
- throw new Error(`Invalid task id "${id}".`);
1730
- }
1731
- return id;
1732
- }
1733
- async function statIfExists(fs2, filePath) {
1734
- try {
1735
- return await fs2.stat(filePath);
1736
- } catch (error2) {
1737
- if (hasErrorCode2(error2, "ENOENT")) {
1738
- return void 0;
1739
- }
1740
- throw error2;
1741
- }
1742
- }
1743
- async function writeAtomically(fs2, filePath, content) {
1744
- const tempPath = `${filePath}.tmp-${process.pid}-${tmpFileCounter}`;
1745
- tmpFileCounter += 1;
1746
- await fs2.mkdir(path2.dirname(filePath), { recursive: true });
1747
- try {
1748
- await fs2.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
1749
- await fs2.rename(tempPath, filePath);
1750
- } catch (error2) {
1751
- try {
1752
- await fs2.unlink(tempPath);
1753
- } catch (unlinkError) {
1754
- if (!hasErrorCode2(unlinkError, "ENOENT")) {
1755
- throw unlinkError;
1756
- }
1757
- }
1758
- throw error2;
1759
- }
1760
- }
1761
-
1762
2834
  // ../task-list/src/backends/markdown-dir.ts
1763
2835
  var ARCHIVE_DIRECTORY_NAME = "archive";
1764
2836
  var MARKDOWN_EXTENSION = ".md";
1765
2837
  var TASK_KIND = "task";
1766
2838
  var TASK_VERSION = 1;
1767
2839
  var TASK_SCHEMA_ID = task_schema_default.$id;
2840
+ var ORDER_LOCK_FILENAME = ".order.lock";
2841
+ var MIN_PREFIX_WIDTH = 2;
1768
2842
  var RESERVED_FRONTMATTER_KEYS = /* @__PURE__ */ new Set([
1769
2843
  "$schema",
2844
+ "created",
1770
2845
  "description",
1771
2846
  "kind",
1772
2847
  "name",
@@ -1779,7 +2854,7 @@ function validateListName(name) {
1779
2854
  }
1780
2855
  return name;
1781
2856
  }
1782
- function parseQualifiedId(qualifiedId) {
2857
+ function parseQualifiedId2(qualifiedId) {
1783
2858
  const separatorIndex = qualifiedId.indexOf("/");
1784
2859
  if (separatorIndex <= 0 || separatorIndex !== qualifiedId.lastIndexOf("/") || separatorIndex === qualifiedId.length - 1) {
1785
2860
  throw new Error(`Invalid qualified task id "${qualifiedId}".`);
@@ -1790,16 +2865,16 @@ function parseQualifiedId(qualifiedId) {
1790
2865
  };
1791
2866
  }
1792
2867
  function listPath(rootPath, list) {
1793
- return path3.join(rootPath, list);
2868
+ return path5.join(rootPath, list);
1794
2869
  }
1795
2870
  function archiveDirectoryPath(rootPath, list) {
1796
- return path3.join(listPath(rootPath, list), ARCHIVE_DIRECTORY_NAME);
2871
+ return path5.join(listPath(rootPath, list), ARCHIVE_DIRECTORY_NAME);
1797
2872
  }
1798
- function activeTaskPath(rootPath, list, id) {
1799
- return path3.join(listPath(rootPath, list), `${id}${MARKDOWN_EXTENSION}`);
2873
+ function activeTaskFilename(id, order, width) {
2874
+ return `${String(order).padStart(width, "0")}-${id}${MARKDOWN_EXTENSION}`;
1800
2875
  }
1801
2876
  function archivedTaskPath(rootPath, list, id) {
1802
- return path3.join(archiveDirectoryPath(rootPath, list), `${id}${MARKDOWN_EXTENSION}`);
2877
+ return path5.join(archiveDirectoryPath(rootPath, list), `${id}${MARKDOWN_EXTENSION}`);
1803
2878
  }
1804
2879
  function isMarkdownFile(entryName) {
1805
2880
  return entryName.endsWith(MARKDOWN_EXTENSION);
@@ -1810,6 +2885,27 @@ function isHiddenEntry(entryName) {
1810
2885
  function isLockFile(entryName) {
1811
2886
  return entryName.endsWith(".lock");
1812
2887
  }
2888
+ function isValidTaskIdShape(id) {
2889
+ return id.length > 0 && !id.startsWith(".") && !id.includes("/") && !id.includes("\\") && !id.includes("..");
2890
+ }
2891
+ function parseActiveFilename(entryName) {
2892
+ if (!isMarkdownFile(entryName)) return void 0;
2893
+ const stem = entryName.slice(0, -MARKDOWN_EXTENSION.length);
2894
+ const match = /^(\d+)-(.+)$/.exec(stem);
2895
+ if (match) {
2896
+ const id = match[2];
2897
+ if (isValidTaskIdShape(id)) {
2898
+ return { id, order: Number.parseInt(match[1], 10) };
2899
+ }
2900
+ }
2901
+ if (isValidTaskIdShape(stem)) {
2902
+ return { id: stem, order: null };
2903
+ }
2904
+ return void 0;
2905
+ }
2906
+ function padWidthForCount(count) {
2907
+ return Math.max(MIN_PREFIX_WIDTH, String(Math.max(count, 1)).length);
2908
+ }
1813
2909
  function malformedTask(filePath, field) {
1814
2910
  return new MalformedTaskError(`Malformed task "${filePath}": invalid "${field}".`);
1815
2911
  }
@@ -1903,7 +2999,7 @@ async function readDirectoryNames(fs2, directoryPath) {
1903
2999
  try {
1904
3000
  return sortStrings(await fs2.readdir(directoryPath));
1905
3001
  } catch (error2) {
1906
- if (hasErrorCode2(error2, "ENOENT")) {
3002
+ if (hasErrorCode(error2, "ENOENT")) {
1907
3003
  return [];
1908
3004
  }
1909
3005
  throw error2;
@@ -1927,22 +3023,31 @@ async function readTaskFile(fs2, list, id, filePath, validStates) {
1927
3023
  task: createTask(list, id, frontmatter, document.body)
1928
3024
  };
1929
3025
  }
3026
+ async function findActiveTaskFilename(fs2, listDirectoryPath, id) {
3027
+ const entries = await readDirectoryNames(fs2, listDirectoryPath);
3028
+ for (const entryName of entries) {
3029
+ if (isHiddenEntry(entryName) || isLockFile(entryName)) continue;
3030
+ const parsed = parseActiveFilename(entryName);
3031
+ if (parsed?.id === id) {
3032
+ return entryName;
3033
+ }
3034
+ }
3035
+ return void 0;
3036
+ }
1930
3037
  async function findTaskLocation(fs2, rootPath, list, id) {
1931
- const activePath = activeTaskPath(rootPath, list, id);
1932
- const activeStat = await statIfExists(fs2, activePath);
1933
- if (activeStat?.isFile()) {
1934
- return {
1935
- archived: false,
1936
- path: activePath
1937
- };
3038
+ const listDirectoryPath = listPath(rootPath, list);
3039
+ const activeName = await findActiveTaskFilename(fs2, listDirectoryPath, id);
3040
+ if (activeName) {
3041
+ const activePath = path5.join(listDirectoryPath, activeName);
3042
+ const activeStat = await statIfExists(fs2, activePath);
3043
+ if (activeStat?.isFile()) {
3044
+ return { archived: false, path: activePath };
3045
+ }
1938
3046
  }
1939
3047
  const archivedPath = archivedTaskPath(rootPath, list, id);
1940
3048
  const archivedStat = await statIfExists(fs2, archivedPath);
1941
3049
  if (archivedStat?.isFile()) {
1942
- return {
1943
- archived: true,
1944
- path: archivedPath
1945
- };
3050
+ return { archived: true, path: archivedPath };
1946
3051
  }
1947
3052
  return void 0;
1948
3053
  }
@@ -1971,6 +3076,7 @@ function createdFrontmatter(defaults, input, initialState) {
1971
3076
  frontmatter[key2] = value;
1972
3077
  }
1973
3078
  }
3079
+ frontmatter.created = (/* @__PURE__ */ new Date()).toISOString();
1974
3080
  return frontmatter;
1975
3081
  }
1976
3082
  function updatedFrontmatter(existingFrontmatter, task, patch) {
@@ -2015,35 +3121,95 @@ function assertCreateDoesNotSetState(input) {
2015
3121
  );
2016
3122
  }
2017
3123
  }
3124
+ function assertCreateHasId(input) {
3125
+ if (input.id === void 0) {
3126
+ throw new Error("id is required for markdown-dir backend");
3127
+ }
3128
+ }
2018
3129
  function assertUpdateDoesNotSetState(patch) {
2019
3130
  if (Object.prototype.hasOwnProperty.call(patch, "state")) {
2020
3131
  throw new Error('Tasks.update() does not accept "state"; use fire() to change task state.');
2021
3132
  }
2022
3133
  }
2023
- function createTasksView(deps, list) {
3134
+ function createTasksView2(deps, list) {
2024
3135
  const listDirectoryPath = listPath(deps.path, list);
2025
3136
  const stateMachine = resolveStateMachine(deps.stateMachine);
2026
3137
  const validStates = new Set(stateMachine.states);
2027
- async function listFiles(directoryPath) {
2028
- const entries = await readDirectoryNames(deps.fs, directoryPath);
2029
- const tasks = [];
3138
+ async function readActiveEntries() {
3139
+ const entries = await readDirectoryNames(deps.fs, listDirectoryPath);
3140
+ const result = [];
2030
3141
  for (const entryName of entries) {
2031
- if (isHiddenEntry(entryName) || isLockFile(entryName) || !isMarkdownFile(entryName)) {
2032
- continue;
2033
- }
2034
- const entryPath = path3.join(directoryPath, entryName);
3142
+ if (isHiddenEntry(entryName) || isLockFile(entryName)) continue;
3143
+ const parsed = parseActiveFilename(entryName);
3144
+ if (!parsed) continue;
3145
+ const entryPath = path5.join(listDirectoryPath, entryName);
2035
3146
  const entryStat = await statIfExists(deps.fs, entryPath);
2036
- if (!entryStat?.isFile()) {
2037
- continue;
2038
- }
3147
+ if (!entryStat?.isFile()) continue;
3148
+ result.push({ id: parsed.id, order: parsed.order, filename: entryName });
3149
+ }
3150
+ result.sort((left, right) => {
3151
+ const leftOrder = left.order ?? Number.POSITIVE_INFINITY;
3152
+ const rightOrder = right.order ?? Number.POSITIVE_INFINITY;
3153
+ if (leftOrder !== rightOrder) return leftOrder - rightOrder;
3154
+ return left.filename.localeCompare(right.filename);
3155
+ });
3156
+ return result;
3157
+ }
3158
+ async function readActiveTasks() {
3159
+ const entries = await readActiveEntries();
3160
+ const tasks = /* @__PURE__ */ new Map();
3161
+ for (const entry of entries) {
3162
+ const filePath = path5.join(listDirectoryPath, entry.filename);
3163
+ const file = await readTaskFile(deps.fs, list, entry.id, filePath, validStates);
3164
+ tasks.set(entry.id, { task: file.task, raw: file.frontmatter });
3165
+ }
3166
+ return { entries, tasks };
3167
+ }
3168
+ async function readArchivedTasks() {
3169
+ const archivePath = archiveDirectoryPath(deps.path, list);
3170
+ const entries = await readDirectoryNames(deps.fs, archivePath);
3171
+ const result = [];
3172
+ for (const entryName of entries) {
3173
+ if (isHiddenEntry(entryName) || isLockFile(entryName) || !isMarkdownFile(entryName)) continue;
3174
+ const entryPath = path5.join(archivePath, entryName);
3175
+ const entryStat = await statIfExists(deps.fs, entryPath);
3176
+ if (!entryStat?.isFile()) continue;
2039
3177
  const id = entryName.slice(0, -MARKDOWN_EXTENSION.length);
2040
- tasks.push((await readTaskFile(deps.fs, list, id, entryPath, validStates)).task);
3178
+ const file = await readTaskFile(deps.fs, list, id, entryPath, validStates);
3179
+ result.push({ task: file.task, raw: file.frontmatter });
3180
+ }
3181
+ return result.sort((left, right) => left.task.qualifiedId.localeCompare(right.task.qualifiedId));
3182
+ }
3183
+ async function rewriteListPrefixes(orderedIds) {
3184
+ const entries = await readActiveEntries();
3185
+ const byId = new Map(entries.map((entry) => [entry.id, entry]));
3186
+ const width = padWidthForCount(orderedIds.length);
3187
+ for (let index = 0; index < orderedIds.length; index += 1) {
3188
+ const id = orderedIds[index];
3189
+ const entry = byId.get(id);
3190
+ if (!entry) continue;
3191
+ const desiredFilename = activeTaskFilename(id, index + 1, width);
3192
+ if (entry.filename !== desiredFilename) {
3193
+ const fromPath = path5.join(listDirectoryPath, entry.filename);
3194
+ const stagingPath = path5.join(listDirectoryPath, `${desiredFilename}.staging-${process.pid}-${index}`);
3195
+ await deps.fs.rename(fromPath, stagingPath);
3196
+ entry.filename = path5.basename(stagingPath);
3197
+ }
3198
+ }
3199
+ const refreshed = await readDirectoryNames(deps.fs, listDirectoryPath);
3200
+ for (const entryName of refreshed) {
3201
+ const stagingMatch = /\.staging-\d+-\d+$/.exec(entryName);
3202
+ if (!stagingMatch) continue;
3203
+ const desiredName = entryName.slice(0, stagingMatch.index);
3204
+ await deps.fs.rename(
3205
+ path5.join(listDirectoryPath, entryName),
3206
+ path5.join(listDirectoryPath, desiredName)
3207
+ );
2041
3208
  }
2042
- return sortTasks(tasks);
2043
3209
  }
2044
- async function withTaskLock(id, action) {
2045
- validateTaskId(id);
2046
- const release = await acquireFileLock(activeTaskPath(deps.path, list, id), {
3210
+ async function withListLock(action) {
3211
+ await deps.fs.mkdir(listDirectoryPath, { recursive: true });
3212
+ const release = await acquireFileLock(path5.join(listDirectoryPath, ORDER_LOCK_FILENAME), {
2047
3213
  fs: deps.fs,
2048
3214
  staleMs: deps.lockStaleMs,
2049
3215
  retries: deps.lockRetries
@@ -2054,6 +3220,10 @@ function createTasksView(deps, list) {
2054
3220
  await release();
2055
3221
  }
2056
3222
  }
3223
+ async function withTaskLock(id, action) {
3224
+ validateTaskId(id);
3225
+ return withListLock(action);
3226
+ }
2057
3227
  async function getTaskFile(id) {
2058
3228
  validateTaskId(id);
2059
3229
  return readTaskAtLocation(deps.fs, deps.path, list, id, validStates);
@@ -2074,27 +3244,41 @@ function createTasksView(deps, list) {
2074
3244
  name: list,
2075
3245
  stateMachine,
2076
3246
  async all(filter) {
2077
- const activeTasks = await listFiles(listDirectoryPath);
2078
- const archivedTasks = filter?.includeArchived ? await listFiles(archiveDirectoryPath(deps.path, list)) : [];
2079
- const combinedTasks = [...activeTasks, ...archivedTasks];
2080
- if (filter?.state) {
2081
- return combinedTasks.filter((task) => task.state === filter.state);
2082
- }
2083
- return combinedTasks;
3247
+ const { entries: activeEntries, tasks: activeTasks } = await readActiveTasks();
3248
+ const archivedEntries = filter?.includeArchived ? await readArchivedTasks() : [];
3249
+ const orderedActive = activeEntries.map((entry) => activeTasks.get(entry.id)).filter((entry) => {
3250
+ if (filter?.state && entry.task.state !== filter.state) return false;
3251
+ return true;
3252
+ });
3253
+ const filteredArchived = archivedEntries.filter((entry) => {
3254
+ if (filter?.state && entry.task.state !== filter.state) return false;
3255
+ return true;
3256
+ });
3257
+ const orderedActiveTasks = applyOrder(orderedActive, filter?.order);
3258
+ return [...orderedActiveTasks, ...filteredArchived.map((entry) => entry.task)];
2084
3259
  },
2085
3260
  async get(id) {
2086
3261
  return (await getTaskFile(id)).task;
2087
3262
  },
2088
3263
  async create(input) {
2089
3264
  assertCreateDoesNotSetState(input);
3265
+ assertCreateHasId(input);
2090
3266
  validateTaskId(input.id);
2091
3267
  await deps.fs.mkdir(listDirectoryPath, { recursive: true });
2092
- return withTaskLock(input.id, async () => {
3268
+ return withListLock(async () => {
2093
3269
  const existing = await findTaskLocation(deps.fs, deps.path, list, input.id);
2094
3270
  if (existing) {
2095
3271
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
2096
3272
  }
2097
- const targetPath = activeTaskPath(deps.path, list, input.id);
3273
+ const activeEntries = await readActiveEntries();
3274
+ const maxOrder = activeEntries.reduce(
3275
+ (max, entry) => entry.order !== null && entry.order > max ? entry.order : max,
3276
+ 0
3277
+ );
3278
+ const nextOrder = maxOrder + 1;
3279
+ const width = padWidthForCount(activeEntries.length + 1);
3280
+ const filename = activeTaskFilename(input.id, nextOrder, width);
3281
+ const targetPath = path5.join(listDirectoryPath, filename);
2098
3282
  const frontmatter = createdFrontmatter(deps.defaults, input, stateMachine.initial);
2099
3283
  const description = input.description ?? "";
2100
3284
  await writeAtomically(deps.fs, targetPath, serializeTaskDocument(frontmatter, description));
@@ -2170,14 +3354,60 @@ function createTasksView(deps, list) {
2170
3354
  }
2171
3355
  await deps.fs.unlink(location.path);
2172
3356
  });
3357
+ },
3358
+ async move(id, anchor) {
3359
+ validateTaskId(id);
3360
+ return withListLock(async () => {
3361
+ const { entries, tasks } = await readActiveTasks();
3362
+ const fromIndex = entries.findIndex((entry) => entry.id === id);
3363
+ if (fromIndex < 0) {
3364
+ throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
3365
+ }
3366
+ const ordered = entries.map((entry) => entry.id);
3367
+ ordered.splice(fromIndex, 1);
3368
+ let insertIndex;
3369
+ if ("position" in anchor) {
3370
+ insertIndex = anchor.position === "top" ? 0 : ordered.length;
3371
+ } else {
3372
+ const anchorId = "before" in anchor ? anchor.before : anchor.after;
3373
+ const anchorIndex = ordered.indexOf(anchorId);
3374
+ if (anchorIndex < 0) {
3375
+ throw new AnchorNotFoundError(anchorId);
3376
+ }
3377
+ insertIndex = "before" in anchor ? anchorIndex : anchorIndex + 1;
3378
+ }
3379
+ ordered.splice(insertIndex, 0, id);
3380
+ await rewriteListPrefixes(ordered);
3381
+ return tasks.get(id).task;
3382
+ });
3383
+ },
3384
+ async reorder(ids) {
3385
+ for (const id of ids) {
3386
+ validateTaskId(id);
3387
+ }
3388
+ return withListLock(async () => {
3389
+ const { entries, tasks } = await readActiveTasks();
3390
+ const currentIds = entries.map((entry) => entry.id);
3391
+ const currentSet = new Set(currentIds);
3392
+ const inputSet = new Set(ids);
3393
+ const missing = currentIds.filter((id) => !inputSet.has(id));
3394
+ const extra = ids.filter((id) => !currentSet.has(id));
3395
+ if (missing.length > 0 || extra.length > 0) {
3396
+ throw new OrderMismatchError({ missing, extra });
3397
+ }
3398
+ await rewriteListPrefixes(ids);
3399
+ return ids.map((id) => tasks.get(id).task);
3400
+ });
2173
3401
  }
2174
3402
  };
2175
3403
  }
2176
3404
  async function markdownDirBackend(deps) {
2177
3405
  await ensureRootPath(deps);
3406
+ const stateMachine = resolveStateMachine(deps.stateMachine);
3407
+ const validStates = new Set(stateMachine.states);
2178
3408
  const list = (name) => {
2179
3409
  const listName = validateListName(name);
2180
- return createTasksView(deps, listName);
3410
+ return createTasksView2(deps, listName);
2181
3411
  };
2182
3412
  const lists = async () => {
2183
3413
  const entries = await readDirectoryNames(deps.fs, deps.path);
@@ -2186,7 +3416,7 @@ async function markdownDirBackend(deps) {
2186
3416
  if (entryName === ARCHIVE_DIRECTORY_NAME || isHiddenEntry(entryName) || isLockFile(entryName)) {
2187
3417
  continue;
2188
3418
  }
2189
- const entryPath = path3.join(deps.path, entryName);
3419
+ const entryPath = path5.join(deps.path, entryName);
2190
3420
  const entryStat = await statIfExists(deps.fs, entryPath);
2191
3421
  if (entryStat?.isDirectory()) {
2192
3422
  result.push(entryName);
@@ -2200,22 +3430,70 @@ async function markdownDirBackend(deps) {
2200
3430
  for (const taskListName of allLists) {
2201
3431
  tasks.push(...await list(taskListName).all(filter));
2202
3432
  }
2203
- return sortTasks(tasks);
3433
+ return tasks;
2204
3434
  };
2205
3435
  const get = async (qualifiedId) => {
2206
- const { list: listName, id } = parseQualifiedId(qualifiedId);
3436
+ const { list: listName, id } = parseQualifiedId2(qualifiedId);
2207
3437
  return list(listName).get(id);
2208
3438
  };
3439
+ const moveBetweenLists = async (qualifiedId, targetList) => {
3440
+ const { list: sourceListName, id } = parseQualifiedId2(qualifiedId);
3441
+ const targetListName = validateListName(targetList);
3442
+ if (sourceListName === targetListName) {
3443
+ const file2 = await readTaskAtLocation(deps.fs, deps.path, sourceListName, id, validStates);
3444
+ return file2.task;
3445
+ }
3446
+ const targetExisting = await findTaskLocation(deps.fs, deps.path, targetListName, id);
3447
+ if (targetExisting) {
3448
+ throw new TaskAlreadyExistsError(`Task "${targetListName}/${id}" already exists.`);
3449
+ }
3450
+ const sourceLocation = await findTaskLocation(deps.fs, deps.path, sourceListName, id);
3451
+ if (!sourceLocation) {
3452
+ throw new TaskNotFoundError(`Task "${sourceListName}/${id}" not found.`);
3453
+ }
3454
+ const targetListDir = listPath(deps.path, targetListName);
3455
+ await deps.fs.mkdir(targetListDir, { recursive: true });
3456
+ const targetEntries = await (async () => {
3457
+ const out = [];
3458
+ const names = await readDirectoryNames(deps.fs, targetListDir);
3459
+ for (const entryName of names) {
3460
+ if (isHiddenEntry(entryName) || isLockFile(entryName)) continue;
3461
+ const parsed = parseActiveFilename(entryName);
3462
+ if (!parsed) continue;
3463
+ out.push({ id: parsed.id, order: parsed.order, filename: entryName });
3464
+ }
3465
+ return out;
3466
+ })();
3467
+ if (sourceLocation.archived) {
3468
+ const archivedTargetDir = archiveDirectoryPath(deps.path, targetListName);
3469
+ await deps.fs.mkdir(archivedTargetDir, { recursive: true });
3470
+ const archivedTargetPath = archivedTaskPath(deps.path, targetListName, id);
3471
+ await deps.fs.rename(sourceLocation.path, archivedTargetPath);
3472
+ const file2 = await readTaskFile(deps.fs, targetListName, id, archivedTargetPath, validStates);
3473
+ return file2.task;
3474
+ }
3475
+ const maxOrder = targetEntries.reduce(
3476
+ (max, entry) => entry.order !== null && entry.order > max ? entry.order : max,
3477
+ 0
3478
+ );
3479
+ const width = padWidthForCount(targetEntries.length + 1);
3480
+ const targetFilename = activeTaskFilename(id, maxOrder + 1, width);
3481
+ const targetPath = path5.join(targetListDir, targetFilename);
3482
+ await deps.fs.rename(sourceLocation.path, targetPath);
3483
+ const file = await readTaskFile(deps.fs, targetListName, id, targetPath, validStates);
3484
+ return file.task;
3485
+ };
2209
3486
  return {
2210
3487
  list,
2211
3488
  lists,
2212
3489
  allTasks,
2213
- get
3490
+ get,
3491
+ moveBetweenLists
2214
3492
  };
2215
3493
  }
2216
3494
 
2217
3495
  // ../task-list/src/backends/yaml-file.ts
2218
- import { parseDocument as parseDocument2 } from "yaml";
3496
+ import { isMap, parseDocument as parseDocument2 } from "yaml";
2219
3497
 
2220
3498
  // ../task-list/src/schema/store.schema.json
2221
3499
  var store_schema_default = {
@@ -2258,7 +3536,15 @@ var STORE_VERSION = 1;
2258
3536
  var TASK_KIND2 = "task";
2259
3537
  var TASK_SCHEMA_ID2 = task_schema_default.$id;
2260
3538
  var TASK_VERSION2 = 1;
2261
- var RESERVED_TASK_KEYS = /* @__PURE__ */ new Set(["$schema", "description", "kind", "name", "state", "version"]);
3539
+ var RESERVED_TASK_KEYS = /* @__PURE__ */ new Set([
3540
+ "$schema",
3541
+ "created",
3542
+ "description",
3543
+ "kind",
3544
+ "name",
3545
+ "state",
3546
+ "version"
3547
+ ]);
2262
3548
  function malformedStore(filePath, field) {
2263
3549
  return new MalformedTaskError(`Malformed task store "${filePath}": invalid "${field}".`);
2264
3550
  }
@@ -2271,7 +3557,7 @@ function validateListName2(name) {
2271
3557
  }
2272
3558
  return name;
2273
3559
  }
2274
- function parseQualifiedId2(qualifiedId) {
3560
+ function parseQualifiedId3(qualifiedId) {
2275
3561
  const separatorIndex = qualifiedId.indexOf("/");
2276
3562
  if (separatorIndex <= 0 || separatorIndex !== qualifiedId.lastIndexOf("/") || separatorIndex === qualifiedId.length - 1) {
2277
3563
  throw new Error(`Invalid qualified task id "${qualifiedId}".`);
@@ -2329,6 +3615,7 @@ function createTaskRecord(defaults, input, initialState) {
2329
3615
  taskRecord[key2] = value;
2330
3616
  }
2331
3617
  }
3618
+ taskRecord.created = (/* @__PURE__ */ new Date()).toISOString();
2332
3619
  return taskRecord;
2333
3620
  }
2334
3621
  function assertCreateDoesNotSetState2(input) {
@@ -2338,6 +3625,11 @@ function assertCreateDoesNotSetState2(input) {
2338
3625
  );
2339
3626
  }
2340
3627
  }
3628
+ function assertCreateHasId2(input) {
3629
+ if (input.id === void 0) {
3630
+ throw new Error("id is required for yaml-file backend");
3631
+ }
3632
+ }
2341
3633
  function assertUpdateDoesNotSetState2(patch) {
2342
3634
  if (Object.prototype.hasOwnProperty.call(patch, "state")) {
2343
3635
  throw new Error('Tasks.update() does not accept "state"; use fire() to change task state.');
@@ -2486,6 +3778,48 @@ function getTaskOrThrow(store, list, id) {
2486
3778
  }
2487
3779
  return taskRecord;
2488
3780
  }
3781
+ function getListNode(document, list) {
3782
+ const lists = document.get("lists");
3783
+ if (!isMap(lists)) {
3784
+ return void 0;
3785
+ }
3786
+ const listNode = lists.get(list);
3787
+ if (!isMap(listNode)) {
3788
+ return void 0;
3789
+ }
3790
+ return listNode;
3791
+ }
3792
+ function pairKey(pair) {
3793
+ const key2 = pair.key;
3794
+ if (typeof key2 === "string") {
3795
+ return key2;
3796
+ }
3797
+ if (key2 && typeof key2 === "object" && "value" in key2 && typeof key2.value === "string") {
3798
+ return key2.value;
3799
+ }
3800
+ return void 0;
3801
+ }
3802
+ function findItemIndex(listNode, id) {
3803
+ return listNode.items.findIndex((pair) => pairKey(pair) === id);
3804
+ }
3805
+ function activeItemIds(listNode, validStates) {
3806
+ const ids = [];
3807
+ for (const pair of listNode.items) {
3808
+ const id = pairKey(pair);
3809
+ if (id === void 0) continue;
3810
+ const value = pair.value;
3811
+ let state;
3812
+ if (value && typeof value === "object" && "get" in value && typeof value.get === "function") {
3813
+ state = value.get("state");
3814
+ } else if (isRecord2(value)) {
3815
+ state = value.state;
3816
+ }
3817
+ if (typeof state === "string" && validStates.has(state) && state !== "archived") {
3818
+ ids.push(id);
3819
+ }
3820
+ }
3821
+ return ids;
3822
+ }
2489
3823
  async function ensureStorePath(deps) {
2490
3824
  if (!deps.create) {
2491
3825
  await deps.fs.stat(deps.path);
@@ -2523,7 +3857,7 @@ async function withStoreLock(deps, action) {
2523
3857
  await release();
2524
3858
  }
2525
3859
  }
2526
- function createTasksView2(deps, list) {
3860
+ function createTasksView3(deps, list) {
2527
3861
  const stateMachine = resolveStateMachine(deps.stateMachine);
2528
3862
  const validStates = new Set(stateMachine.states);
2529
3863
  async function readTasks(filter) {
@@ -2532,8 +3866,11 @@ function createTasksView2(deps, list) {
2532
3866
  if (!listRecord) {
2533
3867
  return [];
2534
3868
  }
2535
- const tasks = Object.entries(listRecord).map(([id, taskRecord]) => createTask2(list, id, taskRecord));
2536
- return sortTasks(tasks.filter((task) => matchesFilter(task, filter)));
3869
+ const entries = Object.entries(listRecord).map(([id, taskRecord]) => ({
3870
+ task: createTask2(list, id, taskRecord),
3871
+ raw: taskRecord
3872
+ })).filter(({ task }) => matchesFilter(task, filter));
3873
+ return applyOrder(entries, filter?.order);
2537
3874
  }
2538
3875
  function assertFireableTaskEvent(task, eventName) {
2539
3876
  const event = findEvent(stateMachine, task.state, eventName);
@@ -2560,6 +3897,7 @@ function createTasksView2(deps, list) {
2560
3897
  },
2561
3898
  async create(input) {
2562
3899
  assertCreateDoesNotSetState2(input);
3900
+ assertCreateHasId2(input);
2563
3901
  validateTaskId(input.id);
2564
3902
  return withStoreLock(deps, async () => {
2565
3903
  const { document, store } = await readStore(deps.fs, deps.path, validStates);
@@ -2648,6 +3986,72 @@ function createTasksView2(deps, list) {
2648
3986
  document.deleteIn(["lists", list, id]);
2649
3987
  await writeAtomically(deps.fs, deps.path, serializeDocument(document));
2650
3988
  });
3989
+ },
3990
+ async move(id, anchor) {
3991
+ validateTaskId(id);
3992
+ return withStoreLock(deps, async () => {
3993
+ const { document, store } = await readStore(deps.fs, deps.path, validStates);
3994
+ const taskRecord = getTaskOrThrow(store, list, id);
3995
+ const listNode = getListNode(document, list);
3996
+ if (!listNode) {
3997
+ throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
3998
+ }
3999
+ const fromIndex = findItemIndex(listNode, id);
4000
+ if (fromIndex < 0) {
4001
+ throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
4002
+ }
4003
+ const [movedPair] = listNode.items.splice(fromIndex, 1);
4004
+ let insertIndex;
4005
+ if ("position" in anchor) {
4006
+ insertIndex = anchor.position === "top" ? 0 : listNode.items.length;
4007
+ } else {
4008
+ const anchorId = "before" in anchor ? anchor.before : anchor.after;
4009
+ const anchorIndex = findItemIndex(listNode, anchorId);
4010
+ if (anchorIndex < 0) {
4011
+ listNode.items.splice(fromIndex, 0, movedPair);
4012
+ throw new AnchorNotFoundError(anchorId);
4013
+ }
4014
+ insertIndex = "before" in anchor ? anchorIndex : anchorIndex + 1;
4015
+ }
4016
+ listNode.items.splice(insertIndex, 0, movedPair);
4017
+ await writeAtomically(deps.fs, deps.path, serializeDocument(document));
4018
+ return createTask2(list, id, taskRecord);
4019
+ });
4020
+ },
4021
+ async reorder(ids) {
4022
+ for (const id of ids) {
4023
+ validateTaskId(id);
4024
+ }
4025
+ return withStoreLock(deps, async () => {
4026
+ const { document, store } = await readStore(deps.fs, deps.path, validStates);
4027
+ const listNode = getListNode(document, list);
4028
+ if (!listNode) {
4029
+ throw new OrderMismatchError({ missing: [...ids], extra: [] });
4030
+ }
4031
+ const currentActive = activeItemIds(listNode, validStates);
4032
+ const currentSet = new Set(currentActive);
4033
+ const inputSet = new Set(ids);
4034
+ const missing = currentActive.filter((id) => !inputSet.has(id));
4035
+ const extra = ids.filter((id) => !currentSet.has(id));
4036
+ if (missing.length > 0 || extra.length > 0) {
4037
+ throw new OrderMismatchError({ missing, extra });
4038
+ }
4039
+ const archivedPairs = listNode.items.filter((pair) => {
4040
+ const id = pairKey(pair);
4041
+ return id !== void 0 && !currentSet.has(id);
4042
+ });
4043
+ const orderedActive = ids.map((id) => {
4044
+ const pair = listNode.items.find((p) => pairKey(p) === id);
4045
+ if (!pair) {
4046
+ throw new OrderMismatchError({ missing: [id], extra: [] });
4047
+ }
4048
+ return pair;
4049
+ });
4050
+ listNode.items.splice(0, listNode.items.length, ...orderedActive, ...archivedPairs);
4051
+ await writeAtomically(deps.fs, deps.path, serializeDocument(document));
4052
+ const tasks = ids.map((id) => createTask2(list, id, getTaskOrThrow(store, list, id)));
4053
+ return tasks;
4054
+ });
2651
4055
  }
2652
4056
  };
2653
4057
  }
@@ -2657,7 +4061,7 @@ async function yamlFileBackend(deps) {
2657
4061
  const validStates = new Set(stateMachine.states);
2658
4062
  const list = (name) => {
2659
4063
  const listName = validateListName2(name);
2660
- return createTasksView2({ ...deps, stateMachine }, listName);
4064
+ return createTasksView3({ ...deps, stateMachine }, listName);
2661
4065
  };
2662
4066
  const lists = async () => {
2663
4067
  const { store } = await readStore(deps.fs, deps.path, validStates);
@@ -2665,26 +4069,47 @@ async function yamlFileBackend(deps) {
2665
4069
  };
2666
4070
  const allTasks = async (filter) => {
2667
4071
  const { store } = await readStore(deps.fs, deps.path, validStates);
2668
- const tasks = [];
2669
- for (const [listName, listRecord] of Object.entries(getListsRecord(store))) {
2670
- for (const [id, taskRecord] of Object.entries(listRecord)) {
2671
- const task = createTask2(listName, id, taskRecord);
2672
- if (matchesFilter(task, filter)) {
2673
- tasks.push(task);
2674
- }
2675
- }
4072
+ const result = [];
4073
+ const listNames = sortStrings(Object.keys(getListsRecord(store)));
4074
+ for (const listName of listNames) {
4075
+ const listRecord = getListsRecord(store)[listName];
4076
+ if (!isRecord2(listRecord)) continue;
4077
+ const entries = Object.entries(listRecord).map(([id, taskRecord]) => ({
4078
+ task: createTask2(listName, id, taskRecord),
4079
+ raw: taskRecord
4080
+ })).filter(({ task }) => matchesFilter(task, filter));
4081
+ result.push(...applyOrder(entries, filter?.order));
2676
4082
  }
2677
- return sortTasks(tasks);
4083
+ return result;
2678
4084
  };
2679
4085
  const get = async (qualifiedId) => {
2680
- const { list: listName, id } = parseQualifiedId2(qualifiedId);
4086
+ const { list: listName, id } = parseQualifiedId3(qualifiedId);
2681
4087
  return list(listName).get(id);
2682
4088
  };
4089
+ const moveBetweenLists = async (qualifiedId, targetList) => {
4090
+ const { list: sourceListName, id } = parseQualifiedId3(qualifiedId);
4091
+ const targetListName = validateListName2(targetList);
4092
+ return withStoreLock(deps, async () => {
4093
+ const { document, store } = await readStore(deps.fs, deps.path, validStates);
4094
+ const taskRecord = getTaskOrThrow(store, sourceListName, id);
4095
+ if (sourceListName === targetListName) {
4096
+ return createTask2(targetListName, id, taskRecord);
4097
+ }
4098
+ if (getTaskRecord(store, targetListName, id)) {
4099
+ throw new TaskAlreadyExistsError(`Task "${targetListName}/${id}" already exists.`);
4100
+ }
4101
+ document.deleteIn(["lists", sourceListName, id]);
4102
+ document.setIn(["lists", targetListName, id], taskRecord);
4103
+ await writeAtomically(deps.fs, deps.path, serializeDocument(document));
4104
+ return createTask2(targetListName, id, taskRecord);
4105
+ });
4106
+ };
2683
4107
  return {
2684
4108
  list,
2685
4109
  lists,
2686
4110
  allTasks,
2687
- get
4111
+ get,
4112
+ moveBetweenLists
2688
4113
  };
2689
4114
  }
2690
4115
 
@@ -2699,10 +4124,18 @@ function createDefaultFs2() {
2699
4124
  return fsPromises2;
2700
4125
  }
2701
4126
  async function openTaskList(options) {
2702
- const factory = backendFactories[options.type];
2703
- if (factory === void 0) {
2704
- throw new Error(`Unknown task list backend type "${options.type}".`);
4127
+ switch (options.type) {
4128
+ case "markdown-dir":
4129
+ case "yaml-file":
4130
+ return openFileBackend(options);
4131
+ case "gh-issues":
4132
+ return openGhIssuesBackend(options);
4133
+ default:
4134
+ throw new Error(`Unknown task list backend type "${options.type}".`);
2705
4135
  }
4136
+ }
4137
+ async function openFileBackend(options) {
4138
+ const factory = backendFactories[options.type];
2706
4139
  const stateMachine = resolveStateMachine(options.stateMachine);
2707
4140
  validateMachine(stateMachine);
2708
4141
  const deps = {
@@ -2718,9 +4151,23 @@ async function openTaskList(options) {
2718
4151
  };
2719
4152
  return factory(deps);
2720
4153
  }
4154
+ async function openGhIssuesBackend(options) {
4155
+ const token = await resolveAuth({ explicitToken: options.auth?.token });
4156
+ const endpoint = resolveEndpoint();
4157
+ return ghIssuesBackend({
4158
+ repo: options.repo,
4159
+ project: options.project,
4160
+ defaults: {
4161
+ metadata: { ...options.defaults?.metadata ?? {} }
4162
+ },
4163
+ token,
4164
+ endpoint,
4165
+ fetch: options.fetch
4166
+ });
4167
+ }
2721
4168
 
2722
4169
  // ../toolcraft/src/human-in-loop/approval-tasks.ts
2723
- import { randomBytes } from "node:crypto";
4170
+ import { randomBytes as randomBytes3 } from "node:crypto";
2724
4171
 
2725
4172
  // ../toolcraft/src/human-in-loop/state-machine.ts
2726
4173
  var approvalStateMachine = {
@@ -2803,7 +4250,7 @@ function isListValidated(runtimeOptions, listName) {
2803
4250
  return validatedListsByRuntime.get(runtimeOptions)?.has(listName) ?? false;
2804
4251
  }
2805
4252
  function createApprovalRecord(payload, enqueuedAt) {
2806
- const approvalId = `${enqueuedAt.slice(0, 19).replaceAll(":", "-")}-${randomBytes(3).toString("hex")}`;
4253
+ const approvalId = `${enqueuedAt.slice(0, 19).replaceAll(":", "-")}-${randomBytes3(3).toString("hex")}`;
2807
4254
  return {
2808
4255
  approvalId,
2809
4256
  name: `${payload.commandPath} (${enqueuedAt})`,
@@ -2886,7 +4333,7 @@ function areEqualStrings(left, right) {
2886
4333
  }
2887
4334
 
2888
4335
  // ../toolcraft/src/human-in-loop/runner.ts
2889
- import { access, readFile as readFile2, writeFile } from "node:fs/promises";
4336
+ import { access, readFile as readFile3, writeFile } from "node:fs/promises";
2890
4337
 
2891
4338
  // ../toolcraft/src/human-in-loop/default-provider.ts
2892
4339
  import process2 from "node:process";
@@ -2994,13 +4441,13 @@ function defaultProviderForPlatform() {
2994
4441
  }
2995
4442
 
2996
4443
  // ../toolcraft/src/human-in-loop/spawn.ts
2997
- import { spawn } from "node:child_process";
4444
+ import { spawn as spawn2 } from "node:child_process";
2998
4445
  function spawnApprovalRunner(approvalId, runtimeOptions, spawnFn) {
2999
4446
  const { execPath, entryArgs } = runtimeOptions.binPath ?? {
3000
4447
  execPath: process.execPath,
3001
4448
  entryArgs: [process.argv[1]]
3002
4449
  };
3003
- const fn = spawnFn ?? spawn;
4450
+ const fn = spawnFn ?? spawn2;
3004
4451
  const child = fn(execPath, [...entryArgs, "approvals", "run", approvalId], {
3005
4452
  detached: true,
3006
4453
  stdio: "ignore",
@@ -3185,13 +4632,13 @@ function createHandlerContext(command, params17) {
3185
4632
  }
3186
4633
  function createFs() {
3187
4634
  return {
3188
- readFile: async (path13, encoding = "utf8") => readFile2(path13, { encoding }),
3189
- writeFile: async (path13, contents) => {
3190
- await writeFile(path13, contents);
4635
+ readFile: async (path15, encoding = "utf8") => readFile3(path15, { encoding }),
4636
+ writeFile: async (path15, contents) => {
4637
+ await writeFile(path15, contents);
3191
4638
  },
3192
- exists: async (path13) => {
4639
+ exists: async (path15) => {
3193
4640
  try {
3194
- await access(path13);
4641
+ await access(path15);
3195
4642
  return true;
3196
4643
  } catch {
3197
4644
  return false;
@@ -3444,22 +4891,22 @@ function escapeMarkdownCell(value) {
3444
4891
 
3445
4892
  // ../toolcraft/src/mcp-proxy.ts
3446
4893
  import { existsSync as existsSync2 } from "node:fs";
3447
- import { mkdir, readFile as readFile3, rename, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
3448
- import path6 from "node:path";
4894
+ import { mkdir, readFile as readFile4, rename, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
4895
+ import path8 from "node:path";
3449
4896
 
3450
4897
  // ../tiny-mcp-client/src/internal.ts
3451
- import { spawn as spawn3 } from "node:child_process";
4898
+ import { spawn as spawn4 } from "node:child_process";
3452
4899
  import { PassThrough as PassThrough2 } from "node:stream";
3453
4900
 
3454
4901
  // ../mcp-oauth/dist/client/auth-store-session-store.js
3455
4902
  import crypto from "node:crypto";
3456
- import path5 from "node:path";
4903
+ import path7 from "node:path";
3457
4904
 
3458
4905
  // ../auth-store/src/encrypted-file-store.ts
3459
- import { createCipheriv, createDecipheriv, randomBytes as randomBytes2, scrypt } from "node:crypto";
4906
+ import { createCipheriv, createDecipheriv, randomBytes as randomBytes4, scrypt } from "node:crypto";
3460
4907
  import { promises as fs } from "node:fs";
3461
4908
  import { homedir, hostname as hostname2, userInfo } from "node:os";
3462
- import path4 from "node:path";
4909
+ import path6 from "node:path";
3463
4910
  var derivedKeyCache = /* @__PURE__ */ new Map();
3464
4911
  var ENCRYPTION_ALGORITHM = "aes-256-gcm";
3465
4912
  var ENCRYPTION_VERSION = 1;
@@ -3477,13 +4924,13 @@ var EncryptedFileStore = class {
3477
4924
  constructor(input) {
3478
4925
  this.fs = input.fs ?? fs;
3479
4926
  this.salt = input.salt;
3480
- this.filePath = input.filePath ?? path4.join(
4927
+ this.filePath = input.filePath ?? path6.join(
3481
4928
  (input.getHomeDirectory ?? homedir)(),
3482
4929
  input.defaultDirectory ?? ".auth-store",
3483
4930
  input.defaultFileName ?? "credentials.enc"
3484
4931
  );
3485
4932
  this.getMachineIdentity = input.getMachineIdentity ?? defaultMachineIdentity;
3486
- this.getRandomBytes = input.getRandomBytes ?? randomBytes2;
4933
+ this.getRandomBytes = input.getRandomBytes ?? randomBytes4;
3487
4934
  }
3488
4935
  async get() {
3489
4936
  let rawDocument;
@@ -3530,7 +4977,7 @@ var EncryptedFileStore = class {
3530
4977
  authTag: authTag.toString("base64"),
3531
4978
  ciphertext: ciphertext.toString("base64")
3532
4979
  };
3533
- await this.fs.mkdir(path4.dirname(this.filePath), { recursive: true });
4980
+ await this.fs.mkdir(path6.dirname(this.filePath), { recursive: true });
3534
4981
  await this.fs.writeFile(this.filePath, JSON.stringify(document), {
3535
4982
  encoding: "utf8"
3536
4983
  });
@@ -3581,7 +5028,7 @@ async function deriveEncryptionKey(getMachineIdentity, salt) {
3581
5028
  function parseEncryptedDocument(raw) {
3582
5029
  try {
3583
5030
  const parsed = JSON.parse(raw);
3584
- if (!isRecord3(parsed)) {
5031
+ if (!isRecord4(parsed)) {
3585
5032
  return null;
3586
5033
  }
3587
5034
  if (parsed.version !== ENCRYPTION_VERSION) {
@@ -3600,7 +5047,7 @@ function parseEncryptedDocument(raw) {
3600
5047
  return null;
3601
5048
  }
3602
5049
  }
3603
- function isRecord3(value) {
5050
+ function isRecord4(value) {
3604
5051
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
3605
5052
  }
3606
5053
  function isNotFoundError(error2) {
@@ -3610,7 +5057,7 @@ function isNotFoundError(error2) {
3610
5057
  }
3611
5058
 
3612
5059
  // ../auth-store/src/keychain-store.ts
3613
- import { spawn as spawn2 } from "node:child_process";
5060
+ import { spawn as spawn3 } from "node:child_process";
3614
5061
  var SECURITY_CLI = "security";
3615
5062
  var KEYCHAIN_ITEM_NOT_FOUND_EXIT_CODE = 44;
3616
5063
  var KeychainStore = class {
@@ -3674,7 +5121,7 @@ var KeychainStore = class {
3674
5121
  };
3675
5122
  function runSecurityCommand(command, args) {
3676
5123
  return new Promise((resolve) => {
3677
- const child = spawn2(command, args, {
5124
+ const child = spawn3(command, args, {
3678
5125
  stdio: ["ignore", "pipe", "pipe"]
3679
5126
  });
3680
5127
  let stdout = "";
@@ -3837,7 +5284,7 @@ function createAuthStoreClientStore(options) {
3837
5284
  }
3838
5285
  function createNamedSecretStore(key2, options, defaults) {
3839
5286
  const hash = crypto.createHash("sha256").update(key2).digest("hex");
3840
- const parsedFilePath = options.fileStore?.filePath === void 0 ? null : path5.parse(options.fileStore.filePath);
5287
+ const parsedFilePath = options.fileStore?.filePath === void 0 ? null : path7.parse(options.fileStore.filePath);
3841
5288
  const fileStore = {
3842
5289
  ...options.fileStore,
3843
5290
  salt: options.fileStore?.salt ?? defaults.salt,
@@ -4043,8 +5490,8 @@ function validateAuthorizationCallbackParameters(callback, expected) {
4043
5490
  }
4044
5491
  return callback.code;
4045
5492
  }
4046
- function escapeHtml(text4) {
4047
- return text4.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
5493
+ function escapeHtml(text5) {
5494
+ return text5.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
4048
5495
  }
4049
5496
  function buildSuccessPage(landingPage) {
4050
5497
  const title = landingPage?.title ?? "Connected";
@@ -5431,7 +6878,7 @@ var ERROR_INVALID_REQUEST = -32600;
5431
6878
  var ERROR_METHOD_NOT_FOUND = -32601;
5432
6879
  var ERROR_INTERNAL = -32603;
5433
6880
  function defaultStdioSpawn(command, args, options) {
5434
- return spawn3(command, args, options);
6881
+ return spawn4(command, args, options);
5435
6882
  }
5436
6883
  function defaultHttpTransportFetch(input, init) {
5437
6884
  return fetch(input, init);
@@ -6742,9 +8189,9 @@ function mergeJsonSchemas(base, overlay) {
6742
8189
  ...mergedRequired === void 0 ? {} : { required: mergedRequired }
6743
8190
  };
6744
8191
  }
6745
- function hasSelfReferencingRef(schema, root, path13 = "#", activePaths = /* @__PURE__ */ new Set()) {
8192
+ function hasSelfReferencingRef(schema, root, path15 = "#", activePaths = /* @__PURE__ */ new Set()) {
6746
8193
  const nextActivePaths = new Set(activePaths);
6747
- nextActivePaths.add(path13);
8194
+ nextActivePaths.add(path15);
6748
8195
  const localRefPath = getLocalRefPath(schema.$ref);
6749
8196
  if (localRefPath !== void 0) {
6750
8197
  if (nextActivePaths.has(localRefPath)) {
@@ -6755,13 +8202,13 @@ function hasSelfReferencingRef(schema, root, path13 = "#", activePaths = /* @__P
6755
8202
  return true;
6756
8203
  }
6757
8204
  }
6758
- if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path13}/items`, nextActivePaths)) {
8205
+ if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path15}/items`, nextActivePaths)) {
6759
8206
  return true;
6760
8207
  }
6761
8208
  if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null && hasSelfReferencingRef(
6762
8209
  schema.additionalProperties,
6763
8210
  root,
6764
- `${path13}/additionalProperties`,
8211
+ `${path15}/additionalProperties`,
6765
8212
  nextActivePaths
6766
8213
  )) {
6767
8214
  return true;
@@ -6770,7 +8217,7 @@ function hasSelfReferencingRef(schema, root, path13 = "#", activePaths = /* @__P
6770
8217
  if (hasSelfReferencingRef(
6771
8218
  childSchema,
6772
8219
  root,
6773
- `${path13}/properties/${escapeJsonPointerSegment(key2)}`,
8220
+ `${path15}/properties/${escapeJsonPointerSegment(key2)}`,
6774
8221
  nextActivePaths
6775
8222
  )) {
6776
8223
  return true;
@@ -6780,19 +8227,19 @@ function hasSelfReferencingRef(schema, root, path13 = "#", activePaths = /* @__P
6780
8227
  if (hasSelfReferencingRef(
6781
8228
  childSchema,
6782
8229
  root,
6783
- `${path13}/$defs/${escapeJsonPointerSegment(key2)}`,
8230
+ `${path15}/$defs/${escapeJsonPointerSegment(key2)}`,
6784
8231
  nextActivePaths
6785
8232
  )) {
6786
8233
  return true;
6787
8234
  }
6788
8235
  }
6789
8236
  for (const [index, childSchema] of (schema.oneOf ?? []).entries()) {
6790
- if (hasSelfReferencingRef(childSchema, root, `${path13}/oneOf/${index}`, nextActivePaths)) {
8237
+ if (hasSelfReferencingRef(childSchema, root, `${path15}/oneOf/${index}`, nextActivePaths)) {
6791
8238
  return true;
6792
8239
  }
6793
8240
  }
6794
8241
  for (const [index, childSchema] of (schema.anyOf ?? []).entries()) {
6795
- if (hasSelfReferencingRef(childSchema, root, `${path13}/anyOf/${index}`, nextActivePaths)) {
8242
+ if (hasSelfReferencingRef(childSchema, root, `${path15}/anyOf/${index}`, nextActivePaths)) {
6796
8243
  return true;
6797
8244
  }
6798
8245
  }
@@ -6808,14 +8255,14 @@ function getLocalRefPath(ref) {
6808
8255
  return ref.startsWith("#/") ? ref : void 0;
6809
8256
  }
6810
8257
  function resolveLocalRef(root, ref) {
6811
- const path13 = getLocalRefPath(ref);
6812
- if (path13 === void 0) {
8258
+ const path15 = getLocalRefPath(ref);
8259
+ if (path15 === void 0) {
6813
8260
  return void 0;
6814
8261
  }
6815
- if (path13 === "#") {
8262
+ if (path15 === "#") {
6816
8263
  return root;
6817
8264
  }
6818
- const segments = path13.slice(2).split("/").map(unescapeJsonPointerSegment);
8265
+ const segments = path15.slice(2).split("/").map(unescapeJsonPointerSegment);
6819
8266
  let current = root;
6820
8267
  for (const segment of segments) {
6821
8268
  if (Array.isArray(current)) {
@@ -7053,7 +8500,7 @@ async function ensureConnected(connection) {
7053
8500
  }
7054
8501
  async function readCache(cachePath) {
7055
8502
  try {
7056
- const raw = await readFile3(cachePath, "utf8");
8503
+ const raw = await readFile4(cachePath, "utf8");
7057
8504
  const parsed = JSON.parse(raw);
7058
8505
  if (parsed === null || typeof parsed !== "object" || !Array.isArray(parsed.tools) || parsed.upstream === void 0 || typeof parsed.upstream.name !== "string" || typeof parsed.upstream.version !== "string") {
7059
8506
  return void 0;
@@ -7074,7 +8521,7 @@ async function readCache(cachePath) {
7074
8521
  }
7075
8522
  }
7076
8523
  async function writeCache(cachePath, cache) {
7077
- const directory = path6.dirname(cachePath);
8524
+ const directory = path8.dirname(cachePath);
7078
8525
  const tempPath = `${cachePath}.tmp`;
7079
8526
  await mkdir(directory, { recursive: true });
7080
8527
  await writeFile2(tempPath, `${JSON.stringify(cache, null, 2)}
@@ -7217,14 +8664,14 @@ function collectProxyGroups(root) {
7217
8664
  }
7218
8665
  function resolveCachePath(name, projectRoot) {
7219
8666
  if (projectRoot !== void 0) {
7220
- return path6.join(projectRoot, ".toolcraft", "mcp", `${name}.json`);
8667
+ return path8.join(projectRoot, ".toolcraft", "mcp", `${name}.json`);
7221
8668
  }
7222
8669
  let current = process.cwd();
7223
8670
  while (true) {
7224
- if (existsSync2(path6.join(current, "package.json"))) {
7225
- return path6.join(current, ".toolcraft", "mcp", `${name}.json`);
8671
+ if (existsSync2(path8.join(current, "package.json"))) {
8672
+ return path8.join(current, ".toolcraft", "mcp", `${name}.json`);
7226
8673
  }
7227
- const parent = path6.dirname(current);
8674
+ const parent = path8.dirname(current);
7228
8675
  if (parent === current) {
7229
8676
  throw new Error(
7230
8677
  `Could not find package.json above "${process.cwd()}" while resolving MCP cache path.`
@@ -7276,9 +8723,49 @@ function getExpectedNumberDescription(schema) {
7276
8723
  }
7277
8724
 
7278
8725
  // ../toolcraft/src/renderer.ts
8726
+ import YAML from "yaml";
7279
8727
  function isObject(value) {
7280
8728
  return value !== null && typeof value === "object" && !Array.isArray(value);
7281
8729
  }
8730
+ function isMcpCallToolResult(value) {
8731
+ if (!isObject(value)) {
8732
+ return false;
8733
+ }
8734
+ const hasContent = Array.isArray(value.content);
8735
+ const hasStructured = value.structuredContent !== void 0;
8736
+ if (!hasContent && !hasStructured) {
8737
+ return false;
8738
+ }
8739
+ return Object.keys(value).every(
8740
+ (key2) => key2 === "content" || key2 === "structuredContent" || key2 === "isError" || key2 === "_meta"
8741
+ );
8742
+ }
8743
+ function isMcpTextContent(value) {
8744
+ return isObject(value) && value.type === "text" && typeof value.text === "string";
8745
+ }
8746
+ function extractMcpPayload(envelope) {
8747
+ const structuredContent = envelope.structuredContent;
8748
+ if (isObject(structuredContent) && "result" in structuredContent) {
8749
+ return structuredContent.result;
8750
+ }
8751
+ if (structuredContent !== void 0) {
8752
+ return structuredContent;
8753
+ }
8754
+ if (Array.isArray(envelope.content)) {
8755
+ const text5 = envelope.content.filter(isMcpTextContent).map((block) => block.text).join("\n");
8756
+ return text5.length > 0 ? text5 : void 0;
8757
+ }
8758
+ return void 0;
8759
+ }
8760
+ function unwrapMcpEnvelope(result) {
8761
+ if (!isMcpCallToolResult(result)) {
8762
+ return { result, mcpError: false };
8763
+ }
8764
+ return {
8765
+ result: extractMcpPayload(result),
8766
+ mcpError: result.isError === true
8767
+ };
8768
+ }
7282
8769
  function isArrayOfObjects(value) {
7283
8770
  return Array.isArray(value) && value.every((entry) => isObject(entry));
7284
8771
  }
@@ -7302,30 +8789,6 @@ function stringifyJson(value, spaces) {
7302
8789
  return String(value);
7303
8790
  }
7304
8791
  }
7305
- function renderObjectTable(result, primitives) {
7306
- const rows = Object.entries(result).map(([key2, value]) => ({
7307
- key: key2,
7308
- value: stringifyValue2(value)
7309
- }));
7310
- return primitives.renderTable({
7311
- theme: primitives.getTheme(),
7312
- columns: [
7313
- {
7314
- name: "key",
7315
- title: "Key",
7316
- alignment: "left",
7317
- maxLen: Math.max("Key".length, ...rows.map((row) => row.key.length))
7318
- },
7319
- {
7320
- name: "value",
7321
- title: "Value",
7322
- alignment: "left",
7323
- maxLen: Math.max("Value".length, ...rows.map((row) => row.value.length))
7324
- }
7325
- ],
7326
- rows
7327
- });
7328
- }
7329
8792
  function renderObjectMarkdown(result) {
7330
8793
  return Object.entries(result).map(([key2, value]) => `- ${key2}: ${stringifyValue2(value)}`).join("\n");
7331
8794
  }
@@ -7338,29 +8801,6 @@ function getColumnNames(rows) {
7338
8801
  }
7339
8802
  return [...names];
7340
8803
  }
7341
- function renderArrayTable(result, primitives) {
7342
- if (result.length === 0) {
7343
- return "[]";
7344
- }
7345
- const columnNames = getColumnNames(result);
7346
- return primitives.renderTable({
7347
- theme: primitives.getTheme(),
7348
- columns: columnNames.map((name) => ({
7349
- name,
7350
- title: name,
7351
- alignment: "left",
7352
- maxLen: Math.max(
7353
- name.length,
7354
- ...result.map((row) => name in row ? stringifyValue2(row[name]).length : 0)
7355
- )
7356
- })),
7357
- rows: result.map(
7358
- (row) => Object.fromEntries(
7359
- columnNames.map((name) => [name, name in row ? stringifyValue2(row[name]) : ""])
7360
- )
7361
- )
7362
- });
7363
- }
7364
8804
  function renderArrayMarkdown(result) {
7365
8805
  if (result.length === 0) {
7366
8806
  return "[]";
@@ -7373,7 +8813,7 @@ function renderArrayMarkdown(result) {
7373
8813
  );
7374
8814
  return [header, separator, ...rows].join("\n");
7375
8815
  }
7376
- function autoRender(result, output, primitives) {
8816
+ function autoRender(result, output, _primitives) {
7377
8817
  if (result === null || result === void 0) {
7378
8818
  if (output === "json") {
7379
8819
  return stringifyJson({ ok: true }, 2);
@@ -7386,14 +8826,16 @@ function autoRender(result, output, primitives) {
7386
8826
  }
7387
8827
  return result;
7388
8828
  }
8829
+ if (output === "rich" && Array.isArray(result) && result.every((value) => typeof value === "string")) {
8830
+ return result.join("\n");
8831
+ }
7389
8832
  if (isObject(result)) {
7390
- if (output === "rich") {
7391
- return renderObjectTable(result, primitives);
7392
- }
7393
8833
  if (output === "md") {
7394
8834
  return renderObjectMarkdown(result);
7395
8835
  }
7396
- return stringifyJson(result, 2);
8836
+ if (output === "json") {
8837
+ return stringifyJson(result, 2);
8838
+ }
7397
8839
  }
7398
8840
  if (isArrayOfObjects(result)) {
7399
8841
  if (output === "md") {
@@ -7402,20 +8844,36 @@ function autoRender(result, output, primitives) {
7402
8844
  if (output === "json") {
7403
8845
  return stringifyJson(result, 2);
7404
8846
  }
7405
- return renderArrayTable(result, primitives);
8847
+ }
8848
+ if (output === "rich") {
8849
+ return YAML.stringify(result);
7406
8850
  }
7407
8851
  return stringifyJson(result, 2);
7408
8852
  }
7409
- function renderResult(command, result, output, primitives, write2 = (chunk) => {
8853
+ function renderResult(command, result, output, primitives, write2 = (chunk, stream = "stdout") => {
8854
+ if (stream === "stderr") {
8855
+ process.stderr.write(chunk);
8856
+ return;
8857
+ }
7410
8858
  process.stdout.write(chunk);
7411
8859
  }) {
8860
+ const unwrapped = unwrapMcpEnvelope(result);
8861
+ result = unwrapped.result;
8862
+ if (unwrapped.mcpError) {
8863
+ const payload2 = autoRender(result, output, primitives);
8864
+ if (payload2.length > 0) {
8865
+ write2(`${payload2}
8866
+ `, "stderr");
8867
+ }
8868
+ return { mcpError: true };
8869
+ }
7412
8870
  if (output === "json" && command.render?.json) {
7413
8871
  const payload2 = command.render.json(result, primitives);
7414
8872
  if (payload2 !== void 0) {
7415
8873
  write2(`${stringifyJson(payload2, 2)}
7416
8874
  `);
7417
8875
  }
7418
- return;
8876
+ return { mcpError: false };
7419
8877
  }
7420
8878
  if (output === "md" && command.render?.markdown) {
7421
8879
  const payload2 = command.render.markdown(result, primitives);
@@ -7423,17 +8881,18 @@ function renderResult(command, result, output, primitives, write2 = (chunk) => {
7423
8881
  write2(`${payload2}
7424
8882
  `);
7425
8883
  }
7426
- return;
8884
+ return { mcpError: false };
7427
8885
  }
7428
8886
  if (output === "rich" && command.render?.rich) {
7429
8887
  command.render.rich(result, primitives);
7430
- return;
8888
+ return { mcpError: false };
7431
8889
  }
7432
8890
  const payload = autoRender(result, output, primitives);
7433
8891
  if (payload.length > 0) {
7434
8892
  write2(`${payload}
7435
8893
  `);
7436
8894
  }
8895
+ return { mcpError: false };
7437
8896
  }
7438
8897
 
7439
8898
  // ../toolcraft/src/cli.ts
@@ -7444,7 +8903,7 @@ function inferProgramName(argv) {
7444
8903
  if (typeof entrypoint !== "string" || entrypoint.length === 0) {
7445
8904
  return "toolcraft";
7446
8905
  }
7447
- const parsed = path7.parse(entrypoint);
8906
+ const parsed = path9.parse(entrypoint);
7448
8907
  return parsed.name.length > 0 ? parsed.name : "toolcraft";
7449
8908
  }
7450
8909
  function normalizeRoots(roots, argv) {
@@ -7466,7 +8925,7 @@ function unwrapOptional(schema) {
7466
8925
  }
7467
8926
  return schema;
7468
8927
  }
7469
- function splitWords(value) {
8928
+ function splitWords3(value) {
7470
8929
  const words = [];
7471
8930
  let current = "";
7472
8931
  for (let index = 0; index < value.length; index += 1) {
@@ -7500,13 +8959,13 @@ function splitWords(value) {
7500
8959
  }
7501
8960
  function formatSegment(segment, casing) {
7502
8961
  const separator = casing === "snake" ? "_" : "-";
7503
- return splitWords(segment).join(separator);
8962
+ return splitWords3(segment).join(separator);
7504
8963
  }
7505
- function toOptionFlag(path13, casing) {
7506
- return `--${path13.map((segment) => formatSegment(segment, casing)).join(".")}`;
8964
+ function toOptionFlag(path15, casing) {
8965
+ return `--${path15.map((segment) => formatSegment(segment, casing)).join(".")}`;
7507
8966
  }
7508
- function toOptionAttribute(path13, casing) {
7509
- return path13.map((segment) => {
8967
+ function toOptionAttribute(path15, casing) {
8968
+ return path15.map((segment) => {
7510
8969
  const formatted = formatSegment(segment, casing);
7511
8970
  if (casing === "snake") {
7512
8971
  return formatted;
@@ -7517,23 +8976,23 @@ function toOptionAttribute(path13, casing) {
7517
8976
  ).join("");
7518
8977
  }).join(".");
7519
8978
  }
7520
- function toDisplayPath(path13) {
7521
- return path13.join(".");
8979
+ function toDisplayPath(path15) {
8980
+ return path15.join(".");
7522
8981
  }
7523
- function toUnionKindControlPath(path13) {
7524
- if (path13.length === 0) {
8982
+ function toUnionKindControlPath(path15) {
8983
+ if (path15.length === 0) {
7525
8984
  return ["kind"];
7526
8985
  }
7527
- const head = path13.slice(0, -1);
7528
- const tail = path13[path13.length - 1] ?? "";
8986
+ const head = path15.slice(0, -1);
8987
+ const tail = path15[path15.length - 1] ?? "";
7529
8988
  return [...head, `${tail}Kind`];
7530
8989
  }
7531
- function toUnionKindDisplayPath(path13) {
7532
- if (path13.length === 0) {
8990
+ function toUnionKindDisplayPath(path15) {
8991
+ if (path15.length === 0) {
7533
8992
  return "kind";
7534
8993
  }
7535
- const head = path13.slice(0, -1);
7536
- const tail = path13[path13.length - 1] ?? "";
8994
+ const head = path15.slice(0, -1);
8995
+ const tail = path15[path15.length - 1] ?? "";
7537
8996
  return [...head, `${tail}-kind`].join(".");
7538
8997
  }
7539
8998
  function createSyntheticEnumSchema(values) {
@@ -7549,19 +9008,26 @@ function getRequiredBranchFingerprint(branch, casing) {
7549
9008
  const requiredKeys = Object.entries(branch.shape).filter(([, schema]) => schema.kind !== "optional").map(([key2]) => formatSegment(key2, casing)).sort();
7550
9009
  return requiredKeys.join("+");
7551
9010
  }
7552
- function collectFields(schema, casing, globalLongOptionFlags, path13 = [], inheritedOptional = false, variantContext) {
9011
+ function collectFields(schema, casing, globalLongOptionFlags, path15 = [], inheritedOptional = false, variantContext) {
7553
9012
  const collected = {
7554
9013
  dynamicFields: [],
7555
9014
  fields: [],
7556
9015
  variants: []
7557
9016
  };
7558
9017
  for (const [key2, rawChildSchema] of Object.entries(schema.shape)) {
7559
- const nextPath = [...path13, key2];
9018
+ const nextPath = [...path15, key2];
7560
9019
  const runtimeOptional = inheritedOptional || rawChildSchema.kind === "optional";
7561
9020
  const childSchema = unwrapOptional(rawChildSchema);
7562
9021
  const requiredWhenActive = rawChildSchema.kind !== "optional" && childSchema.default === void 0;
7563
9022
  if (childSchema.kind === "object") {
7564
- const nested = collectFields(childSchema, casing, globalLongOptionFlags, nextPath, runtimeOptional, variantContext);
9023
+ const nested = collectFields(
9024
+ childSchema,
9025
+ casing,
9026
+ globalLongOptionFlags,
9027
+ nextPath,
9028
+ runtimeOptional,
9029
+ variantContext
9030
+ );
7565
9031
  collected.dynamicFields.push(...nested.dynamicFields);
7566
9032
  collected.fields.push(...nested.fields);
7567
9033
  collected.variants.push(...nested.variants);
@@ -7575,7 +9041,11 @@ function collectFields(schema, casing, globalLongOptionFlags, path13 = [], inher
7575
9041
  path: [...nextPath, childSchema.discriminator],
7576
9042
  displayPath: toDisplayPath([...nextPath, childSchema.discriminator]),
7577
9043
  optionAttribute: toOptionAttribute([...nextPath, childSchema.discriminator], casing),
7578
- commanderOptionAttribute: toCommanderOptionAttribute([...nextPath, childSchema.discriminator], casing, globalLongOptionFlags),
9044
+ commanderOptionAttribute: toCommanderOptionAttribute(
9045
+ [...nextPath, childSchema.discriminator],
9046
+ casing,
9047
+ globalLongOptionFlags
9048
+ ),
7579
9049
  optionFlag: toOptionFlag([...nextPath, childSchema.discriminator], casing),
7580
9050
  shortFlag: void 0,
7581
9051
  schema: createSyntheticEnumSchema(branchIds),
@@ -7616,13 +9086,19 @@ function collectFields(schema, casing, globalLongOptionFlags, path13 = [], inher
7616
9086
  const variantId = `${toDisplayPath(nextPath)}:union`;
7617
9087
  const controlPath = toUnionKindControlPath(nextPath);
7618
9088
  const controlDisplayPath = toUnionKindDisplayPath(nextPath);
7619
- const branchIds = childSchema.branches.map((branch) => getRequiredBranchFingerprint(branch, casing));
9089
+ const branchIds = childSchema.branches.map(
9090
+ (branch) => getRequiredBranchFingerprint(branch, casing)
9091
+ );
7620
9092
  const controlField = {
7621
9093
  id: controlDisplayPath,
7622
9094
  path: controlPath,
7623
9095
  displayPath: controlDisplayPath,
7624
9096
  optionAttribute: toOptionAttribute(controlPath, casing),
7625
- commanderOptionAttribute: toCommanderOptionAttribute(controlPath, casing, globalLongOptionFlags),
9097
+ commanderOptionAttribute: toCommanderOptionAttribute(
9098
+ controlPath,
9099
+ casing,
9100
+ globalLongOptionFlags
9101
+ ),
7626
9102
  optionFlag: toOptionFlag(controlPath, casing),
7627
9103
  shortFlag: void 0,
7628
9104
  schema: createSyntheticEnumSchema(branchIds),
@@ -7719,9 +9195,9 @@ function collectFields(schema, casing, globalLongOptionFlags, path13 = [], inher
7719
9195
  }
7720
9196
  return collected;
7721
9197
  }
7722
- function toCommanderOptionAttribute(path13, casing, globalLongOptionFlags) {
7723
- const optionAttribute = toOptionAttribute(path13, casing);
7724
- const optionFlag = toOptionFlag(path13, casing);
9198
+ function toCommanderOptionAttribute(path15, casing, globalLongOptionFlags) {
9199
+ const optionAttribute = toOptionAttribute(path15, casing);
9200
+ const optionFlag = toOptionFlag(path15, casing);
7725
9201
  if (!globalLongOptionFlags.has(optionFlag)) {
7726
9202
  return optionAttribute;
7727
9203
  }
@@ -7869,7 +9345,9 @@ function parseArrayValue(value, schema, label) {
7869
9345
  if (itemSchema.kind === "array" || itemSchema.kind === "object") {
7870
9346
  throw new UserError(`Array parameter "${label}" must use scalar items.`);
7871
9347
  }
7872
- return splitArrayInput(value).map((item) => parseScalarValue(item, itemSchema, label));
9348
+ return splitArrayInput(value).map(
9349
+ (item) => parseScalarValue(item, itemSchema, label)
9350
+ );
7873
9351
  }
7874
9352
  function createOption(field, globalLongOptionFlags) {
7875
9353
  const flags = formatOptionFlags(field, globalLongOptionFlags);
@@ -7893,7 +9371,11 @@ function createOption(field, globalLongOptionFlags) {
7893
9371
  return [
7894
9372
  createCommanderOption(`${flags} <value...>`, field.description, field).argParser(
7895
9373
  (value, previous = []) => {
7896
- const parsed = parseArrayValue(value, field.schema, field.displayPath);
9374
+ const parsed = parseArrayValue(
9375
+ value,
9376
+ field.schema,
9377
+ field.displayPath
9378
+ );
7897
9379
  if (parsed === null) {
7898
9380
  return NULL_OPTION_VALUE;
7899
9381
  }
@@ -7920,7 +9402,9 @@ function createOption(field, globalLongOptionFlags) {
7920
9402
  }
7921
9403
  var ALWAYS_GLOBAL_LONG_OPTION_FLAGS = ["--yes", "--output", "--verbose"];
7922
9404
  function getGlobalLongOptionFlags(presetsEnabled) {
7923
- return new Set(presetsEnabled ? ["--preset", ...ALWAYS_GLOBAL_LONG_OPTION_FLAGS] : ALWAYS_GLOBAL_LONG_OPTION_FLAGS);
9405
+ return new Set(
9406
+ presetsEnabled ? ["--preset", ...ALWAYS_GLOBAL_LONG_OPTION_FLAGS] : ALWAYS_GLOBAL_LONG_OPTION_FLAGS
9407
+ );
7924
9408
  }
7925
9409
  function createCommanderOption(flags, description, field) {
7926
9410
  const option = new Option(flags, description);
@@ -7981,11 +9465,7 @@ function resolveHelpTarget(root, argv, scope, rootDisplayName) {
7981
9465
  if (current.kind !== "group") {
7982
9466
  break;
7983
9467
  }
7984
- const child = findVisibleChild(
7985
- current,
7986
- token,
7987
- scope
7988
- );
9468
+ const child = findVisibleChild(current, token, scope);
7989
9469
  if (child === void 0) {
7990
9470
  break;
7991
9471
  }
@@ -7997,32 +9477,23 @@ function resolveHelpTarget(root, argv, scope, rootDisplayName) {
7997
9477
  node: current
7998
9478
  };
7999
9479
  }
8000
- function describeSchemaType(schema) {
8001
- switch (schema.kind) {
8002
- case "string":
8003
- return "string";
8004
- case "number":
8005
- return "number";
8006
- case "boolean":
8007
- return "boolean";
8008
- case "enum":
8009
- return "value";
8010
- case "array":
8011
- return `${describeSchemaType(unwrapOptional(schema.item))}...`;
8012
- case "json":
8013
- return "json";
8014
- default:
8015
- throw new UserError("Unsupported CLI schema kind.");
8016
- }
8017
- }
8018
9480
  function formatHelpFieldFlags(field, globalLongOptionFlags) {
8019
9481
  if (field.positionalIndex !== void 0) {
8020
9482
  return formatPositionalToken(field);
8021
9483
  }
8022
9484
  if (field.schema.kind === "boolean") {
8023
- return `${formatOptionFlags(field, globalLongOptionFlags)} [value]`;
9485
+ if (field.defaultValue === true) {
9486
+ return `--no-${field.optionFlag.slice(2)}`;
9487
+ }
9488
+ return formatOptionFlags(field, globalLongOptionFlags);
8024
9489
  }
8025
- return `${formatOptionFlags(field, globalLongOptionFlags)} <${describeSchemaType(field.schema)}>`;
9490
+ return `${formatOptionFlags(field, globalLongOptionFlags)} <${describeHelpValueToken(
9491
+ field.schema,
9492
+ {
9493
+ displayPath: field.displayPath,
9494
+ optionFlag: field.optionFlag
9495
+ }
9496
+ )}>`;
8026
9497
  }
8027
9498
  function appendHelpMetadata(description, metadata) {
8028
9499
  if (metadata.length === 0) {
@@ -8044,6 +9515,87 @@ function formatHelpFieldDescription(field) {
8044
9515
  }
8045
9516
  return appendHelpMetadata(description, metadata);
8046
9517
  }
9518
+ function describeKnownStringFormat(format) {
9519
+ switch (format) {
9520
+ case "date":
9521
+ return "date";
9522
+ case "date-time":
9523
+ return "datetime";
9524
+ case "uri":
9525
+ return "url";
9526
+ case "email":
9527
+ return "email";
9528
+ default:
9529
+ return void 0;
9530
+ }
9531
+ }
9532
+ function describeKnownStringPattern(pattern) {
9533
+ if (pattern === void 0) {
9534
+ return void 0;
9535
+ }
9536
+ if (pattern === "^\\d{4}-\\d{2}-\\d{2}$") {
9537
+ return "YYYY-MM-DD";
9538
+ }
9539
+ if (pattern.startsWith("^\\d{4}-\\d{2}-\\d{2}T")) {
9540
+ return "YYYY-MM-DDTHH:MM:SS";
9541
+ }
9542
+ return void 0;
9543
+ }
9544
+ function stripLongOptionPrefix(optionFlag) {
9545
+ return optionFlag.startsWith("--") ? optionFlag.slice(2) : optionFlag;
9546
+ }
9547
+ function getLastSegment(value, separator) {
9548
+ const segments = value.split(separator);
9549
+ return segments[segments.length - 1] ?? value;
9550
+ }
9551
+ function matchesFieldNameSuffix(name, suffix) {
9552
+ const lowerName = name.toLowerCase();
9553
+ const lowerSuffix = suffix.toLowerCase();
9554
+ return lowerName === lowerSuffix || name.endsWith(suffix) || lowerName.endsWith(`-${lowerSuffix}`) || lowerName.endsWith(`_${lowerSuffix}`);
9555
+ }
9556
+ function describeFieldNameValueToken(displayPath, optionFlag) {
9557
+ const displayName = getLastSegment(displayPath, ".");
9558
+ const optionName = getLastSegment(stripLongOptionPrefix(optionFlag), ".");
9559
+ const candidates = [displayName, optionName];
9560
+ const suffixTokens = [
9561
+ ["Path", "path"],
9562
+ ["Paths", "path"],
9563
+ ["File", "path"],
9564
+ ["Files", "path"],
9565
+ ["Url", "url"],
9566
+ ["Email", "email"],
9567
+ ["Name", "name"],
9568
+ ["Id", "id"]
9569
+ ];
9570
+ for (const [suffix, token] of suffixTokens) {
9571
+ if (candidates.some((candidate) => matchesFieldNameSuffix(candidate, suffix))) {
9572
+ return token;
9573
+ }
9574
+ }
9575
+ return void 0;
9576
+ }
9577
+ function describeHelpValueToken(schema, field) {
9578
+ if (schema.kind === "array") {
9579
+ const itemSchema = unwrapOptional(schema.item);
9580
+ if (itemSchema.kind === "array" || itemSchema.kind === "object") {
9581
+ return "value...";
9582
+ }
9583
+ return `${describeHelpValueToken(itemSchema, field)}...`;
9584
+ }
9585
+ if (schema.kind === "json") {
9586
+ return "json";
9587
+ }
9588
+ if (schema.kind === "string") {
9589
+ const metadataToken = describeKnownStringFormat(schema.format) ?? describeKnownStringPattern(schema.pattern);
9590
+ if (metadataToken !== void 0) {
9591
+ return metadataToken;
9592
+ }
9593
+ }
9594
+ if (schema.kind === "enum") {
9595
+ return "value";
9596
+ }
9597
+ return describeFieldNameValueToken(field.displayPath, field.optionFlag) ?? "value";
9598
+ }
8047
9599
  function describeDynamicFieldType(field) {
8048
9600
  if (field.schema.kind === "record") {
8049
9601
  const valueSchema = unwrapOptional(field.schema.value);
@@ -8051,12 +9603,18 @@ function describeDynamicFieldType(field) {
8051
9603
  return "json";
8052
9604
  }
8053
9605
  if (valueSchema.kind === "array") {
8054
- return `${describeSchemaType(valueSchema)}`;
9606
+ return describeHelpValueToken(valueSchema, {
9607
+ displayPath: field.optionPathDisplay,
9608
+ optionFlag: field.optionFlag
9609
+ });
8055
9610
  }
8056
9611
  if (valueSchema.kind === "object") {
8057
9612
  return "value";
8058
9613
  }
8059
- return describeSchemaType(valueSchema);
9614
+ return describeHelpValueToken(valueSchema, {
9615
+ displayPath: field.optionPathDisplay,
9616
+ optionFlag: field.optionFlag
9617
+ });
8060
9618
  }
8061
9619
  return "value";
8062
9620
  }
@@ -8078,7 +9636,9 @@ function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefi
8078
9636
  const displayPath = `${displayPrefix}.${key2}`;
8079
9637
  const description = childSchema.description ?? displayPath;
8080
9638
  if (childSchema.kind === "object") {
8081
- rows.push(...collectDynamicObjectHelpRows(childSchema, casing, optionFlag, displayPath, metadata));
9639
+ rows.push(
9640
+ ...collectDynamicObjectHelpRows(childSchema, casing, optionFlag, displayPath, metadata)
9641
+ );
8082
9642
  continue;
8083
9643
  }
8084
9644
  if (childSchema.kind === "record") {
@@ -8115,7 +9675,10 @@ function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefi
8115
9675
  continue;
8116
9676
  }
8117
9677
  rows.push({
8118
- flags: childSchema.kind === "boolean" ? `${optionFlag} [value]` : `${optionFlag} <${describeSchemaType(childSchema)}>`,
9678
+ flags: childSchema.kind === "boolean" ? childSchema.default === true ? `--no-${optionFlag.slice(2)}` : optionFlag : `${optionFlag} <${describeHelpValueToken(childSchema, {
9679
+ displayPath,
9680
+ optionFlag
9681
+ })}>`,
8119
9682
  description: appendHelpMetadata(description, metadata)
8120
9683
  });
8121
9684
  }
@@ -8147,10 +9710,12 @@ function formatDynamicHelpFields(field, casing) {
8147
9710
  );
8148
9711
  }
8149
9712
  }
8150
- return [{
8151
- flags: `${field.optionFlag} <${describeDynamicFieldType(field)}>`,
8152
- description: appendHelpMetadata(field.description ?? field.optionPathDisplay, metadata)
8153
- }];
9713
+ return [
9714
+ {
9715
+ flags: `${field.optionFlag} <${describeDynamicFieldType(field)}>`,
9716
+ description: appendHelpMetadata(field.description ?? field.optionPathDisplay, metadata)
9717
+ }
9718
+ ];
8154
9719
  }
8155
9720
  function formatSecretRows(secrets) {
8156
9721
  return Object.values(secrets).map((secret) => ({
@@ -8181,29 +9746,25 @@ function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
8181
9746
  formatHelpFieldFlags(field, globalLongOptionFlags),
8182
9747
  field.positionalIndex === void 0 && (field.optional || field.hasDefault)
8183
9748
  )
8184
- ).concat(collected.dynamicFields.flatMap((field) => formatCommandDynamicParameterTokens(field, casing)));
9749
+ ).concat(
9750
+ collected.dynamicFields.flatMap((field) => formatCommandDynamicParameterTokens(field, casing))
9751
+ );
8185
9752
  }
8186
- function formatCommandRowName(node, depth, casing, globalLongOptionFlags) {
9753
+ function formatCommandRowName(node, casing, globalLongOptionFlags) {
8187
9754
  const baseName = node.aliases.length === 0 ? node.name : `${node.name} (${node.aliases.join(", ")})`;
8188
9755
  const parameterTokens = node.kind === "command" ? formatCommandParameterTokens(node, casing, globalLongOptionFlags) : [];
8189
9756
  const name = parameterTokens.length === 0 ? baseName : `${baseName} ${parameterTokens.join(" ")}`;
8190
- return `${" ".repeat(depth)}${name}`;
9757
+ return name;
8191
9758
  }
8192
- function formatCommandRows(group, scope, casing, globalLongOptionFlags, depth = 0) {
8193
- return getVisibleChildren(group, scope).flatMap((child) => {
8194
- const row = {
8195
- name: formatCommandRowName(child, depth, casing, globalLongOptionFlags),
8196
- description: child.description ?? ""
8197
- };
8198
- if (child.kind === "command") {
8199
- return [row];
8200
- }
8201
- return [row, ...formatCommandRows(child, scope, casing, globalLongOptionFlags, depth + 1)];
8202
- });
9759
+ function formatCommandRows(group, scope, casing, globalLongOptionFlags) {
9760
+ return getVisibleChildren(group, scope).map((child) => ({
9761
+ name: formatCommandRowName(child, casing, globalLongOptionFlags),
9762
+ description: child.description ?? ""
9763
+ }));
8203
9764
  }
8204
- function formatGlobalOptionRows(showVersion, presetsEnabled) {
9765
+ function formatGlobalOptionRows(ctx) {
8205
9766
  const rows = [];
8206
- if (presetsEnabled) {
9767
+ if (ctx.presetsEnabled) {
8207
9768
  rows.push({
8208
9769
  flags: "--preset <path>",
8209
9770
  description: "Load parameter defaults from a JSON file"
@@ -8216,14 +9777,10 @@ function formatGlobalOptionRows(showVersion, presetsEnabled) {
8216
9777
  },
8217
9778
  {
8218
9779
  flags: "--output <format>",
8219
- description: "Output format (rich, md, json)"
8220
- },
8221
- {
8222
- flags: "-h, --help",
8223
- description: "Show help"
9780
+ description: "Output format: rich, md, json."
8224
9781
  }
8225
9782
  );
8226
- if (showVersion) {
9783
+ if (ctx.showVersion) {
8227
9784
  rows.push({
8228
9785
  flags: "--version",
8229
9786
  description: "Show version"
@@ -8234,34 +9791,43 @@ function formatGlobalOptionRows(showVersion, presetsEnabled) {
8234
9791
  function renderHelpSections(sections) {
8235
9792
  return sections.filter((section) => section.length > 0).join("\n\n");
8236
9793
  }
9794
+ function formatHelpCommandList(rows) {
9795
+ return process.stdout.isTTY === false ? help_formatter_plain_exports.formatCommandList(rows) : formatCommandList(rows);
9796
+ }
9797
+ function formatHelpOptionList(rows) {
9798
+ return process.stdout.isTTY === false ? help_formatter_plain_exports.formatOptionList(rows) : formatOptionList(rows);
9799
+ }
8237
9800
  function buildUsageLine(breadcrumb, rootUsageName, suffix) {
8238
- if (rootUsageName === void 0) {
8239
- return void 0;
8240
- }
8241
- const subPath = breadcrumb.slice(1).join(" ");
8242
- return subPath ? `${rootUsageName} ${subPath} ${suffix}` : `${rootUsageName} ${suffix}`;
9801
+ const visibleBreadcrumb = breadcrumb.filter((segment) => segment.length > 0);
9802
+ const usageBreadcrumb = breadcrumb[0] === "" ? [rootUsageName, ...visibleBreadcrumb] : visibleBreadcrumb;
9803
+ const subPath = usageBreadcrumb.slice(1).join(" ");
9804
+ const tokens = [rootUsageName, subPath, suffix].filter((segment) => segment.length > 0);
9805
+ return tokens.join(" ");
8243
9806
  }
8244
- function renderGroupHelp(group, breadcrumb, scope, casing, showVersion, presetsEnabled, rootUsageName) {
9807
+ function renderGroupHelp(group, breadcrumb, scope, casing, globalOptions, rootUsageName) {
8245
9808
  const sections = [];
8246
- const globalLongOptionFlags = getGlobalLongOptionFlags(presetsEnabled);
9809
+ const globalLongOptionFlags = getGlobalLongOptionFlags(globalOptions.presetsEnabled);
8247
9810
  const commandRows = formatCommandRows(group, scope, casing, globalLongOptionFlags);
8248
9811
  if (commandRows.length > 0) {
8249
- sections.push(`${text.section("Commands:")}
8250
- ${formatCommandList(commandRows)}`);
9812
+ sections.push(`${text.sectionHeader("Commands")}
9813
+ ${formatHelpCommandList(commandRows)}`);
8251
9814
  }
8252
- sections.push(`${text.section("Global options:")}
8253
- ${formatOptionList(formatGlobalOptionRows(showVersion, presetsEnabled))}`);
9815
+ sections.push(
9816
+ `${text.sectionHeader("Options")}
9817
+ ${formatHelpOptionList(formatGlobalOptionRows(globalOptions))}`
9818
+ );
8254
9819
  return renderHelpDocument({
8255
9820
  breadcrumb,
8256
- usageLine: buildUsageLine(breadcrumb, rootUsageName, "[options] [command]"),
9821
+ rootUsageName,
9822
+ usageLine: buildUsageLine(breadcrumb, rootUsageName, "[command] [options]"),
8257
9823
  description: group.description,
8258
9824
  requiresAuth: group.requires?.auth === true,
8259
9825
  sections
8260
9826
  });
8261
9827
  }
8262
- function renderLeafHelp(command, breadcrumb, casing, presetsEnabled, rootUsageName) {
9828
+ function renderLeafHelp(command, breadcrumb, casing, globalOptions, rootUsageName) {
8263
9829
  const sections = [];
8264
- const globalLongOptionFlags = getGlobalLongOptionFlags(presetsEnabled);
9830
+ const globalLongOptionFlags = getGlobalLongOptionFlags(globalOptions.presetsEnabled);
8265
9831
  const collected = collectFields(command.params, casing, globalLongOptionFlags);
8266
9832
  const fields = assignPositionals(collected.fields, command.positional);
8267
9833
  const optionRows = fields.map((field) => ({
@@ -8269,20 +9835,25 @@ function renderLeafHelp(command, breadcrumb, casing, presetsEnabled, rootUsageNa
8269
9835
  description: formatHelpFieldDescription(field)
8270
9836
  })).concat(collected.dynamicFields.flatMap((field) => formatDynamicHelpFields(field, casing)));
8271
9837
  if (optionRows.length > 0) {
8272
- sections.push(`${text.section("Options:")}
8273
- ${formatOptionList(optionRows)}`);
9838
+ sections.push(`${text.sectionHeader("Options")}
9839
+ ${formatHelpOptionList(optionRows)}`);
8274
9840
  }
8275
- sections.push(`${text.section("Global options:")}
8276
- ${formatOptionList(formatGlobalOptionRows(false, presetsEnabled))}`);
9841
+ sections.push(
9842
+ `${text.sectionHeader("Options")}
9843
+ ${formatHelpOptionList(formatGlobalOptionRows(globalOptions))}`
9844
+ );
8277
9845
  const secretRows = formatSecretRows(command.secrets);
8278
9846
  if (secretRows.length > 0) {
8279
- sections.push(`${text.section("Secrets (via environment):")}
8280
- ${formatOptionList(secretRows)}`);
9847
+ sections.push(
9848
+ `${text.sectionHeader("Secrets (environment)")}
9849
+ ${formatHelpOptionList(secretRows)}`
9850
+ );
8281
9851
  }
8282
9852
  const positionalFields = fields.filter((f) => f.positionalIndex !== void 0);
8283
9853
  const usageSuffix = positionalFields.length > 0 ? `[options] ${positionalFields.map(formatPositionalToken).join(" ")}` : "[options]";
8284
9854
  return renderHelpDocument({
8285
9855
  breadcrumb,
9856
+ rootUsageName,
8286
9857
  usageLine: buildUsageLine(breadcrumb, rootUsageName, usageSuffix),
8287
9858
  description: command.description,
8288
9859
  requiresAuth: command.requires?.auth === true,
@@ -8290,17 +9861,21 @@ ${formatOptionList(secretRows)}`);
8290
9861
  });
8291
9862
  }
8292
9863
  function renderHelpDocument(input) {
8293
- const lines = [text.heading(input.breadcrumb.join(" ")), ""];
8294
- if (input.usageLine !== void 0) {
8295
- lines.push(`${text.section("Usage:")} ${text.usageCommand(input.usageLine)}`, "");
8296
- }
8297
- if (input.description !== void 0) {
8298
- lines.push(input.description);
8299
- }
9864
+ const title = input.breadcrumb.filter((segment) => segment.length > 0).join(" ") || input.rootUsageName;
9865
+ const description = input.description ?? "";
9866
+ const sentenceEndIndex = description.indexOf(". ");
9867
+ const headingDescription = sentenceEndIndex === -1 ? description : description.slice(0, sentenceEndIndex + 1);
9868
+ const remainingDescription = sentenceEndIndex === -1 ? "" : description.slice(sentenceEndIndex + 2);
9869
+ const heading = headingDescription.length > 0 ? `${title} \u2014 ${headingDescription}` : title;
9870
+ const lines = [text.heading(heading), ""];
9871
+ if (remainingDescription.length > 0) {
9872
+ lines.push(remainingDescription, "");
9873
+ }
9874
+ lines.push(`Usage: ${text.usageCommand(input.usageLine)}`, "");
8300
9875
  if (input.requiresAuth) {
8301
9876
  lines.push("Requires: authentication");
8302
9877
  }
8303
- if (input.description !== void 0 || input.requiresAuth) {
9878
+ if (input.requiresAuth) {
8304
9879
  lines.push("");
8305
9880
  }
8306
9881
  lines.push(renderHelpSections(input.sections));
@@ -8311,16 +9886,28 @@ async function renderGeneratedHelp(root, argv, options) {
8311
9886
  const target = resolveHelpTarget(root, argv, "cli", options.rootDisplayName);
8312
9887
  const output = resolveHelpOutput(argv);
8313
9888
  const casing = options.casing ?? "kebab";
9889
+ const rootUsageName = options.rootUsageName ?? inferProgramName(argv);
8314
9890
  await withOutputFormat2(output, async () => {
8315
9891
  const rendered = target.node.kind === "group" ? renderGroupHelp(
8316
9892
  target.node,
8317
9893
  target.breadcrumb,
8318
9894
  "cli",
8319
9895
  casing,
8320
- options.version !== void 0,
8321
- options.presets === true,
8322
- options.rootUsageName
8323
- ) : renderLeafHelp(target.node, target.breadcrumb, casing, options.presets === true, options.rootUsageName);
9896
+ {
9897
+ showVersion: options.version !== void 0,
9898
+ presetsEnabled: options.presets === true
9899
+ },
9900
+ rootUsageName
9901
+ ) : renderLeafHelp(
9902
+ target.node,
9903
+ target.breadcrumb,
9904
+ casing,
9905
+ {
9906
+ showVersion: options.version !== void 0,
9907
+ presetsEnabled: options.presets === true
9908
+ },
9909
+ rootUsageName
9910
+ );
8324
9911
  process.stdout.write(rendered);
8325
9912
  });
8326
9913
  }
@@ -8373,7 +9960,16 @@ function createNodeCommand(node, casing, globalLongOptionFlags, execute, presets
8373
9960
  if (!isNodeVisibleInScope(node, "cli")) {
8374
9961
  return null;
8375
9962
  }
8376
- const visibleChildren = node.children.map((child) => createNodeCommand(child, casing, globalLongOptionFlags, execute, presetsEnabled, nextPathSegments)).filter((child) => child !== null);
9963
+ const visibleChildren = node.children.map(
9964
+ (child) => createNodeCommand(
9965
+ child,
9966
+ casing,
9967
+ globalLongOptionFlags,
9968
+ execute,
9969
+ presetsEnabled,
9970
+ nextPathSegments
9971
+ )
9972
+ ).filter((child) => child !== null);
8377
9973
  const group = new CommanderCommand(node.name);
8378
9974
  if (node.description !== void 0) {
8379
9975
  group.description(node.description);
@@ -8398,13 +9994,15 @@ function addGlobalOptions(command, presetsEnabled) {
8398
9994
  if (value === "markdown") {
8399
9995
  return "md";
8400
9996
  }
8401
- throw new InvalidArgumentError('Invalid value for "--output". Expected one of: rich, md, markdown, json.');
9997
+ throw new InvalidArgumentError(
9998
+ 'Invalid value for "--output". Expected one of: rich, md, markdown, json.'
9999
+ );
8402
10000
  }).option("--verbose", "Print stack traces for unexpected errors.");
8403
10001
  }
8404
- function setNestedValue(target, path13, value) {
10002
+ function setNestedValue(target, path15, value) {
8405
10003
  let cursor = target;
8406
- for (let index = 0; index < path13.length - 1; index += 1) {
8407
- const segment = path13[index] ?? "";
10004
+ for (let index = 0; index < path15.length - 1; index += 1) {
10005
+ const segment = path15[index] ?? "";
8408
10006
  const existing = cursor[segment];
8409
10007
  if (typeof existing === "object" && existing !== null) {
8410
10008
  cursor = existing;
@@ -8414,7 +10012,7 @@ function setNestedValue(target, path13, value) {
8414
10012
  cursor[segment] = next;
8415
10013
  cursor = next;
8416
10014
  }
8417
- const leaf = path13[path13.length - 1];
10015
+ const leaf = path15[path15.length - 1];
8418
10016
  if (leaf !== void 0) {
8419
10017
  cursor[leaf] = value;
8420
10018
  }
@@ -8516,13 +10114,13 @@ async function withOutputFormat2(output, fn) {
8516
10114
  }
8517
10115
  function createFs2() {
8518
10116
  return {
8519
- readFile: async (path13, encoding = "utf8") => readFile4(path13, { encoding }),
8520
- writeFile: async (path13, contents) => {
8521
- await writeFile3(path13, contents);
10117
+ readFile: async (path15, encoding = "utf8") => readFile5(path15, { encoding }),
10118
+ writeFile: async (path15, contents) => {
10119
+ await writeFile3(path15, contents);
8522
10120
  },
8523
- exists: async (path13) => {
10121
+ exists: async (path15) => {
8524
10122
  try {
8525
- await access2(path13);
10123
+ await access2(path15);
8526
10124
  return true;
8527
10125
  } catch {
8528
10126
  return false;
@@ -8543,9 +10141,9 @@ function isPlainObject2(value) {
8543
10141
  function hasFieldValue(value) {
8544
10142
  return value !== void 0;
8545
10143
  }
8546
- function hasNestedField(fields, path13) {
10144
+ function hasNestedField(fields, path15) {
8547
10145
  return fields.some(
8548
- (field) => path13.length < field.path.length && path13.every((segment, index) => field.path[index] === segment)
10146
+ (field) => path15.length < field.path.length && path15.every((segment, index) => field.path[index] === segment)
8549
10147
  );
8550
10148
  }
8551
10149
  function describeExpectedPresetValue(schema) {
@@ -8602,7 +10200,12 @@ function validatePresetFieldValue(value, field, presetPath) {
8602
10200
  return value;
8603
10201
  }
8604
10202
  if (field.schema.kind !== "array") {
8605
- return validatePresetScalarValue(value, field.schema, field.displayPath, presetPath);
10203
+ return validatePresetScalarValue(
10204
+ value,
10205
+ field.schema,
10206
+ field.displayPath,
10207
+ presetPath
10208
+ );
8606
10209
  }
8607
10210
  const itemSchema = unwrapOptional(field.schema.item);
8608
10211
  if (itemSchema.kind === "array" || itemSchema.kind === "object") {
@@ -8620,7 +10223,7 @@ function validatePresetFieldValue(value, field, presetPath) {
8620
10223
  async function loadPresetValues(fields, presetPath) {
8621
10224
  let rawPreset;
8622
10225
  try {
8623
- rawPreset = await readFile4(presetPath, {
10226
+ rawPreset = await readFile5(presetPath, {
8624
10227
  encoding: "utf8"
8625
10228
  });
8626
10229
  } catch (error2) {
@@ -8641,9 +10244,9 @@ async function loadPresetValues(fields, presetPath) {
8641
10244
  }
8642
10245
  const fieldByPath = new Map(fields.map((field) => [field.displayPath, field]));
8643
10246
  const presetValues = {};
8644
- function visitObject(current, path13) {
10247
+ function visitObject(current, path15) {
8645
10248
  for (const [key2, value] of Object.entries(current)) {
8646
- const nextPath = [...path13, key2];
10249
+ const nextPath = [...path15, key2];
8647
10250
  const displayPath = toDisplayPath(nextPath);
8648
10251
  const field = fieldByPath.get(displayPath);
8649
10252
  if (field !== void 0) {
@@ -8702,7 +10305,9 @@ function matchesFixtureValue(expected, actual) {
8702
10305
  if (!isPlainObject2(actual)) {
8703
10306
  return false;
8704
10307
  }
8705
- return Object.entries(expected).every(([key2, value]) => matchesFixtureValue(value, actual[key2]));
10308
+ return Object.entries(expected).every(
10309
+ ([key2, value]) => matchesFixtureValue(value, actual[key2])
10310
+ );
8706
10311
  }
8707
10312
  return Object.is(expected, actual);
8708
10313
  }
@@ -8740,7 +10345,9 @@ function createFixtureResponse(response) {
8740
10345
  }
8741
10346
  function createFixtureFetch(entries) {
8742
10347
  return async (input, init) => {
8743
- const method = normalizeHttpMethod(init?.method ?? (input instanceof Request ? input.method : void 0));
10348
+ const method = normalizeHttpMethod(
10349
+ init?.method ?? (input instanceof Request ? input.method : void 0)
10350
+ );
8744
10351
  const url = getFetchUrl(input);
8745
10352
  const match = entries?.find((entry) => {
8746
10353
  const requestMethod = normalizeHttpMethod(entry.request.method);
@@ -8785,7 +10392,9 @@ function resolveFixtureMethodResult(methodName, definition, args) {
8785
10392
  }
8786
10393
  const explicitMatcher = isPlainObject2(entry.request) ? entry.request : void 0;
8787
10394
  const matcher = explicitMatcher ?? Object.fromEntries(
8788
- Object.entries(entry).filter(([key2]) => key2 !== "result" && key2 !== "response" && key2 !== "error")
10395
+ Object.entries(entry).filter(
10396
+ ([key2]) => key2 !== "result" && key2 !== "response" && key2 !== "error"
10397
+ )
8789
10398
  );
8790
10399
  const firstArg = args[0];
8791
10400
  let matched = false;
@@ -8841,8 +10450,8 @@ function createFixtureService(definition) {
8841
10450
  );
8842
10451
  }
8843
10452
  function resolveFixturePath(commandPath) {
8844
- const parsed = path7.parse(commandPath);
8845
- return path7.join(parsed.dir, `${parsed.name}.fixture.json`);
10453
+ const parsed = path9.parse(commandPath);
10454
+ return path9.join(parsed.dir, `${parsed.name}.fixture.json`);
8846
10455
  }
8847
10456
  function selectFixtureScenario(scenarios, selector) {
8848
10457
  if (isNumericFixtureSelector(selector)) {
@@ -8864,12 +10473,14 @@ function selectFixtureScenario(scenarios, selector) {
8864
10473
  async function loadFixtureScenario(command, selector) {
8865
10474
  const commandPath = getCommandSourcePath(command);
8866
10475
  if (commandPath === void 0) {
8867
- throw new UserError(`Fixture mode could not determine the source file for command "${command.name}".`);
10476
+ throw new UserError(
10477
+ `Fixture mode could not determine the source file for command "${command.name}".`
10478
+ );
8868
10479
  }
8869
10480
  const fixturePath = resolveFixturePath(commandPath);
8870
10481
  let rawFixture;
8871
10482
  try {
8872
- rawFixture = await readFile4(fixturePath, {
10483
+ rawFixture = await readFile5(fixturePath, {
8873
10484
  encoding: "utf8"
8874
10485
  });
8875
10486
  } catch {
@@ -8965,8 +10576,8 @@ function validateServices(services) {
8965
10576
  }
8966
10577
  }
8967
10578
  }
8968
- function getNestedValue(target, path13) {
8969
- return path13.reduce(
10579
+ function getNestedValue(target, path15) {
10580
+ return path15.reduce(
8970
10581
  (current, segment) => current !== null && typeof current === "object" ? current[segment] : void 0,
8971
10582
  target
8972
10583
  );
@@ -9065,7 +10676,13 @@ function resolveDynamicLeaf(schema, rawSegments, casing, outputPath = [], displa
9065
10676
  if (formatSegment(key2, casing) !== head) {
9066
10677
  continue;
9067
10678
  }
9068
- return resolveDynamicLeaf(childSchema, rest, casing, [...outputPath, key2], [...displayPath, key2]);
10679
+ return resolveDynamicLeaf(
10680
+ childSchema,
10681
+ rest,
10682
+ casing,
10683
+ [...outputPath, key2],
10684
+ [...displayPath, key2]
10685
+ );
9069
10686
  }
9070
10687
  throw new UserError(`Unknown parameter "${[...displayPath, head].join(".")}".`);
9071
10688
  }
@@ -9082,13 +10699,23 @@ function resolveDynamicLeaf(schema, rawSegments, casing, outputPath = [], displa
9082
10699
  case "array": {
9083
10700
  const itemSchema = unwrapOptional(unwrappedSchema.item);
9084
10701
  if (itemSchema.kind !== "object") {
9085
- throw new UserError(`Array parameter "${toDisplayPath(displayPath)}" must use object items.`);
10702
+ throw new UserError(
10703
+ `Array parameter "${toDisplayPath(displayPath)}" must use object items.`
10704
+ );
9086
10705
  }
9087
10706
  const [head, ...rest] = rawSegments;
9088
10707
  if (head === void 0 || !isNumericFixtureSelector(head)) {
9089
- throw new UserError(`Array parameter "${toDisplayPath(displayPath)}" must use numeric indices.`);
10708
+ throw new UserError(
10709
+ `Array parameter "${toDisplayPath(displayPath)}" must use numeric indices.`
10710
+ );
9090
10711
  }
9091
- return resolveDynamicLeaf(itemSchema, rest, casing, [...outputPath, head], [...displayPath, head]);
10712
+ return resolveDynamicLeaf(
10713
+ itemSchema,
10714
+ rest,
10715
+ casing,
10716
+ [...outputPath, head],
10717
+ [...displayPath, head]
10718
+ );
9092
10719
  }
9093
10720
  default:
9094
10721
  throw new UserError(`Unknown parameter "${[...displayPath, ...rawSegments].join(".")}".`);
@@ -9124,7 +10751,9 @@ function finalizeDynamicValue(schema, value, displayPath) {
9124
10751
  }
9125
10752
  for (let index = 0; index < indices.length; index += 1) {
9126
10753
  if (indices[index] !== index) {
9127
- throw new UserError(`Array parameter "${displayPath}" must use contiguous indices starting at 0.`);
10754
+ throw new UserError(
10755
+ `Array parameter "${displayPath}" must use contiguous indices starting at 0.`
10756
+ );
9128
10757
  }
9129
10758
  }
9130
10759
  return indices.map(
@@ -9180,7 +10809,9 @@ function finalizeDynamicValue(schema, value, displayPath) {
9180
10809
  function parseDynamicValues(dynamicFields, rawArgv, casing) {
9181
10810
  const rawValues = /* @__PURE__ */ new Map();
9182
10811
  const providedFieldIds = /* @__PURE__ */ new Set();
9183
- const sortedFields = [...dynamicFields].sort((left, right) => right.optionPath.length - left.optionPath.length);
10812
+ const sortedFields = [...dynamicFields].sort(
10813
+ (left, right) => right.optionPath.length - left.optionPath.length
10814
+ );
9184
10815
  for (let index = 0; index < rawArgv.length; index += 1) {
9185
10816
  const token = rawArgv[index] ?? "";
9186
10817
  if (!token.startsWith("--")) {
@@ -9267,7 +10898,9 @@ async function enforceVariantConstraints(params17, fields, dynamicFields, varian
9267
10898
  );
9268
10899
  }
9269
10900
  }
9270
- const invalidDynamicFieldId = branch.dynamicFieldIds.find((fieldId) => providedDynamicFieldIds.has(fieldId));
10901
+ const invalidDynamicFieldId = branch.dynamicFieldIds.find(
10902
+ (fieldId) => providedDynamicFieldIds.has(fieldId)
10903
+ );
9271
10904
  if (invalidDynamicFieldId !== void 0) {
9272
10905
  const field = dynamicFieldById.get(invalidDynamicFieldId);
9273
10906
  if (field !== void 0) {
@@ -9461,7 +11094,12 @@ async function executeCommand(state, services, requirementOptions, runtimeOption
9461
11094
  throw new UserError("Operation cancelled.");
9462
11095
  }
9463
11096
  }
9464
- const result = await invokeWithHumanInLoop(state.command, context, runtimeOptions, state.commandPath);
11097
+ const result = await invokeWithHumanInLoop(
11098
+ state.command,
11099
+ context,
11100
+ runtimeOptions,
11101
+ state.commandPath
11102
+ );
9465
11103
  if (output === "rich" && runtime.isFixture) {
9466
11104
  writeRichHeader(`${state.command.name} (fixture)`);
9467
11105
  }
@@ -9469,7 +11107,10 @@ async function executeCommand(state, services, requirementOptions, runtimeOption
9469
11107
  renderHumanInLoopPending(result);
9470
11108
  return;
9471
11109
  }
9472
- renderResult(state.command, result, output, primitives);
11110
+ const renderStatus = renderResult(state.command, result, output, primitives);
11111
+ if (renderStatus.mcpError) {
11112
+ process.exitCode = 1;
11113
+ }
9473
11114
  });
9474
11115
  }
9475
11116
  function handleRunError(error2, verbose) {
@@ -9531,7 +11172,13 @@ async function runCLI(roots, options = {}) {
9531
11172
  await executeCommand(state, servicesWithBuiltIns, requirementOptions, runtimeOptions);
9532
11173
  };
9533
11174
  for (const child of root.children) {
9534
- const command = createNodeCommand(child, casing, globalLongOptionFlags, execute, presetsEnabled);
11175
+ const command = createNodeCommand(
11176
+ child,
11177
+ casing,
11178
+ globalLongOptionFlags,
11179
+ execute,
11180
+ presetsEnabled
11181
+ );
9535
11182
  if (command === null) {
9536
11183
  continue;
9537
11184
  }
@@ -9572,7 +11219,7 @@ var DCS = 144;
9572
11219
  var SOS = 152;
9573
11220
  var PM = 158;
9574
11221
  var APC = 159;
9575
- function stripAnsi2(input) {
11222
+ function stripAnsi4(input) {
9576
11223
  let output = "";
9577
11224
  for (let index = 0; index < input.length; index += 1) {
9578
11225
  const code = input.charCodeAt(index);
@@ -10261,7 +11908,7 @@ var TerminalScreen = class {
10261
11908
  cursor,
10262
11909
  size
10263
11910
  }) {
10264
- this.lines = Object.freeze(lines.map((line) => stripAnsi2(line)));
11911
+ this.lines = Object.freeze(lines.map((line) => stripAnsi4(line)));
10265
11912
  this.rawLines = Object.freeze([...rawLines]);
10266
11913
  this.cursor = Object.freeze({ ...cursor });
10267
11914
  this.size = Object.freeze({ ...size });
@@ -10346,14 +11993,14 @@ var TerminalSession = class {
10346
11993
  });
10347
11994
  });
10348
11995
  }
10349
- async type(text4) {
10350
- for (const character of text4) {
11996
+ async type(text5) {
11997
+ for (const character of text5) {
10351
11998
  await this.send(character);
10352
11999
  await sleep2(TYPE_DELAY_MS);
10353
12000
  }
10354
12001
  }
10355
- async fill(text4) {
10356
- await this.send(text4.replace(/\r?\n/g, "\r"));
12002
+ async fill(text5) {
12003
+ await this.send(text5.replace(/\r?\n/g, "\r"));
10357
12004
  }
10358
12005
  async press(key2) {
10359
12006
  await this.send(keyToSequence(key2));
@@ -10411,7 +12058,7 @@ var TerminalSession = class {
10411
12058
  });
10412
12059
  }
10413
12060
  async history(opts) {
10414
- const normalized = normalizeHistoryBuffer(stripAnsi2(this.rawBuffer));
12061
+ const normalized = normalizeHistoryBuffer(stripAnsi4(this.rawBuffer));
10415
12062
  const lines = splitHistoryLines(normalized);
10416
12063
  if (opts?.last === void 0) {
10417
12064
  return lines;
@@ -10517,7 +12164,7 @@ function isMissingFileError(error2) {
10517
12164
  return "code" in error2 && error2.code === "ENOENT";
10518
12165
  }
10519
12166
  function matchPattern(buffer, pattern) {
10520
- const clean = normalizeHistoryBuffer(stripAnsi2(buffer));
12167
+ const clean = normalizeHistoryBuffer(stripAnsi4(buffer));
10521
12168
  for (const line of clean.split("\n")) {
10522
12169
  if (typeof pattern === "string") {
10523
12170
  if (line.includes(pattern)) return line;
@@ -10777,7 +12424,7 @@ var params2 = S.Object({
10777
12424
  rows: S.Optional(S.Number({ description: "Terminal height in rows" })),
10778
12425
  observe: S.Optional(S.Boolean({ description: "Mirror PTY output to stderr" }))
10779
12426
  });
10780
- var createSession = defineCommand({
12427
+ var createSession2 = defineCommand({
10781
12428
  name: "create-session",
10782
12429
  description: "Spawn an interactive CLI in a PTY",
10783
12430
  scope: ["cli", "mcp", "sdk"],
@@ -10829,7 +12476,7 @@ var getSession = defineCommand({
10829
12476
 
10830
12477
  // ../agent-skill-config/src/configs.ts
10831
12478
  import os2 from "node:os";
10832
- import path8 from "node:path";
12479
+ import path10 from "node:path";
10833
12480
 
10834
12481
  // ../agent-defs/src/agents/claude-code.ts
10835
12482
  var claudeCodeAgent = {
@@ -11350,20 +12997,20 @@ function getConfigFormat(pathOrFormat) {
11350
12997
  }
11351
12998
  return formatRegistry[formatName];
11352
12999
  }
11353
- function detectFormat(path13) {
11354
- const ext = getExtension(path13);
13000
+ function detectFormat(path15) {
13001
+ const ext = getExtension(path15);
11355
13002
  return extensionMap[ext];
11356
13003
  }
11357
- function getExtension(path13) {
11358
- const lastDot = path13.lastIndexOf(".");
13004
+ function getExtension(path15) {
13005
+ const lastDot = path15.lastIndexOf(".");
11359
13006
  if (lastDot === -1) {
11360
13007
  return "";
11361
13008
  }
11362
- return path13.slice(lastDot).toLowerCase();
13009
+ return path15.slice(lastDot).toLowerCase();
11363
13010
  }
11364
13011
 
11365
13012
  // ../config-mutations/src/execution/path-utils.ts
11366
- import path9 from "node:path";
13013
+ import path11 from "node:path";
11367
13014
  function expandHome(targetPath, homeDir) {
11368
13015
  if (!targetPath?.startsWith("~")) {
11369
13016
  return targetPath;
@@ -11380,7 +13027,7 @@ function expandHome(targetPath, homeDir) {
11380
13027
  remainder = remainder.slice(1);
11381
13028
  }
11382
13029
  }
11383
- return remainder.length === 0 ? homeDir : path9.join(homeDir, remainder);
13030
+ return remainder.length === 0 ? homeDir : path11.join(homeDir, remainder);
11384
13031
  }
11385
13032
  function validateHomePath(targetPath) {
11386
13033
  if (typeof targetPath !== "string" || targetPath.length === 0) {
@@ -11398,12 +13045,12 @@ function resolvePath(rawPath, homeDir, pathMapper) {
11398
13045
  if (!pathMapper) {
11399
13046
  return expanded;
11400
13047
  }
11401
- const rawDirectory = path9.dirname(expanded);
13048
+ const rawDirectory = path11.dirname(expanded);
11402
13049
  const mappedDirectory = pathMapper.mapTargetDirectory({
11403
13050
  targetDirectory: rawDirectory
11404
13051
  });
11405
- const filename = path9.basename(expanded);
11406
- return filename.length === 0 ? mappedDirectory : path9.join(mappedDirectory, filename);
13052
+ const filename = path11.basename(expanded);
13053
+ return filename.length === 0 ? mappedDirectory : path11.join(mappedDirectory, filename);
11407
13054
  }
11408
13055
 
11409
13056
  // ../config-mutations/src/fs-utils.ts
@@ -12010,8 +13657,8 @@ import Mustache2 from "mustache";
12010
13657
  var originalEscape = Mustache2.escape;
12011
13658
 
12012
13659
  // ../agent-skill-config/src/templates.ts
12013
- import { readFile as readFile5, stat as stat2 } from "node:fs/promises";
12014
- import path10 from "node:path";
13660
+ import { readFile as readFile6, stat as stat2 } from "node:fs/promises";
13661
+ import path12 from "node:path";
12015
13662
  import { fileURLToPath as fileURLToPath3 } from "node:url";
12016
13663
 
12017
13664
  // ../agent-skill-config/src/apply.ts
@@ -12070,9 +13717,9 @@ async function installSkill(agentId, skill, options) {
12070
13717
 
12071
13718
  // src/commands/installer.ts
12072
13719
  import os3 from "node:os";
12073
- import path11 from "node:path";
13720
+ import path13 from "node:path";
12074
13721
  import * as nodeFs from "node:fs/promises";
12075
- import { readFile as readFile6 } from "node:fs/promises";
13722
+ import { readFile as readFile7 } from "node:fs/promises";
12076
13723
  var DEFAULT_INSTALL_AGENT = "claude-code";
12077
13724
  var DEFAULT_INSTALL_SCOPE = "local";
12078
13725
  var TERMINAL_PILOT_SKILL_NAME = "terminal-pilot";
@@ -12122,7 +13769,7 @@ async function loadTerminalPilotTemplate() {
12122
13769
  ];
12123
13770
  for (const candidate of candidates) {
12124
13771
  try {
12125
- terminalPilotTemplateCache = await readFile6(candidate, "utf8");
13772
+ terminalPilotTemplateCache = await readFile7(candidate, "utf8");
12126
13773
  return terminalPilotTemplateCache;
12127
13774
  } catch (error2) {
12128
13775
  if (!isNotFoundError2(error2)) {
@@ -12137,7 +13784,7 @@ function resolveHomeRelativePath(targetPath, homeDir) {
12137
13784
  return homeDir;
12138
13785
  }
12139
13786
  if (targetPath.startsWith("~/")) {
12140
- return path11.join(homeDir, targetPath.slice(2));
13787
+ return path13.join(homeDir, targetPath.slice(2));
12141
13788
  }
12142
13789
  return targetPath;
12143
13790
  }
@@ -12147,12 +13794,12 @@ function getSkillFolderWithHome(agent, scope, cwd, homeDir) {
12147
13794
  throwUnsupportedAgent(agent);
12148
13795
  }
12149
13796
  return {
12150
- displayPath: path11.join(
13797
+ displayPath: path13.join(
12151
13798
  scope === "global" ? config.globalSkillDir : config.localSkillDir,
12152
13799
  TERMINAL_PILOT_SKILL_NAME
12153
13800
  ),
12154
- fullPath: path11.join(
12155
- scope === "global" ? resolveHomeRelativePath(config.globalSkillDir, homeDir) : path11.resolve(cwd, config.localSkillDir),
13801
+ fullPath: path13.join(
13802
+ scope === "global" ? resolveHomeRelativePath(config.globalSkillDir, homeDir) : path13.resolve(cwd, config.localSkillDir),
12156
13803
  TERMINAL_PILOT_SKILL_NAME
12157
13804
  )
12158
13805
  };
@@ -12344,17 +13991,17 @@ function colorsEqual(left, right) {
12344
13991
  }
12345
13992
  return false;
12346
13993
  }
12347
- function pushRun(runs, style, text4) {
12348
- if (text4.length === 0) {
13994
+ function pushRun(runs, style, text5) {
13995
+ if (text5.length === 0) {
12349
13996
  return;
12350
13997
  }
12351
13998
  const previous = runs.at(-1);
12352
- if (previous && text4 !== "\n" && previous.text !== "\n" && stylesEqual(previous, style)) {
12353
- previous.text += text4;
13999
+ if (previous && text5 !== "\n" && previous.text !== "\n" && stylesEqual(previous, style)) {
14000
+ previous.text += text5;
12354
14001
  return;
12355
14002
  }
12356
14003
  runs.push({
12357
- text: text4,
14004
+ text: text5,
12358
14005
  fg: style.fg,
12359
14006
  bg: style.bg,
12360
14007
  bold: style.bold,
@@ -12953,10 +14600,10 @@ function measureLines(lines) {
12953
14600
  0
12954
14601
  );
12955
14602
  }
12956
- function displayWidth(text4) {
14603
+ function displayWidth(text5) {
12957
14604
  const segmenter = new Intl.Segmenter();
12958
14605
  let width = 0;
12959
- for (const { segment } of segmenter.segment(text4)) {
14606
+ for (const { segment } of segmenter.segment(text5)) {
12960
14607
  const cp = segment.codePointAt(0);
12961
14608
  width += cp !== void 0 && isWideCodePoint(cp) ? 2 : 1;
12962
14609
  }
@@ -13220,7 +14867,7 @@ var waitForExit2 = defineCommand({
13220
14867
  var children = [
13221
14868
  install,
13222
14869
  uninstall,
13223
- createSession,
14870
+ createSession2,
13224
14871
  fill,
13225
14872
  type,
13226
14873
  pressKey,
@@ -13265,7 +14912,7 @@ async function isDirectExecution(argv) {
13265
14912
  try {
13266
14913
  const modulePath = fileURLToPath5(import.meta.url);
13267
14914
  const [resolvedEntryPoint, resolvedModulePath] = await Promise.all([
13268
- realpath(path12.resolve(entryPoint)),
14915
+ realpath(path14.resolve(entryPoint)),
13269
14916
  realpath(modulePath)
13270
14917
  ]);
13271
14918
  return resolvedEntryPoint === resolvedModulePath;