terminal-pilot 0.0.15 → 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 +2570 -774
- package/dist/cli.js.map +4 -4
- package/dist/commands/close-session.js +7 -2
- package/dist/commands/close-session.js.map +4 -4
- package/dist/commands/create-session.js +7 -2
- package/dist/commands/create-session.js.map +4 -4
- package/dist/commands/fill.js +7 -2
- package/dist/commands/fill.js.map +4 -4
- package/dist/commands/get-session.js +7 -2
- package/dist/commands/get-session.js.map +4 -4
- package/dist/commands/index.js +29 -24
- package/dist/commands/index.js.map +4 -4
- package/dist/commands/install.js +13 -8
- package/dist/commands/install.js.map +4 -4
- package/dist/commands/installer.js +15 -10
- package/dist/commands/installer.js.map +4 -4
- package/dist/commands/list-sessions.js +7 -2
- package/dist/commands/list-sessions.js.map +4 -4
- package/dist/commands/press-key.js +7 -2
- package/dist/commands/press-key.js.map +4 -4
- package/dist/commands/read-history.js +7 -2
- package/dist/commands/read-history.js.map +4 -4
- package/dist/commands/read-screen.js +7 -2
- package/dist/commands/read-screen.js.map +4 -4
- package/dist/commands/resize.js +7 -2
- package/dist/commands/resize.js.map +4 -4
- package/dist/commands/runtime.js +6 -1
- package/dist/commands/runtime.js.map +4 -4
- package/dist/commands/screenshot.js +11 -6
- package/dist/commands/screenshot.js.map +4 -4
- package/dist/commands/send-signal.js +7 -2
- package/dist/commands/send-signal.js.map +4 -4
- package/dist/commands/type.js +7 -2
- package/dist/commands/type.js.map +4 -4
- package/dist/commands/uninstall.js +16 -11
- package/dist/commands/uninstall.js.map +4 -4
- package/dist/commands/wait-for-exit.js +7 -2
- package/dist/commands/wait-for-exit.js.map +4 -4
- package/dist/commands/wait-for.js +7 -2
- package/dist/commands/wait-for.js.map +4 -4
- package/dist/testing/cli-repl.js +2571 -774
- package/dist/testing/cli-repl.js.map +4 -4
- package/dist/testing/qa-cli.js +2579 -782
- package/dist/testing/qa-cli.js.map +4 -4
- package/package.json +4 -2
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
|
|
6
|
-
import { fileURLToPath as
|
|
10
|
+
import path14 from "node:path";
|
|
11
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
7
12
|
|
|
8
13
|
// ../toolcraft/src/cli.ts
|
|
9
|
-
import { access as access2, readFile as
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
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: (
|
|
17
|
-
divider: (
|
|
18
|
-
prompt: (
|
|
19
|
-
number: (
|
|
20
|
-
intro: (
|
|
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: (
|
|
24
|
-
muted: (
|
|
25
|
-
success: (
|
|
26
|
-
warning: (
|
|
27
|
-
error: (
|
|
28
|
-
info: (
|
|
29
|
-
badge: (
|
|
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: (
|
|
33
|
-
divider: (
|
|
34
|
-
prompt: (
|
|
35
|
-
number: (
|
|
36
|
-
intro: (
|
|
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: (
|
|
40
|
-
muted: (
|
|
41
|
-
success: (
|
|
42
|
-
warning: (
|
|
43
|
-
error: (
|
|
44
|
-
info: (
|
|
45
|
-
badge: (
|
|
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: (
|
|
52
|
-
dim: (
|
|
53
|
-
italic: (
|
|
54
|
-
underline: (
|
|
55
|
-
strikethrough: (
|
|
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
|
|
469
|
-
|
|
470
|
-
|
|
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
|
|
473
|
-
const
|
|
474
|
-
|
|
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
|
|
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
|
|
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
|
|
@@ -666,7 +904,7 @@ async function confirm2(opts) {
|
|
|
666
904
|
import chalk16 from "chalk";
|
|
667
905
|
|
|
668
906
|
// ../toolcraft/src/index.ts
|
|
669
|
-
import { fileURLToPath } from "node:url";
|
|
907
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
670
908
|
|
|
671
909
|
// ../toolcraft/src/user-error.ts
|
|
672
910
|
var UserError = class extends Error {
|
|
@@ -835,6 +1073,62 @@ var S = {
|
|
|
835
1073
|
Json
|
|
836
1074
|
};
|
|
837
1075
|
|
|
1076
|
+
// ../toolcraft/src/package-metadata.ts
|
|
1077
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
1078
|
+
import path from "node:path";
|
|
1079
|
+
import { fileURLToPath } from "node:url";
|
|
1080
|
+
function pathFromInput(from) {
|
|
1081
|
+
if (from instanceof URL) {
|
|
1082
|
+
return fileURLToPath(from);
|
|
1083
|
+
}
|
|
1084
|
+
if (from.startsWith("file:")) {
|
|
1085
|
+
return fileURLToPath(from);
|
|
1086
|
+
}
|
|
1087
|
+
return path.resolve(from);
|
|
1088
|
+
}
|
|
1089
|
+
function getSearchDirectory(from) {
|
|
1090
|
+
const resolved = pathFromInput(from);
|
|
1091
|
+
try {
|
|
1092
|
+
return statSync(resolved).isDirectory() ? resolved : path.dirname(resolved);
|
|
1093
|
+
} catch {
|
|
1094
|
+
return path.dirname(resolved);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
function readPackageMetadata(packageJsonPath) {
|
|
1098
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
1099
|
+
const metadata = { path: packageJsonPath };
|
|
1100
|
+
if (typeof parsed.name === "string") {
|
|
1101
|
+
metadata.name = parsed.name;
|
|
1102
|
+
}
|
|
1103
|
+
if (typeof parsed.version === "string") {
|
|
1104
|
+
metadata.version = parsed.version;
|
|
1105
|
+
}
|
|
1106
|
+
return metadata;
|
|
1107
|
+
}
|
|
1108
|
+
function findPackageMetadata(from) {
|
|
1109
|
+
let current = getSearchDirectory(from);
|
|
1110
|
+
while (true) {
|
|
1111
|
+
const packageJsonPath = path.join(current, "package.json");
|
|
1112
|
+
if (existsSync(packageJsonPath)) {
|
|
1113
|
+
return readPackageMetadata(packageJsonPath);
|
|
1114
|
+
}
|
|
1115
|
+
const parent = path.dirname(current);
|
|
1116
|
+
if (parent === current) {
|
|
1117
|
+
return void 0;
|
|
1118
|
+
}
|
|
1119
|
+
current = parent;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
function findEntrypointPackageMetadata(entrypoint) {
|
|
1123
|
+
if (entrypoint === void 0 || entrypoint.length === 0) {
|
|
1124
|
+
return void 0;
|
|
1125
|
+
}
|
|
1126
|
+
if (!path.isAbsolute(entrypoint) && !entrypoint.startsWith("file:")) {
|
|
1127
|
+
return void 0;
|
|
1128
|
+
}
|
|
1129
|
+
return findPackageMetadata(entrypoint);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
838
1132
|
// ../toolcraft/src/index.ts
|
|
839
1133
|
var commandConfigSymbol = /* @__PURE__ */ Symbol("toolcraft.command.config");
|
|
840
1134
|
var groupConfigSymbol = /* @__PURE__ */ Symbol("toolcraft.group.config");
|
|
@@ -920,7 +1214,7 @@ function validateRenameMap(rename2) {
|
|
|
920
1214
|
function parseStackPath(candidate) {
|
|
921
1215
|
if (candidate.startsWith("file://")) {
|
|
922
1216
|
try {
|
|
923
|
-
return
|
|
1217
|
+
return fileURLToPath2(candidate);
|
|
924
1218
|
} catch {
|
|
925
1219
|
return void 0;
|
|
926
1220
|
}
|
|
@@ -1274,134 +1568,1196 @@ function getCommandSourcePath(command) {
|
|
|
1274
1568
|
// ../task-list/src/open.ts
|
|
1275
1569
|
import * as fsPromises2 from "node:fs/promises";
|
|
1276
1570
|
|
|
1277
|
-
// ../task-list/src/
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
// ../file-lock/src/lock.ts
|
|
1281
|
-
import * as fsPromises from "node:fs/promises";
|
|
1282
|
-
import * as os from "node:os";
|
|
1283
|
-
var LockTimeoutError = class extends Error {
|
|
1284
|
-
constructor(message2) {
|
|
1285
|
-
super(message2);
|
|
1286
|
-
this.name = "LockTimeoutError";
|
|
1287
|
-
}
|
|
1288
|
-
};
|
|
1289
|
-
function createAbortError() {
|
|
1290
|
-
const error2 = new Error("The operation was aborted.");
|
|
1291
|
-
error2.name = "AbortError";
|
|
1292
|
-
return error2;
|
|
1571
|
+
// ../task-list/src/state-machine.ts
|
|
1572
|
+
function isRecord(value) {
|
|
1573
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1293
1574
|
}
|
|
1294
|
-
function
|
|
1295
|
-
|
|
1296
|
-
|
|
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;
|
|
1297
1581
|
}
|
|
1582
|
+
return event.from.includes(fromState);
|
|
1298
1583
|
}
|
|
1299
|
-
function
|
|
1300
|
-
if (!
|
|
1301
|
-
|
|
1584
|
+
function validateMachine(machine) {
|
|
1585
|
+
if (!isRecord(machine)) {
|
|
1586
|
+
throw new TypeError("State machine must be an object.");
|
|
1302
1587
|
}
|
|
1303
|
-
if (
|
|
1304
|
-
|
|
1588
|
+
if (!isStateList(machine.states)) {
|
|
1589
|
+
throw new TypeError("State machine states must be a string array.");
|
|
1305
1590
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
resolve();
|
|
1310
|
-
}, ms);
|
|
1311
|
-
const onAbort = () => {
|
|
1312
|
-
clearTimeout(timeoutId);
|
|
1313
|
-
signal.removeEventListener("abort", onAbort);
|
|
1314
|
-
reject(createAbortError());
|
|
1315
|
-
};
|
|
1316
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
function backoff(attempt, minTimeout, maxTimeout) {
|
|
1320
|
-
const delay = Math.min(maxTimeout, minTimeout * 2 ** attempt);
|
|
1321
|
-
return delay + Math.random() * delay * 0.1;
|
|
1322
|
-
}
|
|
1323
|
-
function hasErrorCode(error2, code) {
|
|
1324
|
-
return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === code;
|
|
1325
|
-
}
|
|
1326
|
-
function createDefaultFs() {
|
|
1327
|
-
return {
|
|
1328
|
-
open: (path12, flags) => fsPromises.open(path12, flags),
|
|
1329
|
-
stat: fsPromises.stat,
|
|
1330
|
-
unlink: fsPromises.unlink
|
|
1331
|
-
};
|
|
1332
|
-
}
|
|
1333
|
-
async function removeLockFile(fs2, lockPath) {
|
|
1334
|
-
try {
|
|
1335
|
-
await fs2.unlink(lockPath);
|
|
1336
|
-
} catch (error2) {
|
|
1337
|
-
if (!hasErrorCode(error2, "ENOENT")) {
|
|
1338
|
-
throw error2;
|
|
1339
|
-
}
|
|
1591
|
+
const states = new Set(machine.states);
|
|
1592
|
+
if (typeof machine.initial !== "string") {
|
|
1593
|
+
throw new TypeError("State machine initial must be a string.");
|
|
1340
1594
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
try {
|
|
1344
|
-
await handle.writeFile(
|
|
1345
|
-
JSON.stringify({ pid: process.pid, host: os.hostname(), acquiredAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
1346
|
-
{ encoding: "utf8" }
|
|
1347
|
-
);
|
|
1348
|
-
} catch (ignoredError) {
|
|
1349
|
-
void ignoredError;
|
|
1595
|
+
if (!states.has(machine.initial)) {
|
|
1596
|
+
throw new Error(`Initial state "${machine.initial}" is not declared.`);
|
|
1350
1597
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
} catch (ignoredError) {
|
|
1354
|
-
void ignoredError;
|
|
1598
|
+
if (!isRecord(machine.events)) {
|
|
1599
|
+
throw new TypeError("State machine events must be an object.");
|
|
1355
1600
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
const retries = options.retries ?? 20;
|
|
1360
|
-
const minTimeout = options.minTimeout ?? 25;
|
|
1361
|
-
const maxTimeout = options.maxTimeout ?? 250;
|
|
1362
|
-
const staleMs = options.staleMs ?? 3e4;
|
|
1363
|
-
const lockPath = `${filePath}.lock`;
|
|
1364
|
-
let attempt = 0;
|
|
1365
|
-
while (attempt <= retries) {
|
|
1366
|
-
throwIfAborted(options.signal);
|
|
1367
|
-
try {
|
|
1368
|
-
const handle = await fs2.open(lockPath, "wx");
|
|
1369
|
-
await writeLockMetadata(handle);
|
|
1370
|
-
let released = false;
|
|
1371
|
-
return async () => {
|
|
1372
|
-
if (released) {
|
|
1373
|
-
return;
|
|
1374
|
-
}
|
|
1375
|
-
released = true;
|
|
1376
|
-
await removeLockFile(fs2, lockPath);
|
|
1377
|
-
};
|
|
1378
|
-
} catch (error2) {
|
|
1379
|
-
if (!hasErrorCode(error2, "EEXIST")) {
|
|
1380
|
-
throw error2;
|
|
1381
|
-
}
|
|
1601
|
+
for (const [eventName, event] of Object.entries(machine.events)) {
|
|
1602
|
+
if (!isRecord(event)) {
|
|
1603
|
+
throw new TypeError(`Event "${eventName}" must be an object.`);
|
|
1382
1604
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
stat3 = await fs2.stat(lockPath);
|
|
1386
|
-
} catch (statError) {
|
|
1387
|
-
if (hasErrorCode(statError, "ENOENT")) {
|
|
1388
|
-
continue;
|
|
1389
|
-
}
|
|
1390
|
-
throw statError;
|
|
1605
|
+
if (event.from !== "*" && !isStateList(event.from)) {
|
|
1606
|
+
throw new TypeError(`Event "${eventName}" has an invalid "from" definition.`);
|
|
1391
1607
|
}
|
|
1392
|
-
if (
|
|
1393
|
-
|
|
1394
|
-
continue;
|
|
1608
|
+
if (typeof event.to !== "string") {
|
|
1609
|
+
throw new TypeError(`Event "${eventName}" target state must be a string.`);
|
|
1395
1610
|
}
|
|
1396
|
-
if (
|
|
1397
|
-
|
|
1611
|
+
if (!states.has(event.to)) {
|
|
1612
|
+
throw new Error(`Event "${eventName}" references unknown target state "${event.to}".`);
|
|
1398
1613
|
}
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
}
|
|
1404
|
-
|
|
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
|
+
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 {
|
|
2689
|
+
await handle.writeFile(
|
|
2690
|
+
JSON.stringify({ pid: process.pid, host: os.hostname(), acquiredAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
2691
|
+
{ encoding: "utf8" }
|
|
2692
|
+
);
|
|
2693
|
+
} catch (ignoredError) {
|
|
2694
|
+
void ignoredError;
|
|
2695
|
+
}
|
|
2696
|
+
try {
|
|
2697
|
+
await handle.close();
|
|
2698
|
+
} catch (ignoredError) {
|
|
2699
|
+
void ignoredError;
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
async function acquireFileLock(filePath, options = {}) {
|
|
2703
|
+
const fs2 = options.fs ?? createDefaultFs();
|
|
2704
|
+
const retries = options.retries ?? 20;
|
|
2705
|
+
const minTimeout = options.minTimeout ?? 25;
|
|
2706
|
+
const maxTimeout = options.maxTimeout ?? 250;
|
|
2707
|
+
const staleMs = options.staleMs ?? 1e3;
|
|
2708
|
+
const pidIsRunning = options.isPidRunning ?? isPidRunning;
|
|
2709
|
+
const lockPath = `${filePath}.lock`;
|
|
2710
|
+
let attempt = 0;
|
|
2711
|
+
while (attempt <= retries) {
|
|
2712
|
+
throwIfAborted(options.signal);
|
|
2713
|
+
try {
|
|
2714
|
+
const handle = await fs2.open(lockPath, "wx");
|
|
2715
|
+
await writeLockMetadata(handle);
|
|
2716
|
+
let released = false;
|
|
2717
|
+
return async () => {
|
|
2718
|
+
if (released) {
|
|
2719
|
+
return;
|
|
2720
|
+
}
|
|
2721
|
+
released = true;
|
|
2722
|
+
await removeLockFile(fs2, lockPath, options.signal);
|
|
2723
|
+
};
|
|
2724
|
+
} catch (error2) {
|
|
2725
|
+
if (!hasErrorCode2(error2, "EEXIST")) {
|
|
2726
|
+
throw error2;
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
let stat3;
|
|
2730
|
+
try {
|
|
2731
|
+
stat3 = await fs2.stat(lockPath);
|
|
2732
|
+
} catch (statError) {
|
|
2733
|
+
if (hasErrorCode2(statError, "ENOENT")) {
|
|
2734
|
+
continue;
|
|
2735
|
+
}
|
|
2736
|
+
throw statError;
|
|
2737
|
+
}
|
|
2738
|
+
const reclaimLock = await shouldReclaimLock({
|
|
2739
|
+
fs: fs2,
|
|
2740
|
+
isPidRunning: pidIsRunning,
|
|
2741
|
+
lockPath,
|
|
2742
|
+
staleMs,
|
|
2743
|
+
stat: stat3
|
|
2744
|
+
});
|
|
2745
|
+
if (reclaimLock === "missing") {
|
|
2746
|
+
continue;
|
|
2747
|
+
}
|
|
2748
|
+
if (reclaimLock) {
|
|
2749
|
+
await removeLockFile(fs2, lockPath, options.signal);
|
|
2750
|
+
continue;
|
|
2751
|
+
}
|
|
2752
|
+
if (attempt >= retries) {
|
|
2753
|
+
break;
|
|
2754
|
+
}
|
|
2755
|
+
await sleep(backoff(attempt, minTimeout, maxTimeout), options.signal);
|
|
2756
|
+
attempt += 1;
|
|
2757
|
+
}
|
|
2758
|
+
throw new LockTimeoutError(`Failed to acquire lock on "${filePath}".`);
|
|
2759
|
+
}
|
|
2760
|
+
|
|
1405
2761
|
// ../task-list/src/backends/markdown-dir.ts
|
|
1406
2762
|
import { parseDocument, stringify } from "yaml";
|
|
1407
2763
|
|
|
@@ -1440,112 +2796,6 @@ var task_schema_default = {
|
|
|
1440
2796
|
additionalProperties: true
|
|
1441
2797
|
};
|
|
1442
2798
|
|
|
1443
|
-
// ../task-list/src/state-machine.ts
|
|
1444
|
-
function isRecord(value) {
|
|
1445
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1446
|
-
}
|
|
1447
|
-
function isStateList(value) {
|
|
1448
|
-
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
1449
|
-
}
|
|
1450
|
-
function canFireFromState(event, fromState) {
|
|
1451
|
-
if (event.from === "*") {
|
|
1452
|
-
return event.to !== fromState;
|
|
1453
|
-
}
|
|
1454
|
-
return event.from.includes(fromState);
|
|
1455
|
-
}
|
|
1456
|
-
function validateMachine(machine) {
|
|
1457
|
-
if (!isRecord(machine)) {
|
|
1458
|
-
throw new TypeError("State machine must be an object.");
|
|
1459
|
-
}
|
|
1460
|
-
if (!isStateList(machine.states)) {
|
|
1461
|
-
throw new TypeError("State machine states must be a string array.");
|
|
1462
|
-
}
|
|
1463
|
-
const states = new Set(machine.states);
|
|
1464
|
-
if (typeof machine.initial !== "string") {
|
|
1465
|
-
throw new TypeError("State machine initial must be a string.");
|
|
1466
|
-
}
|
|
1467
|
-
if (!states.has(machine.initial)) {
|
|
1468
|
-
throw new Error(`Initial state "${machine.initial}" is not declared.`);
|
|
1469
|
-
}
|
|
1470
|
-
if (!isRecord(machine.events)) {
|
|
1471
|
-
throw new TypeError("State machine events must be an object.");
|
|
1472
|
-
}
|
|
1473
|
-
for (const [eventName, event] of Object.entries(machine.events)) {
|
|
1474
|
-
if (!isRecord(event)) {
|
|
1475
|
-
throw new TypeError(`Event "${eventName}" must be an object.`);
|
|
1476
|
-
}
|
|
1477
|
-
if (event.from !== "*" && !isStateList(event.from)) {
|
|
1478
|
-
throw new TypeError(`Event "${eventName}" has an invalid "from" definition.`);
|
|
1479
|
-
}
|
|
1480
|
-
if (typeof event.to !== "string") {
|
|
1481
|
-
throw new TypeError(`Event "${eventName}" target state must be a string.`);
|
|
1482
|
-
}
|
|
1483
|
-
if (!states.has(event.to)) {
|
|
1484
|
-
throw new Error(`Event "${eventName}" references unknown target state "${event.to}".`);
|
|
1485
|
-
}
|
|
1486
|
-
if (event.from !== "*") {
|
|
1487
|
-
for (const fromState of event.from) {
|
|
1488
|
-
if (!states.has(fromState)) {
|
|
1489
|
-
throw new Error(`Event "${eventName}" references unknown source state "${fromState}".`);
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
function eventsFromState(machine, fromState) {
|
|
1496
|
-
const events = [];
|
|
1497
|
-
for (const [eventName, event] of Object.entries(machine.events)) {
|
|
1498
|
-
if (canFireFromState(event, fromState)) {
|
|
1499
|
-
events.push(eventName);
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
return events;
|
|
1503
|
-
}
|
|
1504
|
-
function findEvent(machine, fromState, eventName) {
|
|
1505
|
-
const event = machine.events[eventName];
|
|
1506
|
-
if (event === void 0) {
|
|
1507
|
-
return void 0;
|
|
1508
|
-
}
|
|
1509
|
-
return canFireFromState(event, fromState) ? event : void 0;
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
// ../task-list/src/types.ts
|
|
1513
|
-
var TaskNotFoundError = class extends Error {
|
|
1514
|
-
constructor(message2 = "Task not found.") {
|
|
1515
|
-
super(message2);
|
|
1516
|
-
this.name = "TaskNotFoundError";
|
|
1517
|
-
}
|
|
1518
|
-
};
|
|
1519
|
-
var TaskAlreadyExistsError = class extends Error {
|
|
1520
|
-
constructor(message2 = "Task already exists.") {
|
|
1521
|
-
super(message2);
|
|
1522
|
-
this.name = "TaskAlreadyExistsError";
|
|
1523
|
-
}
|
|
1524
|
-
};
|
|
1525
|
-
var InvalidTransitionError = class extends Error {
|
|
1526
|
-
task;
|
|
1527
|
-
event;
|
|
1528
|
-
to;
|
|
1529
|
-
reason;
|
|
1530
|
-
constructor(messageOrOptions = "Invalid task transition.") {
|
|
1531
|
-
const options = typeof messageOrOptions === "string" ? {
|
|
1532
|
-
reason: messageOrOptions
|
|
1533
|
-
} : messageOrOptions;
|
|
1534
|
-
super(options.reason);
|
|
1535
|
-
this.name = "InvalidTransitionError";
|
|
1536
|
-
this.task = options.task;
|
|
1537
|
-
this.event = options.event;
|
|
1538
|
-
this.to = options.to;
|
|
1539
|
-
this.reason = options.reason;
|
|
1540
|
-
}
|
|
1541
|
-
};
|
|
1542
|
-
var MalformedTaskError = class extends Error {
|
|
1543
|
-
constructor(message2 = "Malformed task.") {
|
|
1544
|
-
super(message2);
|
|
1545
|
-
this.name = "MalformedTaskError";
|
|
1546
|
-
}
|
|
1547
|
-
};
|
|
1548
|
-
|
|
1549
2799
|
// ../task-list/src/state.ts
|
|
1550
2800
|
var defaultStateMachine = {
|
|
1551
2801
|
initial: "draft",
|
|
@@ -1581,64 +2831,17 @@ function resolveStateMachine(stateMachine) {
|
|
|
1581
2831
|
return stateMachine ?? defaultStateMachine;
|
|
1582
2832
|
}
|
|
1583
2833
|
|
|
1584
|
-
// ../task-list/src/backends/utils.ts
|
|
1585
|
-
import path from "node:path";
|
|
1586
|
-
var tmpFileCounter = 0;
|
|
1587
|
-
function hasErrorCode2(error2, code) {
|
|
1588
|
-
return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === code;
|
|
1589
|
-
}
|
|
1590
|
-
function isRecord2(value) {
|
|
1591
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1592
|
-
}
|
|
1593
|
-
function sortStrings(values) {
|
|
1594
|
-
return [...values].sort((left, right) => left.localeCompare(right));
|
|
1595
|
-
}
|
|
1596
|
-
function sortTasks(tasks) {
|
|
1597
|
-
return [...tasks].sort((left, right) => left.qualifiedId.localeCompare(right.qualifiedId));
|
|
1598
|
-
}
|
|
1599
|
-
function validateTaskId(id) {
|
|
1600
|
-
if (id.length === 0 || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
|
|
1601
|
-
throw new Error(`Invalid task id "${id}".`);
|
|
1602
|
-
}
|
|
1603
|
-
return id;
|
|
1604
|
-
}
|
|
1605
|
-
async function statIfExists(fs2, filePath) {
|
|
1606
|
-
try {
|
|
1607
|
-
return await fs2.stat(filePath);
|
|
1608
|
-
} catch (error2) {
|
|
1609
|
-
if (hasErrorCode2(error2, "ENOENT")) {
|
|
1610
|
-
return void 0;
|
|
1611
|
-
}
|
|
1612
|
-
throw error2;
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
async function writeAtomically(fs2, filePath, content) {
|
|
1616
|
-
const tempPath = `${filePath}.tmp-${process.pid}-${tmpFileCounter}`;
|
|
1617
|
-
tmpFileCounter += 1;
|
|
1618
|
-
await fs2.mkdir(path.dirname(filePath), { recursive: true });
|
|
1619
|
-
try {
|
|
1620
|
-
await fs2.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
|
|
1621
|
-
await fs2.rename(tempPath, filePath);
|
|
1622
|
-
} catch (error2) {
|
|
1623
|
-
try {
|
|
1624
|
-
await fs2.unlink(tempPath);
|
|
1625
|
-
} catch (unlinkError) {
|
|
1626
|
-
if (!hasErrorCode2(unlinkError, "ENOENT")) {
|
|
1627
|
-
throw unlinkError;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
throw error2;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
2834
|
// ../task-list/src/backends/markdown-dir.ts
|
|
1635
2835
|
var ARCHIVE_DIRECTORY_NAME = "archive";
|
|
1636
2836
|
var MARKDOWN_EXTENSION = ".md";
|
|
1637
2837
|
var TASK_KIND = "task";
|
|
1638
2838
|
var TASK_VERSION = 1;
|
|
1639
2839
|
var TASK_SCHEMA_ID = task_schema_default.$id;
|
|
2840
|
+
var ORDER_LOCK_FILENAME = ".order.lock";
|
|
2841
|
+
var MIN_PREFIX_WIDTH = 2;
|
|
1640
2842
|
var RESERVED_FRONTMATTER_KEYS = /* @__PURE__ */ new Set([
|
|
1641
2843
|
"$schema",
|
|
2844
|
+
"created",
|
|
1642
2845
|
"description",
|
|
1643
2846
|
"kind",
|
|
1644
2847
|
"name",
|
|
@@ -1651,7 +2854,7 @@ function validateListName(name) {
|
|
|
1651
2854
|
}
|
|
1652
2855
|
return name;
|
|
1653
2856
|
}
|
|
1654
|
-
function
|
|
2857
|
+
function parseQualifiedId2(qualifiedId) {
|
|
1655
2858
|
const separatorIndex = qualifiedId.indexOf("/");
|
|
1656
2859
|
if (separatorIndex <= 0 || separatorIndex !== qualifiedId.lastIndexOf("/") || separatorIndex === qualifiedId.length - 1) {
|
|
1657
2860
|
throw new Error(`Invalid qualified task id "${qualifiedId}".`);
|
|
@@ -1662,16 +2865,16 @@ function parseQualifiedId(qualifiedId) {
|
|
|
1662
2865
|
};
|
|
1663
2866
|
}
|
|
1664
2867
|
function listPath(rootPath, list) {
|
|
1665
|
-
return
|
|
2868
|
+
return path5.join(rootPath, list);
|
|
1666
2869
|
}
|
|
1667
2870
|
function archiveDirectoryPath(rootPath, list) {
|
|
1668
|
-
return
|
|
2871
|
+
return path5.join(listPath(rootPath, list), ARCHIVE_DIRECTORY_NAME);
|
|
1669
2872
|
}
|
|
1670
|
-
function
|
|
1671
|
-
return
|
|
2873
|
+
function activeTaskFilename(id, order, width) {
|
|
2874
|
+
return `${String(order).padStart(width, "0")}-${id}${MARKDOWN_EXTENSION}`;
|
|
1672
2875
|
}
|
|
1673
2876
|
function archivedTaskPath(rootPath, list, id) {
|
|
1674
|
-
return
|
|
2877
|
+
return path5.join(archiveDirectoryPath(rootPath, list), `${id}${MARKDOWN_EXTENSION}`);
|
|
1675
2878
|
}
|
|
1676
2879
|
function isMarkdownFile(entryName) {
|
|
1677
2880
|
return entryName.endsWith(MARKDOWN_EXTENSION);
|
|
@@ -1682,6 +2885,27 @@ function isHiddenEntry(entryName) {
|
|
|
1682
2885
|
function isLockFile(entryName) {
|
|
1683
2886
|
return entryName.endsWith(".lock");
|
|
1684
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
|
+
}
|
|
1685
2909
|
function malformedTask(filePath, field) {
|
|
1686
2910
|
return new MalformedTaskError(`Malformed task "${filePath}": invalid "${field}".`);
|
|
1687
2911
|
}
|
|
@@ -1775,7 +2999,7 @@ async function readDirectoryNames(fs2, directoryPath) {
|
|
|
1775
2999
|
try {
|
|
1776
3000
|
return sortStrings(await fs2.readdir(directoryPath));
|
|
1777
3001
|
} catch (error2) {
|
|
1778
|
-
if (
|
|
3002
|
+
if (hasErrorCode(error2, "ENOENT")) {
|
|
1779
3003
|
return [];
|
|
1780
3004
|
}
|
|
1781
3005
|
throw error2;
|
|
@@ -1799,22 +3023,31 @@ async function readTaskFile(fs2, list, id, filePath, validStates) {
|
|
|
1799
3023
|
task: createTask(list, id, frontmatter, document.body)
|
|
1800
3024
|
};
|
|
1801
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
|
+
}
|
|
1802
3037
|
async function findTaskLocation(fs2, rootPath, list, id) {
|
|
1803
|
-
const
|
|
1804
|
-
const
|
|
1805
|
-
if (
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
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
|
+
}
|
|
1810
3046
|
}
|
|
1811
3047
|
const archivedPath = archivedTaskPath(rootPath, list, id);
|
|
1812
3048
|
const archivedStat = await statIfExists(fs2, archivedPath);
|
|
1813
3049
|
if (archivedStat?.isFile()) {
|
|
1814
|
-
return {
|
|
1815
|
-
archived: true,
|
|
1816
|
-
path: archivedPath
|
|
1817
|
-
};
|
|
3050
|
+
return { archived: true, path: archivedPath };
|
|
1818
3051
|
}
|
|
1819
3052
|
return void 0;
|
|
1820
3053
|
}
|
|
@@ -1843,6 +3076,7 @@ function createdFrontmatter(defaults, input, initialState) {
|
|
|
1843
3076
|
frontmatter[key2] = value;
|
|
1844
3077
|
}
|
|
1845
3078
|
}
|
|
3079
|
+
frontmatter.created = (/* @__PURE__ */ new Date()).toISOString();
|
|
1846
3080
|
return frontmatter;
|
|
1847
3081
|
}
|
|
1848
3082
|
function updatedFrontmatter(existingFrontmatter, task, patch) {
|
|
@@ -1887,35 +3121,95 @@ function assertCreateDoesNotSetState(input) {
|
|
|
1887
3121
|
);
|
|
1888
3122
|
}
|
|
1889
3123
|
}
|
|
3124
|
+
function assertCreateHasId(input) {
|
|
3125
|
+
if (input.id === void 0) {
|
|
3126
|
+
throw new Error("id is required for markdown-dir backend");
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
1890
3129
|
function assertUpdateDoesNotSetState(patch) {
|
|
1891
3130
|
if (Object.prototype.hasOwnProperty.call(patch, "state")) {
|
|
1892
3131
|
throw new Error('Tasks.update() does not accept "state"; use fire() to change task state.');
|
|
1893
3132
|
}
|
|
1894
3133
|
}
|
|
1895
|
-
function
|
|
3134
|
+
function createTasksView2(deps, list) {
|
|
1896
3135
|
const listDirectoryPath = listPath(deps.path, list);
|
|
1897
3136
|
const stateMachine = resolveStateMachine(deps.stateMachine);
|
|
1898
3137
|
const validStates = new Set(stateMachine.states);
|
|
1899
|
-
async function
|
|
1900
|
-
const entries = await readDirectoryNames(deps.fs,
|
|
1901
|
-
const
|
|
3138
|
+
async function readActiveEntries() {
|
|
3139
|
+
const entries = await readDirectoryNames(deps.fs, listDirectoryPath);
|
|
3140
|
+
const result = [];
|
|
1902
3141
|
for (const entryName of entries) {
|
|
1903
|
-
if (isHiddenEntry(entryName) || isLockFile(entryName)
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
const entryPath =
|
|
3142
|
+
if (isHiddenEntry(entryName) || isLockFile(entryName)) continue;
|
|
3143
|
+
const parsed = parseActiveFilename(entryName);
|
|
3144
|
+
if (!parsed) continue;
|
|
3145
|
+
const entryPath = path5.join(listDirectoryPath, entryName);
|
|
1907
3146
|
const entryStat = await statIfExists(deps.fs, entryPath);
|
|
1908
|
-
if (!entryStat?.isFile())
|
|
1909
|
-
|
|
1910
|
-
|
|
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;
|
|
1911
3177
|
const id = entryName.slice(0, -MARKDOWN_EXTENSION.length);
|
|
1912
|
-
|
|
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
|
+
);
|
|
1913
3208
|
}
|
|
1914
|
-
return sortTasks(tasks);
|
|
1915
3209
|
}
|
|
1916
|
-
async function
|
|
1917
|
-
|
|
1918
|
-
const release = await acquireFileLock(
|
|
3210
|
+
async function withListLock(action) {
|
|
3211
|
+
await deps.fs.mkdir(listDirectoryPath, { recursive: true });
|
|
3212
|
+
const release = await acquireFileLock(path5.join(listDirectoryPath, ORDER_LOCK_FILENAME), {
|
|
1919
3213
|
fs: deps.fs,
|
|
1920
3214
|
staleMs: deps.lockStaleMs,
|
|
1921
3215
|
retries: deps.lockRetries
|
|
@@ -1926,6 +3220,10 @@ function createTasksView(deps, list) {
|
|
|
1926
3220
|
await release();
|
|
1927
3221
|
}
|
|
1928
3222
|
}
|
|
3223
|
+
async function withTaskLock(id, action) {
|
|
3224
|
+
validateTaskId(id);
|
|
3225
|
+
return withListLock(action);
|
|
3226
|
+
}
|
|
1929
3227
|
async function getTaskFile(id) {
|
|
1930
3228
|
validateTaskId(id);
|
|
1931
3229
|
return readTaskAtLocation(deps.fs, deps.path, list, id, validStates);
|
|
@@ -1946,27 +3244,41 @@ function createTasksView(deps, list) {
|
|
|
1946
3244
|
name: list,
|
|
1947
3245
|
stateMachine,
|
|
1948
3246
|
async all(filter) {
|
|
1949
|
-
const activeTasks = await
|
|
1950
|
-
const
|
|
1951
|
-
const
|
|
1952
|
-
|
|
1953
|
-
return
|
|
1954
|
-
}
|
|
1955
|
-
|
|
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)];
|
|
1956
3259
|
},
|
|
1957
3260
|
async get(id) {
|
|
1958
3261
|
return (await getTaskFile(id)).task;
|
|
1959
3262
|
},
|
|
1960
3263
|
async create(input) {
|
|
1961
3264
|
assertCreateDoesNotSetState(input);
|
|
3265
|
+
assertCreateHasId(input);
|
|
1962
3266
|
validateTaskId(input.id);
|
|
1963
3267
|
await deps.fs.mkdir(listDirectoryPath, { recursive: true });
|
|
1964
|
-
return
|
|
3268
|
+
return withListLock(async () => {
|
|
1965
3269
|
const existing = await findTaskLocation(deps.fs, deps.path, list, input.id);
|
|
1966
3270
|
if (existing) {
|
|
1967
3271
|
throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
|
|
1968
3272
|
}
|
|
1969
|
-
const
|
|
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);
|
|
1970
3282
|
const frontmatter = createdFrontmatter(deps.defaults, input, stateMachine.initial);
|
|
1971
3283
|
const description = input.description ?? "";
|
|
1972
3284
|
await writeAtomically(deps.fs, targetPath, serializeTaskDocument(frontmatter, description));
|
|
@@ -2042,14 +3354,60 @@ function createTasksView(deps, list) {
|
|
|
2042
3354
|
}
|
|
2043
3355
|
await deps.fs.unlink(location.path);
|
|
2044
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
|
+
});
|
|
2045
3401
|
}
|
|
2046
3402
|
};
|
|
2047
3403
|
}
|
|
2048
3404
|
async function markdownDirBackend(deps) {
|
|
2049
3405
|
await ensureRootPath(deps);
|
|
3406
|
+
const stateMachine = resolveStateMachine(deps.stateMachine);
|
|
3407
|
+
const validStates = new Set(stateMachine.states);
|
|
2050
3408
|
const list = (name) => {
|
|
2051
3409
|
const listName = validateListName(name);
|
|
2052
|
-
return
|
|
3410
|
+
return createTasksView2(deps, listName);
|
|
2053
3411
|
};
|
|
2054
3412
|
const lists = async () => {
|
|
2055
3413
|
const entries = await readDirectoryNames(deps.fs, deps.path);
|
|
@@ -2058,7 +3416,7 @@ async function markdownDirBackend(deps) {
|
|
|
2058
3416
|
if (entryName === ARCHIVE_DIRECTORY_NAME || isHiddenEntry(entryName) || isLockFile(entryName)) {
|
|
2059
3417
|
continue;
|
|
2060
3418
|
}
|
|
2061
|
-
const entryPath =
|
|
3419
|
+
const entryPath = path5.join(deps.path, entryName);
|
|
2062
3420
|
const entryStat = await statIfExists(deps.fs, entryPath);
|
|
2063
3421
|
if (entryStat?.isDirectory()) {
|
|
2064
3422
|
result.push(entryName);
|
|
@@ -2072,22 +3430,70 @@ async function markdownDirBackend(deps) {
|
|
|
2072
3430
|
for (const taskListName of allLists) {
|
|
2073
3431
|
tasks.push(...await list(taskListName).all(filter));
|
|
2074
3432
|
}
|
|
2075
|
-
return
|
|
3433
|
+
return tasks;
|
|
2076
3434
|
};
|
|
2077
3435
|
const get = async (qualifiedId) => {
|
|
2078
|
-
const { list: listName, id } =
|
|
3436
|
+
const { list: listName, id } = parseQualifiedId2(qualifiedId);
|
|
2079
3437
|
return list(listName).get(id);
|
|
2080
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
|
+
};
|
|
2081
3486
|
return {
|
|
2082
3487
|
list,
|
|
2083
3488
|
lists,
|
|
2084
3489
|
allTasks,
|
|
2085
|
-
get
|
|
3490
|
+
get,
|
|
3491
|
+
moveBetweenLists
|
|
2086
3492
|
};
|
|
2087
3493
|
}
|
|
2088
3494
|
|
|
2089
3495
|
// ../task-list/src/backends/yaml-file.ts
|
|
2090
|
-
import { parseDocument as parseDocument2 } from "yaml";
|
|
3496
|
+
import { isMap, parseDocument as parseDocument2 } from "yaml";
|
|
2091
3497
|
|
|
2092
3498
|
// ../task-list/src/schema/store.schema.json
|
|
2093
3499
|
var store_schema_default = {
|
|
@@ -2130,7 +3536,15 @@ var STORE_VERSION = 1;
|
|
|
2130
3536
|
var TASK_KIND2 = "task";
|
|
2131
3537
|
var TASK_SCHEMA_ID2 = task_schema_default.$id;
|
|
2132
3538
|
var TASK_VERSION2 = 1;
|
|
2133
|
-
var RESERVED_TASK_KEYS = /* @__PURE__ */ new Set([
|
|
3539
|
+
var RESERVED_TASK_KEYS = /* @__PURE__ */ new Set([
|
|
3540
|
+
"$schema",
|
|
3541
|
+
"created",
|
|
3542
|
+
"description",
|
|
3543
|
+
"kind",
|
|
3544
|
+
"name",
|
|
3545
|
+
"state",
|
|
3546
|
+
"version"
|
|
3547
|
+
]);
|
|
2134
3548
|
function malformedStore(filePath, field) {
|
|
2135
3549
|
return new MalformedTaskError(`Malformed task store "${filePath}": invalid "${field}".`);
|
|
2136
3550
|
}
|
|
@@ -2143,7 +3557,7 @@ function validateListName2(name) {
|
|
|
2143
3557
|
}
|
|
2144
3558
|
return name;
|
|
2145
3559
|
}
|
|
2146
|
-
function
|
|
3560
|
+
function parseQualifiedId3(qualifiedId) {
|
|
2147
3561
|
const separatorIndex = qualifiedId.indexOf("/");
|
|
2148
3562
|
if (separatorIndex <= 0 || separatorIndex !== qualifiedId.lastIndexOf("/") || separatorIndex === qualifiedId.length - 1) {
|
|
2149
3563
|
throw new Error(`Invalid qualified task id "${qualifiedId}".`);
|
|
@@ -2201,6 +3615,7 @@ function createTaskRecord(defaults, input, initialState) {
|
|
|
2201
3615
|
taskRecord[key2] = value;
|
|
2202
3616
|
}
|
|
2203
3617
|
}
|
|
3618
|
+
taskRecord.created = (/* @__PURE__ */ new Date()).toISOString();
|
|
2204
3619
|
return taskRecord;
|
|
2205
3620
|
}
|
|
2206
3621
|
function assertCreateDoesNotSetState2(input) {
|
|
@@ -2210,6 +3625,11 @@ function assertCreateDoesNotSetState2(input) {
|
|
|
2210
3625
|
);
|
|
2211
3626
|
}
|
|
2212
3627
|
}
|
|
3628
|
+
function assertCreateHasId2(input) {
|
|
3629
|
+
if (input.id === void 0) {
|
|
3630
|
+
throw new Error("id is required for yaml-file backend");
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
2213
3633
|
function assertUpdateDoesNotSetState2(patch) {
|
|
2214
3634
|
if (Object.prototype.hasOwnProperty.call(patch, "state")) {
|
|
2215
3635
|
throw new Error('Tasks.update() does not accept "state"; use fire() to change task state.');
|
|
@@ -2356,7 +3776,49 @@ function getTaskOrThrow(store, list, id) {
|
|
|
2356
3776
|
if (!taskRecord) {
|
|
2357
3777
|
throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
|
|
2358
3778
|
}
|
|
2359
|
-
return taskRecord;
|
|
3779
|
+
return taskRecord;
|
|
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;
|
|
2360
3822
|
}
|
|
2361
3823
|
async function ensureStorePath(deps) {
|
|
2362
3824
|
if (!deps.create) {
|
|
@@ -2395,7 +3857,7 @@ async function withStoreLock(deps, action) {
|
|
|
2395
3857
|
await release();
|
|
2396
3858
|
}
|
|
2397
3859
|
}
|
|
2398
|
-
function
|
|
3860
|
+
function createTasksView3(deps, list) {
|
|
2399
3861
|
const stateMachine = resolveStateMachine(deps.stateMachine);
|
|
2400
3862
|
const validStates = new Set(stateMachine.states);
|
|
2401
3863
|
async function readTasks(filter) {
|
|
@@ -2404,8 +3866,11 @@ function createTasksView2(deps, list) {
|
|
|
2404
3866
|
if (!listRecord) {
|
|
2405
3867
|
return [];
|
|
2406
3868
|
}
|
|
2407
|
-
const
|
|
2408
|
-
|
|
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);
|
|
2409
3874
|
}
|
|
2410
3875
|
function assertFireableTaskEvent(task, eventName) {
|
|
2411
3876
|
const event = findEvent(stateMachine, task.state, eventName);
|
|
@@ -2432,6 +3897,7 @@ function createTasksView2(deps, list) {
|
|
|
2432
3897
|
},
|
|
2433
3898
|
async create(input) {
|
|
2434
3899
|
assertCreateDoesNotSetState2(input);
|
|
3900
|
+
assertCreateHasId2(input);
|
|
2435
3901
|
validateTaskId(input.id);
|
|
2436
3902
|
return withStoreLock(deps, async () => {
|
|
2437
3903
|
const { document, store } = await readStore(deps.fs, deps.path, validStates);
|
|
@@ -2520,6 +3986,72 @@ function createTasksView2(deps, list) {
|
|
|
2520
3986
|
document.deleteIn(["lists", list, id]);
|
|
2521
3987
|
await writeAtomically(deps.fs, deps.path, serializeDocument(document));
|
|
2522
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
|
+
});
|
|
2523
4055
|
}
|
|
2524
4056
|
};
|
|
2525
4057
|
}
|
|
@@ -2529,7 +4061,7 @@ async function yamlFileBackend(deps) {
|
|
|
2529
4061
|
const validStates = new Set(stateMachine.states);
|
|
2530
4062
|
const list = (name) => {
|
|
2531
4063
|
const listName = validateListName2(name);
|
|
2532
|
-
return
|
|
4064
|
+
return createTasksView3({ ...deps, stateMachine }, listName);
|
|
2533
4065
|
};
|
|
2534
4066
|
const lists = async () => {
|
|
2535
4067
|
const { store } = await readStore(deps.fs, deps.path, validStates);
|
|
@@ -2537,26 +4069,47 @@ async function yamlFileBackend(deps) {
|
|
|
2537
4069
|
};
|
|
2538
4070
|
const allTasks = async (filter) => {
|
|
2539
4071
|
const { store } = await readStore(deps.fs, deps.path, validStates);
|
|
2540
|
-
const
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
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));
|
|
2548
4082
|
}
|
|
2549
|
-
return
|
|
4083
|
+
return result;
|
|
2550
4084
|
};
|
|
2551
4085
|
const get = async (qualifiedId) => {
|
|
2552
|
-
const { list: listName, id } =
|
|
4086
|
+
const { list: listName, id } = parseQualifiedId3(qualifiedId);
|
|
2553
4087
|
return list(listName).get(id);
|
|
2554
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
|
+
};
|
|
2555
4107
|
return {
|
|
2556
4108
|
list,
|
|
2557
4109
|
lists,
|
|
2558
4110
|
allTasks,
|
|
2559
|
-
get
|
|
4111
|
+
get,
|
|
4112
|
+
moveBetweenLists
|
|
2560
4113
|
};
|
|
2561
4114
|
}
|
|
2562
4115
|
|
|
@@ -2571,10 +4124,18 @@ function createDefaultFs2() {
|
|
|
2571
4124
|
return fsPromises2;
|
|
2572
4125
|
}
|
|
2573
4126
|
async function openTaskList(options) {
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
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}".`);
|
|
2577
4135
|
}
|
|
4136
|
+
}
|
|
4137
|
+
async function openFileBackend(options) {
|
|
4138
|
+
const factory = backendFactories[options.type];
|
|
2578
4139
|
const stateMachine = resolveStateMachine(options.stateMachine);
|
|
2579
4140
|
validateMachine(stateMachine);
|
|
2580
4141
|
const deps = {
|
|
@@ -2590,9 +4151,23 @@ async function openTaskList(options) {
|
|
|
2590
4151
|
};
|
|
2591
4152
|
return factory(deps);
|
|
2592
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
|
+
}
|
|
2593
4168
|
|
|
2594
4169
|
// ../toolcraft/src/human-in-loop/approval-tasks.ts
|
|
2595
|
-
import { randomBytes } from "node:crypto";
|
|
4170
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
2596
4171
|
|
|
2597
4172
|
// ../toolcraft/src/human-in-loop/state-machine.ts
|
|
2598
4173
|
var approvalStateMachine = {
|
|
@@ -2675,7 +4250,7 @@ function isListValidated(runtimeOptions, listName) {
|
|
|
2675
4250
|
return validatedListsByRuntime.get(runtimeOptions)?.has(listName) ?? false;
|
|
2676
4251
|
}
|
|
2677
4252
|
function createApprovalRecord(payload, enqueuedAt) {
|
|
2678
|
-
const approvalId = `${enqueuedAt.slice(0, 19).replaceAll(":", "-")}-${
|
|
4253
|
+
const approvalId = `${enqueuedAt.slice(0, 19).replaceAll(":", "-")}-${randomBytes3(3).toString("hex")}`;
|
|
2679
4254
|
return {
|
|
2680
4255
|
approvalId,
|
|
2681
4256
|
name: `${payload.commandPath} (${enqueuedAt})`,
|
|
@@ -2758,7 +4333,7 @@ function areEqualStrings(left, right) {
|
|
|
2758
4333
|
}
|
|
2759
4334
|
|
|
2760
4335
|
// ../toolcraft/src/human-in-loop/runner.ts
|
|
2761
|
-
import { access, readFile, writeFile } from "node:fs/promises";
|
|
4336
|
+
import { access, readFile as readFile3, writeFile } from "node:fs/promises";
|
|
2762
4337
|
|
|
2763
4338
|
// ../toolcraft/src/human-in-loop/default-provider.ts
|
|
2764
4339
|
import process2 from "node:process";
|
|
@@ -2866,13 +4441,13 @@ function defaultProviderForPlatform() {
|
|
|
2866
4441
|
}
|
|
2867
4442
|
|
|
2868
4443
|
// ../toolcraft/src/human-in-loop/spawn.ts
|
|
2869
|
-
import { spawn } from "node:child_process";
|
|
4444
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
2870
4445
|
function spawnApprovalRunner(approvalId, runtimeOptions, spawnFn) {
|
|
2871
4446
|
const { execPath, entryArgs } = runtimeOptions.binPath ?? {
|
|
2872
4447
|
execPath: process.execPath,
|
|
2873
4448
|
entryArgs: [process.argv[1]]
|
|
2874
4449
|
};
|
|
2875
|
-
const fn = spawnFn ??
|
|
4450
|
+
const fn = spawnFn ?? spawn2;
|
|
2876
4451
|
const child = fn(execPath, [...entryArgs, "approvals", "run", approvalId], {
|
|
2877
4452
|
detached: true,
|
|
2878
4453
|
stdio: "ignore",
|
|
@@ -3057,13 +4632,13 @@ function createHandlerContext(command, params17) {
|
|
|
3057
4632
|
}
|
|
3058
4633
|
function createFs() {
|
|
3059
4634
|
return {
|
|
3060
|
-
readFile: async (
|
|
3061
|
-
writeFile: async (
|
|
3062
|
-
await writeFile(
|
|
4635
|
+
readFile: async (path15, encoding = "utf8") => readFile3(path15, { encoding }),
|
|
4636
|
+
writeFile: async (path15, contents) => {
|
|
4637
|
+
await writeFile(path15, contents);
|
|
3063
4638
|
},
|
|
3064
|
-
exists: async (
|
|
4639
|
+
exists: async (path15) => {
|
|
3065
4640
|
try {
|
|
3066
|
-
await access(
|
|
4641
|
+
await access(path15);
|
|
3067
4642
|
return true;
|
|
3068
4643
|
} catch {
|
|
3069
4644
|
return false;
|
|
@@ -3315,23 +4890,23 @@ function escapeMarkdownCell(value) {
|
|
|
3315
4890
|
}
|
|
3316
4891
|
|
|
3317
4892
|
// ../toolcraft/src/mcp-proxy.ts
|
|
3318
|
-
import { existsSync } from "node:fs";
|
|
3319
|
-
import { mkdir, readFile as
|
|
3320
|
-
import
|
|
4893
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
4894
|
+
import { mkdir, readFile as readFile4, rename, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
|
|
4895
|
+
import path8 from "node:path";
|
|
3321
4896
|
|
|
3322
4897
|
// ../tiny-mcp-client/src/internal.ts
|
|
3323
|
-
import { spawn as
|
|
4898
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
3324
4899
|
import { PassThrough as PassThrough2 } from "node:stream";
|
|
3325
4900
|
|
|
3326
|
-
// ../mcp-oauth/
|
|
4901
|
+
// ../mcp-oauth/dist/client/auth-store-session-store.js
|
|
3327
4902
|
import crypto from "node:crypto";
|
|
3328
|
-
import
|
|
4903
|
+
import path7 from "node:path";
|
|
3329
4904
|
|
|
3330
4905
|
// ../auth-store/src/encrypted-file-store.ts
|
|
3331
|
-
import { createCipheriv, createDecipheriv, randomBytes as
|
|
4906
|
+
import { createCipheriv, createDecipheriv, randomBytes as randomBytes4, scrypt } from "node:crypto";
|
|
3332
4907
|
import { promises as fs } from "node:fs";
|
|
3333
4908
|
import { homedir, hostname as hostname2, userInfo } from "node:os";
|
|
3334
|
-
import
|
|
4909
|
+
import path6 from "node:path";
|
|
3335
4910
|
var derivedKeyCache = /* @__PURE__ */ new Map();
|
|
3336
4911
|
var ENCRYPTION_ALGORITHM = "aes-256-gcm";
|
|
3337
4912
|
var ENCRYPTION_VERSION = 1;
|
|
@@ -3349,13 +4924,13 @@ var EncryptedFileStore = class {
|
|
|
3349
4924
|
constructor(input) {
|
|
3350
4925
|
this.fs = input.fs ?? fs;
|
|
3351
4926
|
this.salt = input.salt;
|
|
3352
|
-
this.filePath = input.filePath ??
|
|
4927
|
+
this.filePath = input.filePath ?? path6.join(
|
|
3353
4928
|
(input.getHomeDirectory ?? homedir)(),
|
|
3354
4929
|
input.defaultDirectory ?? ".auth-store",
|
|
3355
4930
|
input.defaultFileName ?? "credentials.enc"
|
|
3356
4931
|
);
|
|
3357
4932
|
this.getMachineIdentity = input.getMachineIdentity ?? defaultMachineIdentity;
|
|
3358
|
-
this.getRandomBytes = input.getRandomBytes ??
|
|
4933
|
+
this.getRandomBytes = input.getRandomBytes ?? randomBytes4;
|
|
3359
4934
|
}
|
|
3360
4935
|
async get() {
|
|
3361
4936
|
let rawDocument;
|
|
@@ -3402,7 +4977,7 @@ var EncryptedFileStore = class {
|
|
|
3402
4977
|
authTag: authTag.toString("base64"),
|
|
3403
4978
|
ciphertext: ciphertext.toString("base64")
|
|
3404
4979
|
};
|
|
3405
|
-
await this.fs.mkdir(
|
|
4980
|
+
await this.fs.mkdir(path6.dirname(this.filePath), { recursive: true });
|
|
3406
4981
|
await this.fs.writeFile(this.filePath, JSON.stringify(document), {
|
|
3407
4982
|
encoding: "utf8"
|
|
3408
4983
|
});
|
|
@@ -3453,7 +5028,7 @@ async function deriveEncryptionKey(getMachineIdentity, salt) {
|
|
|
3453
5028
|
function parseEncryptedDocument(raw) {
|
|
3454
5029
|
try {
|
|
3455
5030
|
const parsed = JSON.parse(raw);
|
|
3456
|
-
if (!
|
|
5031
|
+
if (!isRecord4(parsed)) {
|
|
3457
5032
|
return null;
|
|
3458
5033
|
}
|
|
3459
5034
|
if (parsed.version !== ENCRYPTION_VERSION) {
|
|
@@ -3472,7 +5047,7 @@ function parseEncryptedDocument(raw) {
|
|
|
3472
5047
|
return null;
|
|
3473
5048
|
}
|
|
3474
5049
|
}
|
|
3475
|
-
function
|
|
5050
|
+
function isRecord4(value) {
|
|
3476
5051
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
3477
5052
|
}
|
|
3478
5053
|
function isNotFoundError(error2) {
|
|
@@ -3482,7 +5057,7 @@ function isNotFoundError(error2) {
|
|
|
3482
5057
|
}
|
|
3483
5058
|
|
|
3484
5059
|
// ../auth-store/src/keychain-store.ts
|
|
3485
|
-
import { spawn as
|
|
5060
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
3486
5061
|
var SECURITY_CLI = "security";
|
|
3487
5062
|
var KEYCHAIN_ITEM_NOT_FOUND_EXIT_CODE = 44;
|
|
3488
5063
|
var KeychainStore = class {
|
|
@@ -3546,7 +5121,7 @@ var KeychainStore = class {
|
|
|
3546
5121
|
};
|
|
3547
5122
|
function runSecurityCommand(command, args) {
|
|
3548
5123
|
return new Promise((resolve) => {
|
|
3549
|
-
const child =
|
|
5124
|
+
const child = spawn3(command, args, {
|
|
3550
5125
|
stdio: ["ignore", "pipe", "pipe"]
|
|
3551
5126
|
});
|
|
3552
5127
|
let stdout = "";
|
|
@@ -3640,7 +5215,7 @@ function resolveBackend(input) {
|
|
|
3640
5215
|
return "file";
|
|
3641
5216
|
}
|
|
3642
5217
|
|
|
3643
|
-
// ../mcp-oauth/
|
|
5218
|
+
// ../mcp-oauth/dist/resource-indicator.js
|
|
3644
5219
|
function canonicalizeResourceIndicator(value) {
|
|
3645
5220
|
let url;
|
|
3646
5221
|
try {
|
|
@@ -3652,7 +5227,7 @@ function canonicalizeResourceIndicator(value) {
|
|
|
3652
5227
|
return url.toString();
|
|
3653
5228
|
}
|
|
3654
5229
|
|
|
3655
|
-
// ../mcp-oauth/
|
|
5230
|
+
// ../mcp-oauth/dist/client/auth-store-session-store.js
|
|
3656
5231
|
var DEFAULT_FILE_SALT = "poe-code:mcp-oauth:v1";
|
|
3657
5232
|
var DEFAULT_FILE_DIRECTORY = ".poe-code/mcp-oauth";
|
|
3658
5233
|
var DEFAULT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth";
|
|
@@ -3709,7 +5284,7 @@ function createAuthStoreClientStore(options) {
|
|
|
3709
5284
|
}
|
|
3710
5285
|
function createNamedSecretStore(key2, options, defaults) {
|
|
3711
5286
|
const hash = crypto.createHash("sha256").update(key2).digest("hex");
|
|
3712
|
-
const parsedFilePath = options.fileStore?.filePath === void 0 ? null :
|
|
5287
|
+
const parsedFilePath = options.fileStore?.filePath === void 0 ? null : path7.parse(options.fileStore.filePath);
|
|
3713
5288
|
const fileStore = {
|
|
3714
5289
|
...options.fileStore,
|
|
3715
5290
|
salt: options.fileStore?.salt ?? defaults.salt,
|
|
@@ -3724,37 +5299,29 @@ function createNamedSecretStore(key2, options, defaults) {
|
|
|
3724
5299
|
return createSecretStore({ ...options, fileStore, keychainStore }).store;
|
|
3725
5300
|
}
|
|
3726
5301
|
function createResourceSecretStore(resource, options) {
|
|
3727
|
-
return createNamedSecretStore(
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
service: DEFAULT_KEYCHAIN_SERVICE,
|
|
3734
|
-
accountPrefix: "provider"
|
|
3735
|
-
}
|
|
3736
|
-
);
|
|
5302
|
+
return createNamedSecretStore(canonicalizeResourceIndicator(resource), options, {
|
|
5303
|
+
salt: DEFAULT_FILE_SALT,
|
|
5304
|
+
directory: DEFAULT_FILE_DIRECTORY,
|
|
5305
|
+
service: DEFAULT_KEYCHAIN_SERVICE,
|
|
5306
|
+
accountPrefix: "provider"
|
|
5307
|
+
});
|
|
3737
5308
|
}
|
|
3738
5309
|
function createIssuerSecretStore(issuer, options) {
|
|
3739
|
-
return createNamedSecretStore(
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
|
|
3746
|
-
accountPrefix: "issuer"
|
|
3747
|
-
}
|
|
3748
|
-
);
|
|
5310
|
+
return createNamedSecretStore(issuer, options, {
|
|
5311
|
+
salt: DEFAULT_CLIENT_FILE_SALT,
|
|
5312
|
+
directory: DEFAULT_CLIENT_FILE_DIRECTORY,
|
|
5313
|
+
service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
|
|
5314
|
+
accountPrefix: "issuer"
|
|
5315
|
+
});
|
|
3749
5316
|
}
|
|
3750
5317
|
|
|
3751
|
-
// ../mcp-oauth/
|
|
5318
|
+
// ../mcp-oauth/dist/client/default-oauth-client-provider.js
|
|
3752
5319
|
import { URL as URL2 } from "node:url";
|
|
3753
5320
|
|
|
3754
|
-
// ../mcp-oauth/
|
|
5321
|
+
// ../mcp-oauth/dist/client/loopback-authorization.js
|
|
3755
5322
|
import http from "node:http";
|
|
3756
5323
|
|
|
3757
|
-
// ../mcp-oauth/
|
|
5324
|
+
// ../mcp-oauth/dist/client/authorization-state.js
|
|
3758
5325
|
import crypto2 from "node:crypto";
|
|
3759
5326
|
function createAuthorizationState(input) {
|
|
3760
5327
|
const payload = {
|
|
@@ -3784,7 +5351,7 @@ function parseAuthorizationState(value) {
|
|
|
3784
5351
|
}
|
|
3785
5352
|
}
|
|
3786
5353
|
|
|
3787
|
-
// ../mcp-oauth/
|
|
5354
|
+
// ../mcp-oauth/dist/client/loopback-authorization.js
|
|
3788
5355
|
async function createLoopbackAuthorizationSession(options = {}) {
|
|
3789
5356
|
const callbackPath = options.callbackPath ?? "/callback";
|
|
3790
5357
|
const server = options.createServer ? options.createServer() : http.createServer();
|
|
@@ -3857,10 +5424,7 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
|
|
|
3857
5424
|
return;
|
|
3858
5425
|
}
|
|
3859
5426
|
try {
|
|
3860
|
-
const code = validateAuthorizationCallbackParameters(
|
|
3861
|
-
callbackParameters,
|
|
3862
|
-
expectedAuthorization
|
|
3863
|
-
);
|
|
5427
|
+
const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
|
|
3864
5428
|
settle(() => resolve(code));
|
|
3865
5429
|
} catch (error2) {
|
|
3866
5430
|
settle(() => reject(error2 instanceof Error ? error2 : new Error(String(error2))));
|
|
@@ -3926,8 +5490,8 @@ function validateAuthorizationCallbackParameters(callback, expected) {
|
|
|
3926
5490
|
}
|
|
3927
5491
|
return callback.code;
|
|
3928
5492
|
}
|
|
3929
|
-
function escapeHtml(
|
|
3930
|
-
return
|
|
5493
|
+
function escapeHtml(text5) {
|
|
5494
|
+
return text5.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
3931
5495
|
}
|
|
3932
5496
|
function buildSuccessPage(landingPage) {
|
|
3933
5497
|
const title = landingPage?.title ?? "Connected";
|
|
@@ -3943,7 +5507,7 @@ function buildSuccessPage(landingPage) {
|
|
|
3943
5507
|
].join("");
|
|
3944
5508
|
}
|
|
3945
5509
|
|
|
3946
|
-
// ../mcp-oauth/
|
|
5510
|
+
// ../mcp-oauth/dist/client/pkce.js
|
|
3947
5511
|
import crypto3 from "node:crypto";
|
|
3948
5512
|
function generateCodeVerifier() {
|
|
3949
5513
|
return crypto3.randomBytes(32).toString("base64url");
|
|
@@ -3952,7 +5516,7 @@ function generateCodeChallenge(verifier) {
|
|
|
3952
5516
|
return crypto3.createHash("sha256").update(verifier).digest("base64url");
|
|
3953
5517
|
}
|
|
3954
5518
|
|
|
3955
|
-
// ../mcp-oauth/
|
|
5519
|
+
// ../mcp-oauth/dist/client/token-endpoint.js
|
|
3956
5520
|
var OAuthError = class extends Error {
|
|
3957
5521
|
error;
|
|
3958
5522
|
errorDescription;
|
|
@@ -4082,7 +5646,7 @@ function normalizeBearerTokenType(value) {
|
|
|
4082
5646
|
return value.toLowerCase() === "bearer" ? "Bearer" : null;
|
|
4083
5647
|
}
|
|
4084
5648
|
|
|
4085
|
-
// ../mcp-oauth/
|
|
5649
|
+
// ../mcp-oauth/dist/client/default-oauth-client-provider.js
|
|
4086
5650
|
function createOAuthClientProvider(options) {
|
|
4087
5651
|
if (isProviderOptions(options)) {
|
|
4088
5652
|
return options.provider;
|
|
@@ -4116,16 +5680,10 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
4116
5680
|
const resource = canonicalizeResourceIndicator(input.discovery.resource);
|
|
4117
5681
|
assertRequestMatchesResource(requestUrl, resource);
|
|
4118
5682
|
const forceRefresh = hasCachedAccessToken(await loadSession(resource)) && input.challenge?.params.error === "invalid_token";
|
|
4119
|
-
const session = await ensureAuthorizedSession(
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
resource
|
|
4124
|
-
},
|
|
4125
|
-
input.fetch,
|
|
4126
|
-
true,
|
|
4127
|
-
forceRefresh
|
|
4128
|
-
);
|
|
5683
|
+
const session = await ensureAuthorizedSession(resource, {
|
|
5684
|
+
...input.discovery,
|
|
5685
|
+
resource
|
|
5686
|
+
}, input.fetch, true, forceRefresh);
|
|
4129
5687
|
if (session?.tokens?.accessToken === void 0) {
|
|
4130
5688
|
return { action: "fail" };
|
|
4131
5689
|
}
|
|
@@ -4190,11 +5748,7 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
4190
5748
|
await saveSession(resource, clearedSession);
|
|
4191
5749
|
return clearedSession;
|
|
4192
5750
|
}
|
|
4193
|
-
if (shouldReRegisterStoredDynamicClient(
|
|
4194
|
-
error2,
|
|
4195
|
-
await loadRegisteredClient(discovery.authorizationServer),
|
|
4196
|
-
false
|
|
4197
|
-
)) {
|
|
5751
|
+
if (shouldReRegisterStoredDynamicClient(error2, await loadRegisteredClient(discovery.authorizationServer), false)) {
|
|
4198
5752
|
await clearRegisteredClient(discovery.authorizationServer);
|
|
4199
5753
|
await clearSession(resource);
|
|
4200
5754
|
return null;
|
|
@@ -4353,10 +5907,7 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
4353
5907
|
};
|
|
4354
5908
|
}
|
|
4355
5909
|
}
|
|
4356
|
-
const registrationBody = buildClientRegistrationBody(
|
|
4357
|
-
getClientMetadata(options.client),
|
|
4358
|
-
redirectUri
|
|
4359
|
-
);
|
|
5910
|
+
const registrationBody = buildClientRegistrationBody(getClientMetadata(options.client), redirectUri);
|
|
4360
5911
|
const response = await fetch2(registrationEndpoint, {
|
|
4361
5912
|
method: "POST",
|
|
4362
5913
|
headers: {
|
|
@@ -4480,9 +6031,7 @@ function buildAuthorizationUrl(input) {
|
|
|
4480
6031
|
}
|
|
4481
6032
|
function assertS256PkceSupport(metadata) {
|
|
4482
6033
|
if (!metadata.code_challenge_methods_supported.includes("S256")) {
|
|
4483
|
-
throw new Error(
|
|
4484
|
-
"Authorization server metadata must advertise code_challenge_methods_supported including S256"
|
|
4485
|
-
);
|
|
6034
|
+
throw new Error("Authorization server metadata must advertise code_challenge_methods_supported including S256");
|
|
4486
6035
|
}
|
|
4487
6036
|
}
|
|
4488
6037
|
function normalizeHostname(hostname3) {
|
|
@@ -4520,9 +6069,7 @@ function assertNoAccessTokenInUrl(value, label) {
|
|
|
4520
6069
|
}
|
|
4521
6070
|
function assertRequestMatchesResource(requestUrl, resource) {
|
|
4522
6071
|
if (requestUrl !== resource) {
|
|
4523
|
-
throw new Error(
|
|
4524
|
-
`OAuth request URL ${requestUrl} does not match discovered resource ${resource}`
|
|
4525
|
-
);
|
|
6072
|
+
throw new Error(`OAuth request URL ${requestUrl} does not match discovered resource ${resource}`);
|
|
4526
6073
|
}
|
|
4527
6074
|
}
|
|
4528
6075
|
function buildClientRegistrationBody(metadata, redirectUri) {
|
|
@@ -4566,13 +6113,8 @@ function shouldReRegisterStoredDynamicClient(error2, client, alreadyAttempted) {
|
|
|
4566
6113
|
return true;
|
|
4567
6114
|
}
|
|
4568
6115
|
|
|
4569
|
-
// ../mcp-oauth/
|
|
4570
|
-
import {
|
|
4571
|
-
decodeProtectedHeader,
|
|
4572
|
-
errors,
|
|
4573
|
-
importJWK,
|
|
4574
|
-
jwtVerify
|
|
4575
|
-
} from "jose";
|
|
6116
|
+
// ../mcp-oauth/dist/server/jwks-token-verifier.js
|
|
6117
|
+
import { decodeProtectedHeader, errors, importJWK, jwtVerify } from "jose";
|
|
4576
6118
|
|
|
4577
6119
|
// ../tiny-mcp-client/src/oauth-discovery.ts
|
|
4578
6120
|
function defaultOAuthMetadataFetch(input, init) {
|
|
@@ -5336,7 +6878,7 @@ var ERROR_INVALID_REQUEST = -32600;
|
|
|
5336
6878
|
var ERROR_METHOD_NOT_FOUND = -32601;
|
|
5337
6879
|
var ERROR_INTERNAL = -32603;
|
|
5338
6880
|
function defaultStdioSpawn(command, args, options) {
|
|
5339
|
-
return
|
|
6881
|
+
return spawn4(command, args, options);
|
|
5340
6882
|
}
|
|
5341
6883
|
function defaultHttpTransportFetch(input, init) {
|
|
5342
6884
|
return fetch(input, init);
|
|
@@ -6647,9 +8189,9 @@ function mergeJsonSchemas(base, overlay) {
|
|
|
6647
8189
|
...mergedRequired === void 0 ? {} : { required: mergedRequired }
|
|
6648
8190
|
};
|
|
6649
8191
|
}
|
|
6650
|
-
function hasSelfReferencingRef(schema, root,
|
|
8192
|
+
function hasSelfReferencingRef(schema, root, path15 = "#", activePaths = /* @__PURE__ */ new Set()) {
|
|
6651
8193
|
const nextActivePaths = new Set(activePaths);
|
|
6652
|
-
nextActivePaths.add(
|
|
8194
|
+
nextActivePaths.add(path15);
|
|
6653
8195
|
const localRefPath = getLocalRefPath(schema.$ref);
|
|
6654
8196
|
if (localRefPath !== void 0) {
|
|
6655
8197
|
if (nextActivePaths.has(localRefPath)) {
|
|
@@ -6660,13 +8202,13 @@ function hasSelfReferencingRef(schema, root, path12 = "#", activePaths = /* @__P
|
|
|
6660
8202
|
return true;
|
|
6661
8203
|
}
|
|
6662
8204
|
}
|
|
6663
|
-
if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${
|
|
8205
|
+
if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path15}/items`, nextActivePaths)) {
|
|
6664
8206
|
return true;
|
|
6665
8207
|
}
|
|
6666
8208
|
if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null && hasSelfReferencingRef(
|
|
6667
8209
|
schema.additionalProperties,
|
|
6668
8210
|
root,
|
|
6669
|
-
`${
|
|
8211
|
+
`${path15}/additionalProperties`,
|
|
6670
8212
|
nextActivePaths
|
|
6671
8213
|
)) {
|
|
6672
8214
|
return true;
|
|
@@ -6675,7 +8217,7 @@ function hasSelfReferencingRef(schema, root, path12 = "#", activePaths = /* @__P
|
|
|
6675
8217
|
if (hasSelfReferencingRef(
|
|
6676
8218
|
childSchema,
|
|
6677
8219
|
root,
|
|
6678
|
-
`${
|
|
8220
|
+
`${path15}/properties/${escapeJsonPointerSegment(key2)}`,
|
|
6679
8221
|
nextActivePaths
|
|
6680
8222
|
)) {
|
|
6681
8223
|
return true;
|
|
@@ -6685,19 +8227,19 @@ function hasSelfReferencingRef(schema, root, path12 = "#", activePaths = /* @__P
|
|
|
6685
8227
|
if (hasSelfReferencingRef(
|
|
6686
8228
|
childSchema,
|
|
6687
8229
|
root,
|
|
6688
|
-
`${
|
|
8230
|
+
`${path15}/$defs/${escapeJsonPointerSegment(key2)}`,
|
|
6689
8231
|
nextActivePaths
|
|
6690
8232
|
)) {
|
|
6691
8233
|
return true;
|
|
6692
8234
|
}
|
|
6693
8235
|
}
|
|
6694
8236
|
for (const [index, childSchema] of (schema.oneOf ?? []).entries()) {
|
|
6695
|
-
if (hasSelfReferencingRef(childSchema, root, `${
|
|
8237
|
+
if (hasSelfReferencingRef(childSchema, root, `${path15}/oneOf/${index}`, nextActivePaths)) {
|
|
6696
8238
|
return true;
|
|
6697
8239
|
}
|
|
6698
8240
|
}
|
|
6699
8241
|
for (const [index, childSchema] of (schema.anyOf ?? []).entries()) {
|
|
6700
|
-
if (hasSelfReferencingRef(childSchema, root, `${
|
|
8242
|
+
if (hasSelfReferencingRef(childSchema, root, `${path15}/anyOf/${index}`, nextActivePaths)) {
|
|
6701
8243
|
return true;
|
|
6702
8244
|
}
|
|
6703
8245
|
}
|
|
@@ -6713,14 +8255,14 @@ function getLocalRefPath(ref) {
|
|
|
6713
8255
|
return ref.startsWith("#/") ? ref : void 0;
|
|
6714
8256
|
}
|
|
6715
8257
|
function resolveLocalRef(root, ref) {
|
|
6716
|
-
const
|
|
6717
|
-
if (
|
|
8258
|
+
const path15 = getLocalRefPath(ref);
|
|
8259
|
+
if (path15 === void 0) {
|
|
6718
8260
|
return void 0;
|
|
6719
8261
|
}
|
|
6720
|
-
if (
|
|
8262
|
+
if (path15 === "#") {
|
|
6721
8263
|
return root;
|
|
6722
8264
|
}
|
|
6723
|
-
const segments =
|
|
8265
|
+
const segments = path15.slice(2).split("/").map(unescapeJsonPointerSegment);
|
|
6724
8266
|
let current = root;
|
|
6725
8267
|
for (const segment of segments) {
|
|
6726
8268
|
if (Array.isArray(current)) {
|
|
@@ -6958,7 +8500,7 @@ async function ensureConnected(connection) {
|
|
|
6958
8500
|
}
|
|
6959
8501
|
async function readCache(cachePath) {
|
|
6960
8502
|
try {
|
|
6961
|
-
const raw = await
|
|
8503
|
+
const raw = await readFile4(cachePath, "utf8");
|
|
6962
8504
|
const parsed = JSON.parse(raw);
|
|
6963
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") {
|
|
6964
8506
|
return void 0;
|
|
@@ -6979,7 +8521,7 @@ async function readCache(cachePath) {
|
|
|
6979
8521
|
}
|
|
6980
8522
|
}
|
|
6981
8523
|
async function writeCache(cachePath, cache) {
|
|
6982
|
-
const directory =
|
|
8524
|
+
const directory = path8.dirname(cachePath);
|
|
6983
8525
|
const tempPath = `${cachePath}.tmp`;
|
|
6984
8526
|
await mkdir(directory, { recursive: true });
|
|
6985
8527
|
await writeFile2(tempPath, `${JSON.stringify(cache, null, 2)}
|
|
@@ -7065,7 +8607,7 @@ function isRefreshRequested(name, refresh) {
|
|
|
7065
8607
|
}
|
|
7066
8608
|
return refresh?.has(name) === true;
|
|
7067
8609
|
}
|
|
7068
|
-
async function resolveSingleProxy(group) {
|
|
8610
|
+
async function resolveSingleProxy(group, options) {
|
|
7069
8611
|
const internal = getInternalGroupConfig2(group);
|
|
7070
8612
|
const config = internal.mcp;
|
|
7071
8613
|
if (config === void 0) {
|
|
@@ -7073,7 +8615,7 @@ async function resolveSingleProxy(group) {
|
|
|
7073
8615
|
}
|
|
7074
8616
|
const name = group.name;
|
|
7075
8617
|
try {
|
|
7076
|
-
const cachePath = resolveCachePath(name);
|
|
8618
|
+
const cachePath = resolveCachePath(name, options.projectRoot);
|
|
7077
8619
|
const refresh = parseRefreshEnv(process.env.TOOLCRAFT_MCP_REFRESH);
|
|
7078
8620
|
let cache;
|
|
7079
8621
|
if (isRefreshRequested(name, refresh)) {
|
|
@@ -7122,14 +8664,14 @@ function collectProxyGroups(root) {
|
|
|
7122
8664
|
}
|
|
7123
8665
|
function resolveCachePath(name, projectRoot) {
|
|
7124
8666
|
if (projectRoot !== void 0) {
|
|
7125
|
-
return
|
|
8667
|
+
return path8.join(projectRoot, ".toolcraft", "mcp", `${name}.json`);
|
|
7126
8668
|
}
|
|
7127
8669
|
let current = process.cwd();
|
|
7128
8670
|
while (true) {
|
|
7129
|
-
if (
|
|
7130
|
-
return
|
|
8671
|
+
if (existsSync2(path8.join(current, "package.json"))) {
|
|
8672
|
+
return path8.join(current, ".toolcraft", "mcp", `${name}.json`);
|
|
7131
8673
|
}
|
|
7132
|
-
const parent =
|
|
8674
|
+
const parent = path8.dirname(current);
|
|
7133
8675
|
if (parent === current) {
|
|
7134
8676
|
throw new Error(
|
|
7135
8677
|
`Could not find package.json above "${process.cwd()}" while resolving MCP cache path.`
|
|
@@ -7167,9 +8709,9 @@ async function dialUpstream(name, config) {
|
|
|
7167
8709
|
await client.connect(transport);
|
|
7168
8710
|
return client;
|
|
7169
8711
|
}
|
|
7170
|
-
async function resolveMcpProxies(root) {
|
|
8712
|
+
async function resolveMcpProxies(root, options = {}) {
|
|
7171
8713
|
const groups = collectProxyGroups(root);
|
|
7172
|
-
await Promise.all(groups.map((group) => resolveSingleProxy(group)));
|
|
8714
|
+
await Promise.all(groups.map((group) => resolveSingleProxy(group, options)));
|
|
7173
8715
|
}
|
|
7174
8716
|
|
|
7175
8717
|
// ../toolcraft/src/number-schema.ts
|
|
@@ -7181,9 +8723,49 @@ function getExpectedNumberDescription(schema) {
|
|
|
7181
8723
|
}
|
|
7182
8724
|
|
|
7183
8725
|
// ../toolcraft/src/renderer.ts
|
|
8726
|
+
import YAML from "yaml";
|
|
7184
8727
|
function isObject(value) {
|
|
7185
8728
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7186
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
|
+
}
|
|
7187
8769
|
function isArrayOfObjects(value) {
|
|
7188
8770
|
return Array.isArray(value) && value.every((entry) => isObject(entry));
|
|
7189
8771
|
}
|
|
@@ -7207,30 +8789,6 @@ function stringifyJson(value, spaces) {
|
|
|
7207
8789
|
return String(value);
|
|
7208
8790
|
}
|
|
7209
8791
|
}
|
|
7210
|
-
function renderObjectTable(result, primitives) {
|
|
7211
|
-
const rows = Object.entries(result).map(([key2, value]) => ({
|
|
7212
|
-
key: key2,
|
|
7213
|
-
value: stringifyValue2(value)
|
|
7214
|
-
}));
|
|
7215
|
-
return primitives.renderTable({
|
|
7216
|
-
theme: primitives.getTheme(),
|
|
7217
|
-
columns: [
|
|
7218
|
-
{
|
|
7219
|
-
name: "key",
|
|
7220
|
-
title: "Key",
|
|
7221
|
-
alignment: "left",
|
|
7222
|
-
maxLen: Math.max("Key".length, ...rows.map((row) => row.key.length))
|
|
7223
|
-
},
|
|
7224
|
-
{
|
|
7225
|
-
name: "value",
|
|
7226
|
-
title: "Value",
|
|
7227
|
-
alignment: "left",
|
|
7228
|
-
maxLen: Math.max("Value".length, ...rows.map((row) => row.value.length))
|
|
7229
|
-
}
|
|
7230
|
-
],
|
|
7231
|
-
rows
|
|
7232
|
-
});
|
|
7233
|
-
}
|
|
7234
8792
|
function renderObjectMarkdown(result) {
|
|
7235
8793
|
return Object.entries(result).map(([key2, value]) => `- ${key2}: ${stringifyValue2(value)}`).join("\n");
|
|
7236
8794
|
}
|
|
@@ -7243,29 +8801,6 @@ function getColumnNames(rows) {
|
|
|
7243
8801
|
}
|
|
7244
8802
|
return [...names];
|
|
7245
8803
|
}
|
|
7246
|
-
function renderArrayTable(result, primitives) {
|
|
7247
|
-
if (result.length === 0) {
|
|
7248
|
-
return "[]";
|
|
7249
|
-
}
|
|
7250
|
-
const columnNames = getColumnNames(result);
|
|
7251
|
-
return primitives.renderTable({
|
|
7252
|
-
theme: primitives.getTheme(),
|
|
7253
|
-
columns: columnNames.map((name) => ({
|
|
7254
|
-
name,
|
|
7255
|
-
title: name,
|
|
7256
|
-
alignment: "left",
|
|
7257
|
-
maxLen: Math.max(
|
|
7258
|
-
name.length,
|
|
7259
|
-
...result.map((row) => name in row ? stringifyValue2(row[name]).length : 0)
|
|
7260
|
-
)
|
|
7261
|
-
})),
|
|
7262
|
-
rows: result.map(
|
|
7263
|
-
(row) => Object.fromEntries(
|
|
7264
|
-
columnNames.map((name) => [name, name in row ? stringifyValue2(row[name]) : ""])
|
|
7265
|
-
)
|
|
7266
|
-
)
|
|
7267
|
-
});
|
|
7268
|
-
}
|
|
7269
8804
|
function renderArrayMarkdown(result) {
|
|
7270
8805
|
if (result.length === 0) {
|
|
7271
8806
|
return "[]";
|
|
@@ -7278,7 +8813,7 @@ function renderArrayMarkdown(result) {
|
|
|
7278
8813
|
);
|
|
7279
8814
|
return [header, separator, ...rows].join("\n");
|
|
7280
8815
|
}
|
|
7281
|
-
function autoRender(result, output,
|
|
8816
|
+
function autoRender(result, output, _primitives) {
|
|
7282
8817
|
if (result === null || result === void 0) {
|
|
7283
8818
|
if (output === "json") {
|
|
7284
8819
|
return stringifyJson({ ok: true }, 2);
|
|
@@ -7291,14 +8826,16 @@ function autoRender(result, output, primitives) {
|
|
|
7291
8826
|
}
|
|
7292
8827
|
return result;
|
|
7293
8828
|
}
|
|
8829
|
+
if (output === "rich" && Array.isArray(result) && result.every((value) => typeof value === "string")) {
|
|
8830
|
+
return result.join("\n");
|
|
8831
|
+
}
|
|
7294
8832
|
if (isObject(result)) {
|
|
7295
|
-
if (output === "rich") {
|
|
7296
|
-
return renderObjectTable(result, primitives);
|
|
7297
|
-
}
|
|
7298
8833
|
if (output === "md") {
|
|
7299
8834
|
return renderObjectMarkdown(result);
|
|
7300
8835
|
}
|
|
7301
|
-
|
|
8836
|
+
if (output === "json") {
|
|
8837
|
+
return stringifyJson(result, 2);
|
|
8838
|
+
}
|
|
7302
8839
|
}
|
|
7303
8840
|
if (isArrayOfObjects(result)) {
|
|
7304
8841
|
if (output === "md") {
|
|
@@ -7307,20 +8844,36 @@ function autoRender(result, output, primitives) {
|
|
|
7307
8844
|
if (output === "json") {
|
|
7308
8845
|
return stringifyJson(result, 2);
|
|
7309
8846
|
}
|
|
7310
|
-
|
|
8847
|
+
}
|
|
8848
|
+
if (output === "rich") {
|
|
8849
|
+
return YAML.stringify(result);
|
|
7311
8850
|
}
|
|
7312
8851
|
return stringifyJson(result, 2);
|
|
7313
8852
|
}
|
|
7314
|
-
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
|
+
}
|
|
7315
8858
|
process.stdout.write(chunk);
|
|
7316
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
|
+
}
|
|
7317
8870
|
if (output === "json" && command.render?.json) {
|
|
7318
8871
|
const payload2 = command.render.json(result, primitives);
|
|
7319
8872
|
if (payload2 !== void 0) {
|
|
7320
8873
|
write2(`${stringifyJson(payload2, 2)}
|
|
7321
8874
|
`);
|
|
7322
8875
|
}
|
|
7323
|
-
return;
|
|
8876
|
+
return { mcpError: false };
|
|
7324
8877
|
}
|
|
7325
8878
|
if (output === "md" && command.render?.markdown) {
|
|
7326
8879
|
const payload2 = command.render.markdown(result, primitives);
|
|
@@ -7328,17 +8881,18 @@ function renderResult(command, result, output, primitives, write2 = (chunk) => {
|
|
|
7328
8881
|
write2(`${payload2}
|
|
7329
8882
|
`);
|
|
7330
8883
|
}
|
|
7331
|
-
return;
|
|
8884
|
+
return { mcpError: false };
|
|
7332
8885
|
}
|
|
7333
8886
|
if (output === "rich" && command.render?.rich) {
|
|
7334
8887
|
command.render.rich(result, primitives);
|
|
7335
|
-
return;
|
|
8888
|
+
return { mcpError: false };
|
|
7336
8889
|
}
|
|
7337
8890
|
const payload = autoRender(result, output, primitives);
|
|
7338
8891
|
if (payload.length > 0) {
|
|
7339
8892
|
write2(`${payload}
|
|
7340
8893
|
`);
|
|
7341
8894
|
}
|
|
8895
|
+
return { mcpError: false };
|
|
7342
8896
|
}
|
|
7343
8897
|
|
|
7344
8898
|
// ../toolcraft/src/cli.ts
|
|
@@ -7349,7 +8903,7 @@ function inferProgramName(argv) {
|
|
|
7349
8903
|
if (typeof entrypoint !== "string" || entrypoint.length === 0) {
|
|
7350
8904
|
return "toolcraft";
|
|
7351
8905
|
}
|
|
7352
|
-
const parsed =
|
|
8906
|
+
const parsed = path9.parse(entrypoint);
|
|
7353
8907
|
return parsed.name.length > 0 ? parsed.name : "toolcraft";
|
|
7354
8908
|
}
|
|
7355
8909
|
function normalizeRoots(roots, argv) {
|
|
@@ -7371,7 +8925,7 @@ function unwrapOptional(schema) {
|
|
|
7371
8925
|
}
|
|
7372
8926
|
return schema;
|
|
7373
8927
|
}
|
|
7374
|
-
function
|
|
8928
|
+
function splitWords3(value) {
|
|
7375
8929
|
const words = [];
|
|
7376
8930
|
let current = "";
|
|
7377
8931
|
for (let index = 0; index < value.length; index += 1) {
|
|
@@ -7405,13 +8959,13 @@ function splitWords(value) {
|
|
|
7405
8959
|
}
|
|
7406
8960
|
function formatSegment(segment, casing) {
|
|
7407
8961
|
const separator = casing === "snake" ? "_" : "-";
|
|
7408
|
-
return
|
|
8962
|
+
return splitWords3(segment).join(separator);
|
|
7409
8963
|
}
|
|
7410
|
-
function toOptionFlag(
|
|
7411
|
-
return `--${
|
|
8964
|
+
function toOptionFlag(path15, casing) {
|
|
8965
|
+
return `--${path15.map((segment) => formatSegment(segment, casing)).join(".")}`;
|
|
7412
8966
|
}
|
|
7413
|
-
function toOptionAttribute(
|
|
7414
|
-
return
|
|
8967
|
+
function toOptionAttribute(path15, casing) {
|
|
8968
|
+
return path15.map((segment) => {
|
|
7415
8969
|
const formatted = formatSegment(segment, casing);
|
|
7416
8970
|
if (casing === "snake") {
|
|
7417
8971
|
return formatted;
|
|
@@ -7422,23 +8976,23 @@ function toOptionAttribute(path12, casing) {
|
|
|
7422
8976
|
).join("");
|
|
7423
8977
|
}).join(".");
|
|
7424
8978
|
}
|
|
7425
|
-
function toDisplayPath(
|
|
7426
|
-
return
|
|
8979
|
+
function toDisplayPath(path15) {
|
|
8980
|
+
return path15.join(".");
|
|
7427
8981
|
}
|
|
7428
|
-
function toUnionKindControlPath(
|
|
7429
|
-
if (
|
|
8982
|
+
function toUnionKindControlPath(path15) {
|
|
8983
|
+
if (path15.length === 0) {
|
|
7430
8984
|
return ["kind"];
|
|
7431
8985
|
}
|
|
7432
|
-
const head =
|
|
7433
|
-
const tail =
|
|
8986
|
+
const head = path15.slice(0, -1);
|
|
8987
|
+
const tail = path15[path15.length - 1] ?? "";
|
|
7434
8988
|
return [...head, `${tail}Kind`];
|
|
7435
8989
|
}
|
|
7436
|
-
function toUnionKindDisplayPath(
|
|
7437
|
-
if (
|
|
8990
|
+
function toUnionKindDisplayPath(path15) {
|
|
8991
|
+
if (path15.length === 0) {
|
|
7438
8992
|
return "kind";
|
|
7439
8993
|
}
|
|
7440
|
-
const head =
|
|
7441
|
-
const tail =
|
|
8994
|
+
const head = path15.slice(0, -1);
|
|
8995
|
+
const tail = path15[path15.length - 1] ?? "";
|
|
7442
8996
|
return [...head, `${tail}-kind`].join(".");
|
|
7443
8997
|
}
|
|
7444
8998
|
function createSyntheticEnumSchema(values) {
|
|
@@ -7454,19 +9008,26 @@ function getRequiredBranchFingerprint(branch, casing) {
|
|
|
7454
9008
|
const requiredKeys = Object.entries(branch.shape).filter(([, schema]) => schema.kind !== "optional").map(([key2]) => formatSegment(key2, casing)).sort();
|
|
7455
9009
|
return requiredKeys.join("+");
|
|
7456
9010
|
}
|
|
7457
|
-
function collectFields(schema, casing,
|
|
9011
|
+
function collectFields(schema, casing, globalLongOptionFlags, path15 = [], inheritedOptional = false, variantContext) {
|
|
7458
9012
|
const collected = {
|
|
7459
9013
|
dynamicFields: [],
|
|
7460
9014
|
fields: [],
|
|
7461
9015
|
variants: []
|
|
7462
9016
|
};
|
|
7463
9017
|
for (const [key2, rawChildSchema] of Object.entries(schema.shape)) {
|
|
7464
|
-
const nextPath = [...
|
|
9018
|
+
const nextPath = [...path15, key2];
|
|
7465
9019
|
const runtimeOptional = inheritedOptional || rawChildSchema.kind === "optional";
|
|
7466
9020
|
const childSchema = unwrapOptional(rawChildSchema);
|
|
7467
9021
|
const requiredWhenActive = rawChildSchema.kind !== "optional" && childSchema.default === void 0;
|
|
7468
9022
|
if (childSchema.kind === "object") {
|
|
7469
|
-
const nested = collectFields(
|
|
9023
|
+
const nested = collectFields(
|
|
9024
|
+
childSchema,
|
|
9025
|
+
casing,
|
|
9026
|
+
globalLongOptionFlags,
|
|
9027
|
+
nextPath,
|
|
9028
|
+
runtimeOptional,
|
|
9029
|
+
variantContext
|
|
9030
|
+
);
|
|
7470
9031
|
collected.dynamicFields.push(...nested.dynamicFields);
|
|
7471
9032
|
collected.fields.push(...nested.fields);
|
|
7472
9033
|
collected.variants.push(...nested.variants);
|
|
@@ -7480,7 +9041,11 @@ function collectFields(schema, casing, path12 = [], inheritedOptional = false, v
|
|
|
7480
9041
|
path: [...nextPath, childSchema.discriminator],
|
|
7481
9042
|
displayPath: toDisplayPath([...nextPath, childSchema.discriminator]),
|
|
7482
9043
|
optionAttribute: toOptionAttribute([...nextPath, childSchema.discriminator], casing),
|
|
7483
|
-
commanderOptionAttribute: toCommanderOptionAttribute(
|
|
9044
|
+
commanderOptionAttribute: toCommanderOptionAttribute(
|
|
9045
|
+
[...nextPath, childSchema.discriminator],
|
|
9046
|
+
casing,
|
|
9047
|
+
globalLongOptionFlags
|
|
9048
|
+
),
|
|
7484
9049
|
optionFlag: toOptionFlag([...nextPath, childSchema.discriminator], casing),
|
|
7485
9050
|
shortFlag: void 0,
|
|
7486
9051
|
schema: createSyntheticEnumSchema(branchIds),
|
|
@@ -7493,7 +9058,7 @@ function collectFields(schema, casing, path12 = [], inheritedOptional = false, v
|
|
|
7493
9058
|
collected.fields.push(controlField);
|
|
7494
9059
|
const branches = [];
|
|
7495
9060
|
for (const [branchId, branchSchema] of Object.entries(childSchema.branches)) {
|
|
7496
|
-
const branch = collectFields(branchSchema, casing, nextPath, true, {
|
|
9061
|
+
const branch = collectFields(branchSchema, casing, globalLongOptionFlags, nextPath, true, {
|
|
7497
9062
|
id: variantId,
|
|
7498
9063
|
branchId
|
|
7499
9064
|
});
|
|
@@ -7521,13 +9086,19 @@ function collectFields(schema, casing, path12 = [], inheritedOptional = false, v
|
|
|
7521
9086
|
const variantId = `${toDisplayPath(nextPath)}:union`;
|
|
7522
9087
|
const controlPath = toUnionKindControlPath(nextPath);
|
|
7523
9088
|
const controlDisplayPath = toUnionKindDisplayPath(nextPath);
|
|
7524
|
-
const branchIds = childSchema.branches.map(
|
|
9089
|
+
const branchIds = childSchema.branches.map(
|
|
9090
|
+
(branch) => getRequiredBranchFingerprint(branch, casing)
|
|
9091
|
+
);
|
|
7525
9092
|
const controlField = {
|
|
7526
9093
|
id: controlDisplayPath,
|
|
7527
9094
|
path: controlPath,
|
|
7528
9095
|
displayPath: controlDisplayPath,
|
|
7529
9096
|
optionAttribute: toOptionAttribute(controlPath, casing),
|
|
7530
|
-
commanderOptionAttribute: toCommanderOptionAttribute(
|
|
9097
|
+
commanderOptionAttribute: toCommanderOptionAttribute(
|
|
9098
|
+
controlPath,
|
|
9099
|
+
casing,
|
|
9100
|
+
globalLongOptionFlags
|
|
9101
|
+
),
|
|
7531
9102
|
optionFlag: toOptionFlag(controlPath, casing),
|
|
7532
9103
|
shortFlag: void 0,
|
|
7533
9104
|
schema: createSyntheticEnumSchema(branchIds),
|
|
@@ -7542,7 +9113,7 @@ function collectFields(schema, casing, path12 = [], inheritedOptional = false, v
|
|
|
7542
9113
|
const branches = [];
|
|
7543
9114
|
childSchema.branches.forEach((branchSchema, index) => {
|
|
7544
9115
|
const branchId = branchIds[index] ?? "";
|
|
7545
|
-
const branch = collectFields(branchSchema, casing, nextPath, true, {
|
|
9116
|
+
const branch = collectFields(branchSchema, casing, globalLongOptionFlags, nextPath, true, {
|
|
7546
9117
|
id: variantId,
|
|
7547
9118
|
branchId
|
|
7548
9119
|
});
|
|
@@ -7609,7 +9180,7 @@ function collectFields(schema, casing, path12 = [], inheritedOptional = false, v
|
|
|
7609
9180
|
path: nextPath,
|
|
7610
9181
|
displayPath: toDisplayPath(nextPath),
|
|
7611
9182
|
optionAttribute: toOptionAttribute(nextPath, casing),
|
|
7612
|
-
commanderOptionAttribute: toCommanderOptionAttribute(nextPath, casing),
|
|
9183
|
+
commanderOptionAttribute: toCommanderOptionAttribute(nextPath, casing, globalLongOptionFlags),
|
|
7613
9184
|
optionFlag: toOptionFlag(nextPath, casing),
|
|
7614
9185
|
shortFlag: childSchema.short,
|
|
7615
9186
|
schema: childSchema,
|
|
@@ -7624,10 +9195,10 @@ function collectFields(schema, casing, path12 = [], inheritedOptional = false, v
|
|
|
7624
9195
|
}
|
|
7625
9196
|
return collected;
|
|
7626
9197
|
}
|
|
7627
|
-
function toCommanderOptionAttribute(
|
|
7628
|
-
const optionAttribute = toOptionAttribute(
|
|
7629
|
-
const optionFlag = toOptionFlag(
|
|
7630
|
-
if (!
|
|
9198
|
+
function toCommanderOptionAttribute(path15, casing, globalLongOptionFlags) {
|
|
9199
|
+
const optionAttribute = toOptionAttribute(path15, casing);
|
|
9200
|
+
const optionFlag = toOptionFlag(path15, casing);
|
|
9201
|
+
if (!globalLongOptionFlags.has(optionFlag)) {
|
|
7631
9202
|
return optionAttribute;
|
|
7632
9203
|
}
|
|
7633
9204
|
return `param_${optionAttribute}`;
|
|
@@ -7657,8 +9228,8 @@ function assignPositionals(fields, positional) {
|
|
|
7657
9228
|
});
|
|
7658
9229
|
return fields;
|
|
7659
9230
|
}
|
|
7660
|
-
function formatOptionFlags(field) {
|
|
7661
|
-
const collidesWithGlobalFlag =
|
|
9231
|
+
function formatOptionFlags(field, globalLongOptionFlags) {
|
|
9232
|
+
const collidesWithGlobalFlag = globalLongOptionFlags.has(field.optionFlag);
|
|
7662
9233
|
if (collidesWithGlobalFlag) {
|
|
7663
9234
|
if (field.shortFlag === void 0) {
|
|
7664
9235
|
throw new UserError(
|
|
@@ -7774,11 +9345,13 @@ function parseArrayValue(value, schema, label) {
|
|
|
7774
9345
|
if (itemSchema.kind === "array" || itemSchema.kind === "object") {
|
|
7775
9346
|
throw new UserError(`Array parameter "${label}" must use scalar items.`);
|
|
7776
9347
|
}
|
|
7777
|
-
return splitArrayInput(value).map(
|
|
9348
|
+
return splitArrayInput(value).map(
|
|
9349
|
+
(item) => parseScalarValue(item, itemSchema, label)
|
|
9350
|
+
);
|
|
7778
9351
|
}
|
|
7779
|
-
function createOption(field) {
|
|
7780
|
-
const flags = formatOptionFlags(field);
|
|
7781
|
-
const collidesWithGlobalFlag =
|
|
9352
|
+
function createOption(field, globalLongOptionFlags) {
|
|
9353
|
+
const flags = formatOptionFlags(field, globalLongOptionFlags);
|
|
9354
|
+
const collidesWithGlobalFlag = globalLongOptionFlags.has(field.optionFlag);
|
|
7782
9355
|
const commanderValue = (value) => value === null ? NULL_OPTION_VALUE : value;
|
|
7783
9356
|
if (field.schema.kind === "boolean") {
|
|
7784
9357
|
if (collidesWithGlobalFlag) {
|
|
@@ -7798,7 +9371,11 @@ function createOption(field) {
|
|
|
7798
9371
|
return [
|
|
7799
9372
|
createCommanderOption(`${flags} <value...>`, field.description, field).argParser(
|
|
7800
9373
|
(value, previous = []) => {
|
|
7801
|
-
const parsed = parseArrayValue(
|
|
9374
|
+
const parsed = parseArrayValue(
|
|
9375
|
+
value,
|
|
9376
|
+
field.schema,
|
|
9377
|
+
field.displayPath
|
|
9378
|
+
);
|
|
7802
9379
|
if (parsed === null) {
|
|
7803
9380
|
return NULL_OPTION_VALUE;
|
|
7804
9381
|
}
|
|
@@ -7823,7 +9400,12 @@ function createOption(field) {
|
|
|
7823
9400
|
);
|
|
7824
9401
|
return [option];
|
|
7825
9402
|
}
|
|
7826
|
-
var
|
|
9403
|
+
var ALWAYS_GLOBAL_LONG_OPTION_FLAGS = ["--yes", "--output", "--verbose"];
|
|
9404
|
+
function getGlobalLongOptionFlags(presetsEnabled) {
|
|
9405
|
+
return new Set(
|
|
9406
|
+
presetsEnabled ? ["--preset", ...ALWAYS_GLOBAL_LONG_OPTION_FLAGS] : ALWAYS_GLOBAL_LONG_OPTION_FLAGS
|
|
9407
|
+
);
|
|
9408
|
+
}
|
|
7827
9409
|
function createCommanderOption(flags, description, field) {
|
|
7828
9410
|
const option = new Option(flags, description);
|
|
7829
9411
|
if (field.commanderOptionAttribute !== field.optionAttribute) {
|
|
@@ -7883,11 +9465,7 @@ function resolveHelpTarget(root, argv, scope, rootDisplayName) {
|
|
|
7883
9465
|
if (current.kind !== "group") {
|
|
7884
9466
|
break;
|
|
7885
9467
|
}
|
|
7886
|
-
const child = findVisibleChild(
|
|
7887
|
-
current,
|
|
7888
|
-
token,
|
|
7889
|
-
scope
|
|
7890
|
-
);
|
|
9468
|
+
const child = findVisibleChild(current, token, scope);
|
|
7891
9469
|
if (child === void 0) {
|
|
7892
9470
|
break;
|
|
7893
9471
|
}
|
|
@@ -7899,32 +9477,23 @@ function resolveHelpTarget(root, argv, scope, rootDisplayName) {
|
|
|
7899
9477
|
node: current
|
|
7900
9478
|
};
|
|
7901
9479
|
}
|
|
7902
|
-
function
|
|
7903
|
-
switch (schema.kind) {
|
|
7904
|
-
case "string":
|
|
7905
|
-
return "string";
|
|
7906
|
-
case "number":
|
|
7907
|
-
return "number";
|
|
7908
|
-
case "boolean":
|
|
7909
|
-
return "boolean";
|
|
7910
|
-
case "enum":
|
|
7911
|
-
return "value";
|
|
7912
|
-
case "array":
|
|
7913
|
-
return `${describeSchemaType(unwrapOptional(schema.item))}...`;
|
|
7914
|
-
case "json":
|
|
7915
|
-
return "json";
|
|
7916
|
-
default:
|
|
7917
|
-
throw new UserError("Unsupported CLI schema kind.");
|
|
7918
|
-
}
|
|
7919
|
-
}
|
|
7920
|
-
function formatHelpFieldFlags(field) {
|
|
9480
|
+
function formatHelpFieldFlags(field, globalLongOptionFlags) {
|
|
7921
9481
|
if (field.positionalIndex !== void 0) {
|
|
7922
9482
|
return formatPositionalToken(field);
|
|
7923
9483
|
}
|
|
7924
9484
|
if (field.schema.kind === "boolean") {
|
|
7925
|
-
|
|
9485
|
+
if (field.defaultValue === true) {
|
|
9486
|
+
return `--no-${field.optionFlag.slice(2)}`;
|
|
9487
|
+
}
|
|
9488
|
+
return formatOptionFlags(field, globalLongOptionFlags);
|
|
7926
9489
|
}
|
|
7927
|
-
return `${formatOptionFlags(field)} <${
|
|
9490
|
+
return `${formatOptionFlags(field, globalLongOptionFlags)} <${describeHelpValueToken(
|
|
9491
|
+
field.schema,
|
|
9492
|
+
{
|
|
9493
|
+
displayPath: field.displayPath,
|
|
9494
|
+
optionFlag: field.optionFlag
|
|
9495
|
+
}
|
|
9496
|
+
)}>`;
|
|
7928
9497
|
}
|
|
7929
9498
|
function appendHelpMetadata(description, metadata) {
|
|
7930
9499
|
if (metadata.length === 0) {
|
|
@@ -7946,6 +9515,87 @@ function formatHelpFieldDescription(field) {
|
|
|
7946
9515
|
}
|
|
7947
9516
|
return appendHelpMetadata(description, metadata);
|
|
7948
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
|
+
}
|
|
7949
9599
|
function describeDynamicFieldType(field) {
|
|
7950
9600
|
if (field.schema.kind === "record") {
|
|
7951
9601
|
const valueSchema = unwrapOptional(field.schema.value);
|
|
@@ -7953,12 +9603,18 @@ function describeDynamicFieldType(field) {
|
|
|
7953
9603
|
return "json";
|
|
7954
9604
|
}
|
|
7955
9605
|
if (valueSchema.kind === "array") {
|
|
7956
|
-
return
|
|
9606
|
+
return describeHelpValueToken(valueSchema, {
|
|
9607
|
+
displayPath: field.optionPathDisplay,
|
|
9608
|
+
optionFlag: field.optionFlag
|
|
9609
|
+
});
|
|
7957
9610
|
}
|
|
7958
9611
|
if (valueSchema.kind === "object") {
|
|
7959
9612
|
return "value";
|
|
7960
9613
|
}
|
|
7961
|
-
return
|
|
9614
|
+
return describeHelpValueToken(valueSchema, {
|
|
9615
|
+
displayPath: field.optionPathDisplay,
|
|
9616
|
+
optionFlag: field.optionFlag
|
|
9617
|
+
});
|
|
7962
9618
|
}
|
|
7963
9619
|
return "value";
|
|
7964
9620
|
}
|
|
@@ -7980,7 +9636,9 @@ function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefi
|
|
|
7980
9636
|
const displayPath = `${displayPrefix}.${key2}`;
|
|
7981
9637
|
const description = childSchema.description ?? displayPath;
|
|
7982
9638
|
if (childSchema.kind === "object") {
|
|
7983
|
-
rows.push(
|
|
9639
|
+
rows.push(
|
|
9640
|
+
...collectDynamicObjectHelpRows(childSchema, casing, optionFlag, displayPath, metadata)
|
|
9641
|
+
);
|
|
7984
9642
|
continue;
|
|
7985
9643
|
}
|
|
7986
9644
|
if (childSchema.kind === "record") {
|
|
@@ -8017,7 +9675,10 @@ function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefi
|
|
|
8017
9675
|
continue;
|
|
8018
9676
|
}
|
|
8019
9677
|
rows.push({
|
|
8020
|
-
flags: childSchema.kind === "boolean" ?
|
|
9678
|
+
flags: childSchema.kind === "boolean" ? childSchema.default === true ? `--no-${optionFlag.slice(2)}` : optionFlag : `${optionFlag} <${describeHelpValueToken(childSchema, {
|
|
9679
|
+
displayPath,
|
|
9680
|
+
optionFlag
|
|
9681
|
+
})}>`,
|
|
8021
9682
|
description: appendHelpMetadata(description, metadata)
|
|
8022
9683
|
});
|
|
8023
9684
|
}
|
|
@@ -8049,10 +9710,12 @@ function formatDynamicHelpFields(field, casing) {
|
|
|
8049
9710
|
);
|
|
8050
9711
|
}
|
|
8051
9712
|
}
|
|
8052
|
-
return [
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
9713
|
+
return [
|
|
9714
|
+
{
|
|
9715
|
+
flags: `${field.optionFlag} <${describeDynamicFieldType(field)}>`,
|
|
9716
|
+
description: appendHelpMetadata(field.description ?? field.optionPathDisplay, metadata)
|
|
9717
|
+
}
|
|
9718
|
+
];
|
|
8056
9719
|
}
|
|
8057
9720
|
function formatSecretRows(secrets) {
|
|
8058
9721
|
return Object.values(secrets).map((secret) => ({
|
|
@@ -8066,32 +9729,58 @@ function formatSecretDescription(secret) {
|
|
|
8066
9729
|
}
|
|
8067
9730
|
return secret.optional === true ? "Optional secret" : "Required secret";
|
|
8068
9731
|
}
|
|
8069
|
-
function
|
|
9732
|
+
function wrapOptionalCommandParameterToken(token, optional) {
|
|
9733
|
+
return optional ? `[${token}]` : token;
|
|
9734
|
+
}
|
|
9735
|
+
function formatCommandDynamicParameterTokens(field, casing) {
|
|
9736
|
+
const optional = field.optional || field.hasDefault;
|
|
9737
|
+
return formatDynamicHelpFields(field, casing).map(
|
|
9738
|
+
(row) => wrapOptionalCommandParameterToken(row.flags, optional)
|
|
9739
|
+
);
|
|
9740
|
+
}
|
|
9741
|
+
function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
|
|
9742
|
+
const collected = collectFields(command.params, casing, globalLongOptionFlags);
|
|
9743
|
+
const fields = assignPositionals(collected.fields, command.positional);
|
|
9744
|
+
return fields.map(
|
|
9745
|
+
(field) => wrapOptionalCommandParameterToken(
|
|
9746
|
+
formatHelpFieldFlags(field, globalLongOptionFlags),
|
|
9747
|
+
field.positionalIndex === void 0 && (field.optional || field.hasDefault)
|
|
9748
|
+
)
|
|
9749
|
+
).concat(
|
|
9750
|
+
collected.dynamicFields.flatMap((field) => formatCommandDynamicParameterTokens(field, casing))
|
|
9751
|
+
);
|
|
9752
|
+
}
|
|
9753
|
+
function formatCommandRowName(node, casing, globalLongOptionFlags) {
|
|
9754
|
+
const baseName = node.aliases.length === 0 ? node.name : `${node.name} (${node.aliases.join(", ")})`;
|
|
9755
|
+
const parameterTokens = node.kind === "command" ? formatCommandParameterTokens(node, casing, globalLongOptionFlags) : [];
|
|
9756
|
+
const name = parameterTokens.length === 0 ? baseName : `${baseName} ${parameterTokens.join(" ")}`;
|
|
9757
|
+
return name;
|
|
9758
|
+
}
|
|
9759
|
+
function formatCommandRows(group, scope, casing, globalLongOptionFlags) {
|
|
8070
9760
|
return getVisibleChildren(group, scope).map((child) => ({
|
|
8071
|
-
name:
|
|
9761
|
+
name: formatCommandRowName(child, casing, globalLongOptionFlags),
|
|
8072
9762
|
description: child.description ?? ""
|
|
8073
9763
|
}));
|
|
8074
9764
|
}
|
|
8075
|
-
function formatGlobalOptionRows(
|
|
8076
|
-
const rows = [
|
|
8077
|
-
|
|
9765
|
+
function formatGlobalOptionRows(ctx) {
|
|
9766
|
+
const rows = [];
|
|
9767
|
+
if (ctx.presetsEnabled) {
|
|
9768
|
+
rows.push({
|
|
8078
9769
|
flags: "--preset <path>",
|
|
8079
9770
|
description: "Load parameter defaults from a JSON file"
|
|
8080
|
-
}
|
|
9771
|
+
});
|
|
9772
|
+
}
|
|
9773
|
+
rows.push(
|
|
8081
9774
|
{
|
|
8082
9775
|
flags: "--yes",
|
|
8083
9776
|
description: "Accept defaults, skip prompts"
|
|
8084
9777
|
},
|
|
8085
9778
|
{
|
|
8086
9779
|
flags: "--output <format>",
|
|
8087
|
-
description: "Output format
|
|
8088
|
-
},
|
|
8089
|
-
{
|
|
8090
|
-
flags: "-h, --help",
|
|
8091
|
-
description: "Show help"
|
|
9780
|
+
description: "Output format: rich, md, json."
|
|
8092
9781
|
}
|
|
8093
|
-
|
|
8094
|
-
if (showVersion) {
|
|
9782
|
+
);
|
|
9783
|
+
if (ctx.showVersion) {
|
|
8095
9784
|
rows.push({
|
|
8096
9785
|
flags: "--version",
|
|
8097
9786
|
description: "Show version"
|
|
@@ -8102,53 +9791,69 @@ function formatGlobalOptionRows(showVersion) {
|
|
|
8102
9791
|
function renderHelpSections(sections) {
|
|
8103
9792
|
return sections.filter((section) => section.length > 0).join("\n\n");
|
|
8104
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
|
+
}
|
|
8105
9800
|
function buildUsageLine(breadcrumb, rootUsageName, suffix) {
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
const
|
|
8110
|
-
return
|
|
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(" ");
|
|
8111
9806
|
}
|
|
8112
|
-
function renderGroupHelp(group, breadcrumb, scope,
|
|
9807
|
+
function renderGroupHelp(group, breadcrumb, scope, casing, globalOptions, rootUsageName) {
|
|
8113
9808
|
const sections = [];
|
|
8114
|
-
const
|
|
9809
|
+
const globalLongOptionFlags = getGlobalLongOptionFlags(globalOptions.presetsEnabled);
|
|
9810
|
+
const commandRows = formatCommandRows(group, scope, casing, globalLongOptionFlags);
|
|
8115
9811
|
if (commandRows.length > 0) {
|
|
8116
|
-
sections.push(`${text.
|
|
8117
|
-
${
|
|
9812
|
+
sections.push(`${text.sectionHeader("Commands")}
|
|
9813
|
+
${formatHelpCommandList(commandRows)}`);
|
|
8118
9814
|
}
|
|
8119
|
-
sections.push(
|
|
8120
|
-
|
|
9815
|
+
sections.push(
|
|
9816
|
+
`${text.sectionHeader("Options")}
|
|
9817
|
+
${formatHelpOptionList(formatGlobalOptionRows(globalOptions))}`
|
|
9818
|
+
);
|
|
8121
9819
|
return renderHelpDocument({
|
|
8122
9820
|
breadcrumb,
|
|
8123
|
-
|
|
9821
|
+
rootUsageName,
|
|
9822
|
+
usageLine: buildUsageLine(breadcrumb, rootUsageName, "[command] [options]"),
|
|
8124
9823
|
description: group.description,
|
|
8125
9824
|
requiresAuth: group.requires?.auth === true,
|
|
8126
9825
|
sections
|
|
8127
9826
|
});
|
|
8128
9827
|
}
|
|
8129
|
-
function renderLeafHelp(command, breadcrumb, casing, rootUsageName) {
|
|
9828
|
+
function renderLeafHelp(command, breadcrumb, casing, globalOptions, rootUsageName) {
|
|
8130
9829
|
const sections = [];
|
|
8131
|
-
const
|
|
9830
|
+
const globalLongOptionFlags = getGlobalLongOptionFlags(globalOptions.presetsEnabled);
|
|
9831
|
+
const collected = collectFields(command.params, casing, globalLongOptionFlags);
|
|
8132
9832
|
const fields = assignPositionals(collected.fields, command.positional);
|
|
8133
9833
|
const optionRows = fields.map((field) => ({
|
|
8134
|
-
flags: formatHelpFieldFlags(field),
|
|
9834
|
+
flags: formatHelpFieldFlags(field, globalLongOptionFlags),
|
|
8135
9835
|
description: formatHelpFieldDescription(field)
|
|
8136
9836
|
})).concat(collected.dynamicFields.flatMap((field) => formatDynamicHelpFields(field, casing)));
|
|
8137
9837
|
if (optionRows.length > 0) {
|
|
8138
|
-
sections.push(`${text.
|
|
8139
|
-
${
|
|
9838
|
+
sections.push(`${text.sectionHeader("Options")}
|
|
9839
|
+
${formatHelpOptionList(optionRows)}`);
|
|
8140
9840
|
}
|
|
8141
|
-
sections.push(
|
|
8142
|
-
|
|
9841
|
+
sections.push(
|
|
9842
|
+
`${text.sectionHeader("Options")}
|
|
9843
|
+
${formatHelpOptionList(formatGlobalOptionRows(globalOptions))}`
|
|
9844
|
+
);
|
|
8143
9845
|
const secretRows = formatSecretRows(command.secrets);
|
|
8144
9846
|
if (secretRows.length > 0) {
|
|
8145
|
-
sections.push(
|
|
8146
|
-
|
|
9847
|
+
sections.push(
|
|
9848
|
+
`${text.sectionHeader("Secrets (environment)")}
|
|
9849
|
+
${formatHelpOptionList(secretRows)}`
|
|
9850
|
+
);
|
|
8147
9851
|
}
|
|
8148
9852
|
const positionalFields = fields.filter((f) => f.positionalIndex !== void 0);
|
|
8149
9853
|
const usageSuffix = positionalFields.length > 0 ? `[options] ${positionalFields.map(formatPositionalToken).join(" ")}` : "[options]";
|
|
8150
9854
|
return renderHelpDocument({
|
|
8151
9855
|
breadcrumb,
|
|
9856
|
+
rootUsageName,
|
|
8152
9857
|
usageLine: buildUsageLine(breadcrumb, rootUsageName, usageSuffix),
|
|
8153
9858
|
description: command.description,
|
|
8154
9859
|
requiresAuth: command.requires?.auth === true,
|
|
@@ -8156,17 +9861,21 @@ ${formatOptionList(secretRows)}`);
|
|
|
8156
9861
|
});
|
|
8157
9862
|
}
|
|
8158
9863
|
function renderHelpDocument(input) {
|
|
8159
|
-
const
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
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)}`, "");
|
|
8166
9875
|
if (input.requiresAuth) {
|
|
8167
9876
|
lines.push("Requires: authentication");
|
|
8168
9877
|
}
|
|
8169
|
-
if (input.
|
|
9878
|
+
if (input.requiresAuth) {
|
|
8170
9879
|
lines.push("");
|
|
8171
9880
|
}
|
|
8172
9881
|
lines.push(renderHelpSections(input.sections));
|
|
@@ -8177,26 +9886,46 @@ async function renderGeneratedHelp(root, argv, options) {
|
|
|
8177
9886
|
const target = resolveHelpTarget(root, argv, "cli", options.rootDisplayName);
|
|
8178
9887
|
const output = resolveHelpOutput(argv);
|
|
8179
9888
|
const casing = options.casing ?? "kebab";
|
|
9889
|
+
const rootUsageName = options.rootUsageName ?? inferProgramName(argv);
|
|
8180
9890
|
await withOutputFormat2(output, async () => {
|
|
8181
|
-
const rendered = target.node.kind === "group" ? renderGroupHelp(
|
|
9891
|
+
const rendered = target.node.kind === "group" ? renderGroupHelp(
|
|
9892
|
+
target.node,
|
|
9893
|
+
target.breadcrumb,
|
|
9894
|
+
"cli",
|
|
9895
|
+
casing,
|
|
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
|
+
);
|
|
8182
9911
|
process.stdout.write(rendered);
|
|
8183
9912
|
});
|
|
8184
9913
|
}
|
|
8185
|
-
function createNodeCommand(node, casing, execute, pathSegments = []) {
|
|
9914
|
+
function createNodeCommand(node, casing, globalLongOptionFlags, execute, presetsEnabled, pathSegments = []) {
|
|
8186
9915
|
const nextPathSegments = [...pathSegments, node.name];
|
|
8187
9916
|
if (node.kind === "command") {
|
|
8188
9917
|
if (!node.scope.includes("cli")) {
|
|
8189
9918
|
return null;
|
|
8190
9919
|
}
|
|
8191
9920
|
const command = new CommanderCommand(node.name);
|
|
8192
|
-
const collected = collectFields(node.params, casing);
|
|
9921
|
+
const collected = collectFields(node.params, casing, globalLongOptionFlags);
|
|
8193
9922
|
const fields = assignPositionals(collected.fields, node.positional);
|
|
8194
9923
|
if (node.description !== void 0) {
|
|
8195
9924
|
command.description(node.description);
|
|
8196
9925
|
}
|
|
8197
9926
|
node.aliases.forEach((alias) => command.alias(alias));
|
|
8198
9927
|
command.addHelpCommand(false);
|
|
8199
|
-
addGlobalOptions(command);
|
|
9928
|
+
addGlobalOptions(command, presetsEnabled);
|
|
8200
9929
|
command.allowExcessArguments(true);
|
|
8201
9930
|
if (collected.dynamicFields.length > 0) {
|
|
8202
9931
|
command.allowUnknownOption(true);
|
|
@@ -8206,7 +9935,7 @@ function createNodeCommand(node, casing, execute, pathSegments = []) {
|
|
|
8206
9935
|
command.argument(formatPositionalToken(field));
|
|
8207
9936
|
continue;
|
|
8208
9937
|
}
|
|
8209
|
-
for (const option of createOption(field)) {
|
|
9938
|
+
for (const option of createOption(field, globalLongOptionFlags)) {
|
|
8210
9939
|
command.addOption(option);
|
|
8211
9940
|
}
|
|
8212
9941
|
}
|
|
@@ -8220,6 +9949,7 @@ function createNodeCommand(node, casing, execute, pathSegments = []) {
|
|
|
8220
9949
|
dynamicFields: collected.dynamicFields,
|
|
8221
9950
|
fields,
|
|
8222
9951
|
positionalValues,
|
|
9952
|
+
presetsEnabled,
|
|
8223
9953
|
rawArgv: actionCommand.args,
|
|
8224
9954
|
actionCommand,
|
|
8225
9955
|
variants: collected.variants
|
|
@@ -8230,35 +9960,49 @@ function createNodeCommand(node, casing, execute, pathSegments = []) {
|
|
|
8230
9960
|
if (!isNodeVisibleInScope(node, "cli")) {
|
|
8231
9961
|
return null;
|
|
8232
9962
|
}
|
|
8233
|
-
const visibleChildren = node.children.map(
|
|
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);
|
|
8234
9973
|
const group = new CommanderCommand(node.name);
|
|
8235
9974
|
if (node.description !== void 0) {
|
|
8236
9975
|
group.description(node.description);
|
|
8237
9976
|
}
|
|
8238
9977
|
node.aliases.forEach((alias) => group.alias(alias));
|
|
8239
9978
|
group.addHelpCommand(false);
|
|
8240
|
-
addGlobalOptions(group);
|
|
9979
|
+
addGlobalOptions(group, presetsEnabled);
|
|
8241
9980
|
for (const child of visibleChildren) {
|
|
8242
9981
|
const isDefaultChild = node.default !== void 0 && node.default.scope.includes("cli") && (child.name() === node.default.name || child.aliases().includes(node.default.name));
|
|
8243
9982
|
group.addCommand(child, isDefaultChild ? { isDefault: true } : void 0);
|
|
8244
9983
|
}
|
|
8245
9984
|
return group;
|
|
8246
9985
|
}
|
|
8247
|
-
function addGlobalOptions(command) {
|
|
8248
|
-
|
|
9986
|
+
function addGlobalOptions(command, presetsEnabled) {
|
|
9987
|
+
if (presetsEnabled) {
|
|
9988
|
+
command.option("--preset <path>", "Load parameter defaults from a JSON file.");
|
|
9989
|
+
}
|
|
9990
|
+
command.option("--yes", "Accept defaults and skip prompts.").option("--output <format>", "Output format.", (value) => {
|
|
8249
9991
|
if (value === "rich" || value === "md" || value === "json") {
|
|
8250
9992
|
return value;
|
|
8251
9993
|
}
|
|
8252
9994
|
if (value === "markdown") {
|
|
8253
9995
|
return "md";
|
|
8254
9996
|
}
|
|
8255
|
-
throw new InvalidArgumentError(
|
|
9997
|
+
throw new InvalidArgumentError(
|
|
9998
|
+
'Invalid value for "--output". Expected one of: rich, md, markdown, json.'
|
|
9999
|
+
);
|
|
8256
10000
|
}).option("--verbose", "Print stack traces for unexpected errors.");
|
|
8257
10001
|
}
|
|
8258
|
-
function setNestedValue(target,
|
|
10002
|
+
function setNestedValue(target, path15, value) {
|
|
8259
10003
|
let cursor = target;
|
|
8260
|
-
for (let index = 0; index <
|
|
8261
|
-
const segment =
|
|
10004
|
+
for (let index = 0; index < path15.length - 1; index += 1) {
|
|
10005
|
+
const segment = path15[index] ?? "";
|
|
8262
10006
|
const existing = cursor[segment];
|
|
8263
10007
|
if (typeof existing === "object" && existing !== null) {
|
|
8264
10008
|
cursor = existing;
|
|
@@ -8268,7 +10012,7 @@ function setNestedValue(target, path12, value) {
|
|
|
8268
10012
|
cursor[segment] = next;
|
|
8269
10013
|
cursor = next;
|
|
8270
10014
|
}
|
|
8271
|
-
const leaf =
|
|
10015
|
+
const leaf = path15[path15.length - 1];
|
|
8272
10016
|
if (leaf !== void 0) {
|
|
8273
10017
|
cursor[leaf] = value;
|
|
8274
10018
|
}
|
|
@@ -8370,13 +10114,13 @@ async function withOutputFormat2(output, fn) {
|
|
|
8370
10114
|
}
|
|
8371
10115
|
function createFs2() {
|
|
8372
10116
|
return {
|
|
8373
|
-
readFile: async (
|
|
8374
|
-
writeFile: async (
|
|
8375
|
-
await writeFile3(
|
|
10117
|
+
readFile: async (path15, encoding = "utf8") => readFile5(path15, { encoding }),
|
|
10118
|
+
writeFile: async (path15, contents) => {
|
|
10119
|
+
await writeFile3(path15, contents);
|
|
8376
10120
|
},
|
|
8377
|
-
exists: async (
|
|
10121
|
+
exists: async (path15) => {
|
|
8378
10122
|
try {
|
|
8379
|
-
await access2(
|
|
10123
|
+
await access2(path15);
|
|
8380
10124
|
return true;
|
|
8381
10125
|
} catch {
|
|
8382
10126
|
return false;
|
|
@@ -8397,9 +10141,9 @@ function isPlainObject2(value) {
|
|
|
8397
10141
|
function hasFieldValue(value) {
|
|
8398
10142
|
return value !== void 0;
|
|
8399
10143
|
}
|
|
8400
|
-
function hasNestedField(fields,
|
|
10144
|
+
function hasNestedField(fields, path15) {
|
|
8401
10145
|
return fields.some(
|
|
8402
|
-
(field) =>
|
|
10146
|
+
(field) => path15.length < field.path.length && path15.every((segment, index) => field.path[index] === segment)
|
|
8403
10147
|
);
|
|
8404
10148
|
}
|
|
8405
10149
|
function describeExpectedPresetValue(schema) {
|
|
@@ -8456,7 +10200,12 @@ function validatePresetFieldValue(value, field, presetPath) {
|
|
|
8456
10200
|
return value;
|
|
8457
10201
|
}
|
|
8458
10202
|
if (field.schema.kind !== "array") {
|
|
8459
|
-
return validatePresetScalarValue(
|
|
10203
|
+
return validatePresetScalarValue(
|
|
10204
|
+
value,
|
|
10205
|
+
field.schema,
|
|
10206
|
+
field.displayPath,
|
|
10207
|
+
presetPath
|
|
10208
|
+
);
|
|
8460
10209
|
}
|
|
8461
10210
|
const itemSchema = unwrapOptional(field.schema.item);
|
|
8462
10211
|
if (itemSchema.kind === "array" || itemSchema.kind === "object") {
|
|
@@ -8474,7 +10223,7 @@ function validatePresetFieldValue(value, field, presetPath) {
|
|
|
8474
10223
|
async function loadPresetValues(fields, presetPath) {
|
|
8475
10224
|
let rawPreset;
|
|
8476
10225
|
try {
|
|
8477
|
-
rawPreset = await
|
|
10226
|
+
rawPreset = await readFile5(presetPath, {
|
|
8478
10227
|
encoding: "utf8"
|
|
8479
10228
|
});
|
|
8480
10229
|
} catch (error2) {
|
|
@@ -8495,9 +10244,9 @@ async function loadPresetValues(fields, presetPath) {
|
|
|
8495
10244
|
}
|
|
8496
10245
|
const fieldByPath = new Map(fields.map((field) => [field.displayPath, field]));
|
|
8497
10246
|
const presetValues = {};
|
|
8498
|
-
function visitObject(current,
|
|
10247
|
+
function visitObject(current, path15) {
|
|
8499
10248
|
for (const [key2, value] of Object.entries(current)) {
|
|
8500
|
-
const nextPath = [...
|
|
10249
|
+
const nextPath = [...path15, key2];
|
|
8501
10250
|
const displayPath = toDisplayPath(nextPath);
|
|
8502
10251
|
const field = fieldByPath.get(displayPath);
|
|
8503
10252
|
if (field !== void 0) {
|
|
@@ -8556,7 +10305,9 @@ function matchesFixtureValue(expected, actual) {
|
|
|
8556
10305
|
if (!isPlainObject2(actual)) {
|
|
8557
10306
|
return false;
|
|
8558
10307
|
}
|
|
8559
|
-
return Object.entries(expected).every(
|
|
10308
|
+
return Object.entries(expected).every(
|
|
10309
|
+
([key2, value]) => matchesFixtureValue(value, actual[key2])
|
|
10310
|
+
);
|
|
8560
10311
|
}
|
|
8561
10312
|
return Object.is(expected, actual);
|
|
8562
10313
|
}
|
|
@@ -8594,7 +10345,9 @@ function createFixtureResponse(response) {
|
|
|
8594
10345
|
}
|
|
8595
10346
|
function createFixtureFetch(entries) {
|
|
8596
10347
|
return async (input, init) => {
|
|
8597
|
-
const method = normalizeHttpMethod(
|
|
10348
|
+
const method = normalizeHttpMethod(
|
|
10349
|
+
init?.method ?? (input instanceof Request ? input.method : void 0)
|
|
10350
|
+
);
|
|
8598
10351
|
const url = getFetchUrl(input);
|
|
8599
10352
|
const match = entries?.find((entry) => {
|
|
8600
10353
|
const requestMethod = normalizeHttpMethod(entry.request.method);
|
|
@@ -8639,7 +10392,9 @@ function resolveFixtureMethodResult(methodName, definition, args) {
|
|
|
8639
10392
|
}
|
|
8640
10393
|
const explicitMatcher = isPlainObject2(entry.request) ? entry.request : void 0;
|
|
8641
10394
|
const matcher = explicitMatcher ?? Object.fromEntries(
|
|
8642
|
-
Object.entries(entry).filter(
|
|
10395
|
+
Object.entries(entry).filter(
|
|
10396
|
+
([key2]) => key2 !== "result" && key2 !== "response" && key2 !== "error"
|
|
10397
|
+
)
|
|
8643
10398
|
);
|
|
8644
10399
|
const firstArg = args[0];
|
|
8645
10400
|
let matched = false;
|
|
@@ -8695,8 +10450,8 @@ function createFixtureService(definition) {
|
|
|
8695
10450
|
);
|
|
8696
10451
|
}
|
|
8697
10452
|
function resolveFixturePath(commandPath) {
|
|
8698
|
-
const parsed =
|
|
8699
|
-
return
|
|
10453
|
+
const parsed = path9.parse(commandPath);
|
|
10454
|
+
return path9.join(parsed.dir, `${parsed.name}.fixture.json`);
|
|
8700
10455
|
}
|
|
8701
10456
|
function selectFixtureScenario(scenarios, selector) {
|
|
8702
10457
|
if (isNumericFixtureSelector(selector)) {
|
|
@@ -8718,12 +10473,14 @@ function selectFixtureScenario(scenarios, selector) {
|
|
|
8718
10473
|
async function loadFixtureScenario(command, selector) {
|
|
8719
10474
|
const commandPath = getCommandSourcePath(command);
|
|
8720
10475
|
if (commandPath === void 0) {
|
|
8721
|
-
throw new UserError(
|
|
10476
|
+
throw new UserError(
|
|
10477
|
+
`Fixture mode could not determine the source file for command "${command.name}".`
|
|
10478
|
+
);
|
|
8722
10479
|
}
|
|
8723
10480
|
const fixturePath = resolveFixturePath(commandPath);
|
|
8724
10481
|
let rawFixture;
|
|
8725
10482
|
try {
|
|
8726
|
-
rawFixture = await
|
|
10483
|
+
rawFixture = await readFile5(fixturePath, {
|
|
8727
10484
|
encoding: "utf8"
|
|
8728
10485
|
});
|
|
8729
10486
|
} catch {
|
|
@@ -8819,8 +10576,8 @@ function validateServices(services) {
|
|
|
8819
10576
|
}
|
|
8820
10577
|
}
|
|
8821
10578
|
}
|
|
8822
|
-
function getNestedValue(target,
|
|
8823
|
-
return
|
|
10579
|
+
function getNestedValue(target, path15) {
|
|
10580
|
+
return path15.reduce(
|
|
8824
10581
|
(current, segment) => current !== null && typeof current === "object" ? current[segment] : void 0,
|
|
8825
10582
|
target
|
|
8826
10583
|
);
|
|
@@ -8919,7 +10676,13 @@ function resolveDynamicLeaf(schema, rawSegments, casing, outputPath = [], displa
|
|
|
8919
10676
|
if (formatSegment(key2, casing) !== head) {
|
|
8920
10677
|
continue;
|
|
8921
10678
|
}
|
|
8922
|
-
return resolveDynamicLeaf(
|
|
10679
|
+
return resolveDynamicLeaf(
|
|
10680
|
+
childSchema,
|
|
10681
|
+
rest,
|
|
10682
|
+
casing,
|
|
10683
|
+
[...outputPath, key2],
|
|
10684
|
+
[...displayPath, key2]
|
|
10685
|
+
);
|
|
8923
10686
|
}
|
|
8924
10687
|
throw new UserError(`Unknown parameter "${[...displayPath, head].join(".")}".`);
|
|
8925
10688
|
}
|
|
@@ -8936,13 +10699,23 @@ function resolveDynamicLeaf(schema, rawSegments, casing, outputPath = [], displa
|
|
|
8936
10699
|
case "array": {
|
|
8937
10700
|
const itemSchema = unwrapOptional(unwrappedSchema.item);
|
|
8938
10701
|
if (itemSchema.kind !== "object") {
|
|
8939
|
-
throw new UserError(
|
|
10702
|
+
throw new UserError(
|
|
10703
|
+
`Array parameter "${toDisplayPath(displayPath)}" must use object items.`
|
|
10704
|
+
);
|
|
8940
10705
|
}
|
|
8941
10706
|
const [head, ...rest] = rawSegments;
|
|
8942
10707
|
if (head === void 0 || !isNumericFixtureSelector(head)) {
|
|
8943
|
-
throw new UserError(
|
|
10708
|
+
throw new UserError(
|
|
10709
|
+
`Array parameter "${toDisplayPath(displayPath)}" must use numeric indices.`
|
|
10710
|
+
);
|
|
8944
10711
|
}
|
|
8945
|
-
return resolveDynamicLeaf(
|
|
10712
|
+
return resolveDynamicLeaf(
|
|
10713
|
+
itemSchema,
|
|
10714
|
+
rest,
|
|
10715
|
+
casing,
|
|
10716
|
+
[...outputPath, head],
|
|
10717
|
+
[...displayPath, head]
|
|
10718
|
+
);
|
|
8946
10719
|
}
|
|
8947
10720
|
default:
|
|
8948
10721
|
throw new UserError(`Unknown parameter "${[...displayPath, ...rawSegments].join(".")}".`);
|
|
@@ -8978,7 +10751,9 @@ function finalizeDynamicValue(schema, value, displayPath) {
|
|
|
8978
10751
|
}
|
|
8979
10752
|
for (let index = 0; index < indices.length; index += 1) {
|
|
8980
10753
|
if (indices[index] !== index) {
|
|
8981
|
-
throw new UserError(
|
|
10754
|
+
throw new UserError(
|
|
10755
|
+
`Array parameter "${displayPath}" must use contiguous indices starting at 0.`
|
|
10756
|
+
);
|
|
8982
10757
|
}
|
|
8983
10758
|
}
|
|
8984
10759
|
return indices.map(
|
|
@@ -9034,7 +10809,9 @@ function finalizeDynamicValue(schema, value, displayPath) {
|
|
|
9034
10809
|
function parseDynamicValues(dynamicFields, rawArgv, casing) {
|
|
9035
10810
|
const rawValues = /* @__PURE__ */ new Map();
|
|
9036
10811
|
const providedFieldIds = /* @__PURE__ */ new Set();
|
|
9037
|
-
const sortedFields = [...dynamicFields].sort(
|
|
10812
|
+
const sortedFields = [...dynamicFields].sort(
|
|
10813
|
+
(left, right) => right.optionPath.length - left.optionPath.length
|
|
10814
|
+
);
|
|
9038
10815
|
for (let index = 0; index < rawArgv.length; index += 1) {
|
|
9039
10816
|
const token = rawArgv[index] ?? "";
|
|
9040
10817
|
if (!token.startsWith("--")) {
|
|
@@ -9121,7 +10898,9 @@ async function enforceVariantConstraints(params17, fields, dynamicFields, varian
|
|
|
9121
10898
|
);
|
|
9122
10899
|
}
|
|
9123
10900
|
}
|
|
9124
|
-
const invalidDynamicFieldId = branch.dynamicFieldIds.find(
|
|
10901
|
+
const invalidDynamicFieldId = branch.dynamicFieldIds.find(
|
|
10902
|
+
(fieldId) => providedDynamicFieldIds.has(fieldId)
|
|
10903
|
+
);
|
|
9125
10904
|
if (invalidDynamicFieldId !== void 0) {
|
|
9126
10905
|
const field = dynamicFieldById.get(invalidDynamicFieldId);
|
|
9127
10906
|
if (field !== void 0) {
|
|
@@ -9286,7 +11065,7 @@ async function executeCommand(state, services, requirementOptions, runtimeOption
|
|
|
9286
11065
|
optionValues,
|
|
9287
11066
|
state.rawArgv,
|
|
9288
11067
|
state.casing,
|
|
9289
|
-
resolvedFlags.preset,
|
|
11068
|
+
state.presetsEnabled ? resolvedFlags.preset : void 0,
|
|
9290
11069
|
shouldPrompt
|
|
9291
11070
|
);
|
|
9292
11071
|
const context = {
|
|
@@ -9315,7 +11094,12 @@ async function executeCommand(state, services, requirementOptions, runtimeOption
|
|
|
9315
11094
|
throw new UserError("Operation cancelled.");
|
|
9316
11095
|
}
|
|
9317
11096
|
}
|
|
9318
|
-
const result = await invokeWithHumanInLoop(
|
|
11097
|
+
const result = await invokeWithHumanInLoop(
|
|
11098
|
+
state.command,
|
|
11099
|
+
context,
|
|
11100
|
+
runtimeOptions,
|
|
11101
|
+
state.commandPath
|
|
11102
|
+
);
|
|
9319
11103
|
if (output === "rich" && runtime.isFixture) {
|
|
9320
11104
|
writeRichHeader(`${state.command.name} (fixture)`);
|
|
9321
11105
|
}
|
|
@@ -9323,7 +11107,10 @@ async function executeCommand(state, services, requirementOptions, runtimeOption
|
|
|
9323
11107
|
renderHumanInLoopPending(result);
|
|
9324
11108
|
return;
|
|
9325
11109
|
}
|
|
9326
|
-
renderResult(state.command, result, output, primitives);
|
|
11110
|
+
const renderStatus = renderResult(state.command, result, output, primitives);
|
|
11111
|
+
if (renderStatus.mcpError) {
|
|
11112
|
+
process.exitCode = 1;
|
|
11113
|
+
}
|
|
9327
11114
|
});
|
|
9328
11115
|
}
|
|
9329
11116
|
function handleRunError(error2, verbose) {
|
|
@@ -9350,10 +11137,11 @@ function handleRunError(error2, verbose) {
|
|
|
9350
11137
|
}
|
|
9351
11138
|
async function runCLI(roots, options = {}) {
|
|
9352
11139
|
const root = mergeApprovalsGroup(normalizeRoots(roots, process.argv));
|
|
9353
|
-
await resolveMcpProxies(root);
|
|
11140
|
+
await resolveMcpProxies(root, { projectRoot: options.projectRoot });
|
|
9354
11141
|
const casing = options.casing ?? "kebab";
|
|
9355
11142
|
const services = options.services ?? {};
|
|
9356
11143
|
const runtimeOptions = options.humanInLoop ?? {};
|
|
11144
|
+
const version = options.version ?? findEntrypointPackageMetadata(process.argv[1])?.version;
|
|
9357
11145
|
const servicesWithBuiltIns = {
|
|
9358
11146
|
...services,
|
|
9359
11147
|
runtimeOptions,
|
|
@@ -9364,7 +11152,7 @@ async function runCLI(roots, options = {}) {
|
|
|
9364
11152
|
};
|
|
9365
11153
|
validateServices(services);
|
|
9366
11154
|
if (hasHelpFlag(process.argv)) {
|
|
9367
|
-
await renderGeneratedHelp(root, process.argv, options);
|
|
11155
|
+
await renderGeneratedHelp(root, process.argv, { ...options, version });
|
|
9368
11156
|
return;
|
|
9369
11157
|
}
|
|
9370
11158
|
const program = new CommanderCommand();
|
|
@@ -9372,9 +11160,11 @@ async function runCLI(roots, options = {}) {
|
|
|
9372
11160
|
program.exitOverride();
|
|
9373
11161
|
program.showHelpAfterError();
|
|
9374
11162
|
program.addHelpCommand(false);
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
11163
|
+
const presetsEnabled = options.presets === true;
|
|
11164
|
+
const globalLongOptionFlags = getGlobalLongOptionFlags(presetsEnabled);
|
|
11165
|
+
addGlobalOptions(program, presetsEnabled);
|
|
11166
|
+
if (version !== void 0) {
|
|
11167
|
+
program.version(version, "--version");
|
|
9378
11168
|
}
|
|
9379
11169
|
let lastActionCommand;
|
|
9380
11170
|
const execute = async (state) => {
|
|
@@ -9382,7 +11172,13 @@ async function runCLI(roots, options = {}) {
|
|
|
9382
11172
|
await executeCommand(state, servicesWithBuiltIns, requirementOptions, runtimeOptions);
|
|
9383
11173
|
};
|
|
9384
11174
|
for (const child of root.children) {
|
|
9385
|
-
const command = createNodeCommand(
|
|
11175
|
+
const command = createNodeCommand(
|
|
11176
|
+
child,
|
|
11177
|
+
casing,
|
|
11178
|
+
globalLongOptionFlags,
|
|
11179
|
+
execute,
|
|
11180
|
+
presetsEnabled
|
|
11181
|
+
);
|
|
9386
11182
|
if (command === null) {
|
|
9387
11183
|
continue;
|
|
9388
11184
|
}
|
|
@@ -9423,7 +11219,7 @@ var DCS = 144;
|
|
|
9423
11219
|
var SOS = 152;
|
|
9424
11220
|
var PM = 158;
|
|
9425
11221
|
var APC = 159;
|
|
9426
|
-
function
|
|
11222
|
+
function stripAnsi4(input) {
|
|
9427
11223
|
let output = "";
|
|
9428
11224
|
for (let index = 0; index < input.length; index += 1) {
|
|
9429
11225
|
const code = input.charCodeAt(index);
|
|
@@ -10112,7 +11908,7 @@ var TerminalScreen = class {
|
|
|
10112
11908
|
cursor,
|
|
10113
11909
|
size
|
|
10114
11910
|
}) {
|
|
10115
|
-
this.lines = Object.freeze(lines.map((line) =>
|
|
11911
|
+
this.lines = Object.freeze(lines.map((line) => stripAnsi4(line)));
|
|
10116
11912
|
this.rawLines = Object.freeze([...rawLines]);
|
|
10117
11913
|
this.cursor = Object.freeze({ ...cursor });
|
|
10118
11914
|
this.size = Object.freeze({ ...size });
|
|
@@ -10197,14 +11993,14 @@ var TerminalSession = class {
|
|
|
10197
11993
|
});
|
|
10198
11994
|
});
|
|
10199
11995
|
}
|
|
10200
|
-
async type(
|
|
10201
|
-
for (const character of
|
|
11996
|
+
async type(text5) {
|
|
11997
|
+
for (const character of text5) {
|
|
10202
11998
|
await this.send(character);
|
|
10203
11999
|
await sleep2(TYPE_DELAY_MS);
|
|
10204
12000
|
}
|
|
10205
12001
|
}
|
|
10206
|
-
async fill(
|
|
10207
|
-
await this.send(
|
|
12002
|
+
async fill(text5) {
|
|
12003
|
+
await this.send(text5.replace(/\r?\n/g, "\r"));
|
|
10208
12004
|
}
|
|
10209
12005
|
async press(key2) {
|
|
10210
12006
|
await this.send(keyToSequence(key2));
|
|
@@ -10262,7 +12058,7 @@ var TerminalSession = class {
|
|
|
10262
12058
|
});
|
|
10263
12059
|
}
|
|
10264
12060
|
async history(opts) {
|
|
10265
|
-
const normalized = normalizeHistoryBuffer(
|
|
12061
|
+
const normalized = normalizeHistoryBuffer(stripAnsi4(this.rawBuffer));
|
|
10266
12062
|
const lines = splitHistoryLines(normalized);
|
|
10267
12063
|
if (opts?.last === void 0) {
|
|
10268
12064
|
return lines;
|
|
@@ -10368,7 +12164,7 @@ function isMissingFileError(error2) {
|
|
|
10368
12164
|
return "code" in error2 && error2.code === "ENOENT";
|
|
10369
12165
|
}
|
|
10370
12166
|
function matchPattern(buffer, pattern) {
|
|
10371
|
-
const clean = normalizeHistoryBuffer(
|
|
12167
|
+
const clean = normalizeHistoryBuffer(stripAnsi4(buffer));
|
|
10372
12168
|
for (const line of clean.split("\n")) {
|
|
10373
12169
|
if (typeof pattern === "string") {
|
|
10374
12170
|
if (line.includes(pattern)) return line;
|
|
@@ -10628,7 +12424,7 @@ var params2 = S.Object({
|
|
|
10628
12424
|
rows: S.Optional(S.Number({ description: "Terminal height in rows" })),
|
|
10629
12425
|
observe: S.Optional(S.Boolean({ description: "Mirror PTY output to stderr" }))
|
|
10630
12426
|
});
|
|
10631
|
-
var
|
|
12427
|
+
var createSession2 = defineCommand({
|
|
10632
12428
|
name: "create-session",
|
|
10633
12429
|
description: "Spawn an interactive CLI in a PTY",
|
|
10634
12430
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -10680,7 +12476,7 @@ var getSession = defineCommand({
|
|
|
10680
12476
|
|
|
10681
12477
|
// ../agent-skill-config/src/configs.ts
|
|
10682
12478
|
import os2 from "node:os";
|
|
10683
|
-
import
|
|
12479
|
+
import path10 from "node:path";
|
|
10684
12480
|
|
|
10685
12481
|
// ../agent-defs/src/agents/claude-code.ts
|
|
10686
12482
|
var claudeCodeAgent = {
|
|
@@ -11201,20 +12997,20 @@ function getConfigFormat(pathOrFormat) {
|
|
|
11201
12997
|
}
|
|
11202
12998
|
return formatRegistry[formatName];
|
|
11203
12999
|
}
|
|
11204
|
-
function detectFormat(
|
|
11205
|
-
const ext = getExtension(
|
|
13000
|
+
function detectFormat(path15) {
|
|
13001
|
+
const ext = getExtension(path15);
|
|
11206
13002
|
return extensionMap[ext];
|
|
11207
13003
|
}
|
|
11208
|
-
function getExtension(
|
|
11209
|
-
const lastDot =
|
|
13004
|
+
function getExtension(path15) {
|
|
13005
|
+
const lastDot = path15.lastIndexOf(".");
|
|
11210
13006
|
if (lastDot === -1) {
|
|
11211
13007
|
return "";
|
|
11212
13008
|
}
|
|
11213
|
-
return
|
|
13009
|
+
return path15.slice(lastDot).toLowerCase();
|
|
11214
13010
|
}
|
|
11215
13011
|
|
|
11216
13012
|
// ../config-mutations/src/execution/path-utils.ts
|
|
11217
|
-
import
|
|
13013
|
+
import path11 from "node:path";
|
|
11218
13014
|
function expandHome(targetPath, homeDir) {
|
|
11219
13015
|
if (!targetPath?.startsWith("~")) {
|
|
11220
13016
|
return targetPath;
|
|
@@ -11231,7 +13027,7 @@ function expandHome(targetPath, homeDir) {
|
|
|
11231
13027
|
remainder = remainder.slice(1);
|
|
11232
13028
|
}
|
|
11233
13029
|
}
|
|
11234
|
-
return remainder.length === 0 ? homeDir :
|
|
13030
|
+
return remainder.length === 0 ? homeDir : path11.join(homeDir, remainder);
|
|
11235
13031
|
}
|
|
11236
13032
|
function validateHomePath(targetPath) {
|
|
11237
13033
|
if (typeof targetPath !== "string" || targetPath.length === 0) {
|
|
@@ -11249,12 +13045,12 @@ function resolvePath(rawPath, homeDir, pathMapper) {
|
|
|
11249
13045
|
if (!pathMapper) {
|
|
11250
13046
|
return expanded;
|
|
11251
13047
|
}
|
|
11252
|
-
const rawDirectory =
|
|
13048
|
+
const rawDirectory = path11.dirname(expanded);
|
|
11253
13049
|
const mappedDirectory = pathMapper.mapTargetDirectory({
|
|
11254
13050
|
targetDirectory: rawDirectory
|
|
11255
13051
|
});
|
|
11256
|
-
const filename =
|
|
11257
|
-
return filename.length === 0 ? mappedDirectory :
|
|
13052
|
+
const filename = path11.basename(expanded);
|
|
13053
|
+
return filename.length === 0 ? mappedDirectory : path11.join(mappedDirectory, filename);
|
|
11258
13054
|
}
|
|
11259
13055
|
|
|
11260
13056
|
// ../config-mutations/src/fs-utils.ts
|
|
@@ -11861,9 +13657,9 @@ import Mustache2 from "mustache";
|
|
|
11861
13657
|
var originalEscape = Mustache2.escape;
|
|
11862
13658
|
|
|
11863
13659
|
// ../agent-skill-config/src/templates.ts
|
|
11864
|
-
import { readFile as
|
|
11865
|
-
import
|
|
11866
|
-
import { fileURLToPath as
|
|
13660
|
+
import { readFile as readFile6, stat as stat2 } from "node:fs/promises";
|
|
13661
|
+
import path12 from "node:path";
|
|
13662
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
11867
13663
|
|
|
11868
13664
|
// ../agent-skill-config/src/apply.ts
|
|
11869
13665
|
var UnsupportedAgentError = class extends Error {
|
|
@@ -11921,9 +13717,9 @@ async function installSkill(agentId, skill, options) {
|
|
|
11921
13717
|
|
|
11922
13718
|
// src/commands/installer.ts
|
|
11923
13719
|
import os3 from "node:os";
|
|
11924
|
-
import
|
|
13720
|
+
import path13 from "node:path";
|
|
11925
13721
|
import * as nodeFs from "node:fs/promises";
|
|
11926
|
-
import { readFile as
|
|
13722
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
11927
13723
|
var DEFAULT_INSTALL_AGENT = "claude-code";
|
|
11928
13724
|
var DEFAULT_INSTALL_SCOPE = "local";
|
|
11929
13725
|
var TERMINAL_PILOT_SKILL_NAME = "terminal-pilot";
|
|
@@ -11973,7 +13769,7 @@ async function loadTerminalPilotTemplate() {
|
|
|
11973
13769
|
];
|
|
11974
13770
|
for (const candidate of candidates) {
|
|
11975
13771
|
try {
|
|
11976
|
-
terminalPilotTemplateCache = await
|
|
13772
|
+
terminalPilotTemplateCache = await readFile7(candidate, "utf8");
|
|
11977
13773
|
return terminalPilotTemplateCache;
|
|
11978
13774
|
} catch (error2) {
|
|
11979
13775
|
if (!isNotFoundError2(error2)) {
|
|
@@ -11988,7 +13784,7 @@ function resolveHomeRelativePath(targetPath, homeDir) {
|
|
|
11988
13784
|
return homeDir;
|
|
11989
13785
|
}
|
|
11990
13786
|
if (targetPath.startsWith("~/")) {
|
|
11991
|
-
return
|
|
13787
|
+
return path13.join(homeDir, targetPath.slice(2));
|
|
11992
13788
|
}
|
|
11993
13789
|
return targetPath;
|
|
11994
13790
|
}
|
|
@@ -11998,12 +13794,12 @@ function getSkillFolderWithHome(agent, scope, cwd, homeDir) {
|
|
|
11998
13794
|
throwUnsupportedAgent(agent);
|
|
11999
13795
|
}
|
|
12000
13796
|
return {
|
|
12001
|
-
displayPath:
|
|
13797
|
+
displayPath: path13.join(
|
|
12002
13798
|
scope === "global" ? config.globalSkillDir : config.localSkillDir,
|
|
12003
13799
|
TERMINAL_PILOT_SKILL_NAME
|
|
12004
13800
|
),
|
|
12005
|
-
fullPath:
|
|
12006
|
-
scope === "global" ? resolveHomeRelativePath(config.globalSkillDir, homeDir) :
|
|
13801
|
+
fullPath: path13.join(
|
|
13802
|
+
scope === "global" ? resolveHomeRelativePath(config.globalSkillDir, homeDir) : path13.resolve(cwd, config.localSkillDir),
|
|
12007
13803
|
TERMINAL_PILOT_SKILL_NAME
|
|
12008
13804
|
)
|
|
12009
13805
|
};
|
|
@@ -12195,17 +13991,17 @@ function colorsEqual(left, right) {
|
|
|
12195
13991
|
}
|
|
12196
13992
|
return false;
|
|
12197
13993
|
}
|
|
12198
|
-
function pushRun(runs, style,
|
|
12199
|
-
if (
|
|
13994
|
+
function pushRun(runs, style, text5) {
|
|
13995
|
+
if (text5.length === 0) {
|
|
12200
13996
|
return;
|
|
12201
13997
|
}
|
|
12202
13998
|
const previous = runs.at(-1);
|
|
12203
|
-
if (previous &&
|
|
12204
|
-
previous.text +=
|
|
13999
|
+
if (previous && text5 !== "\n" && previous.text !== "\n" && stylesEqual(previous, style)) {
|
|
14000
|
+
previous.text += text5;
|
|
12205
14001
|
return;
|
|
12206
14002
|
}
|
|
12207
14003
|
runs.push({
|
|
12208
|
-
text:
|
|
14004
|
+
text: text5,
|
|
12209
14005
|
fg: style.fg,
|
|
12210
14006
|
bg: style.bg,
|
|
12211
14007
|
bold: style.bold,
|
|
@@ -12407,18 +14203,18 @@ function parseAnsi2(input) {
|
|
|
12407
14203
|
import { Resvg } from "@resvg/resvg-js";
|
|
12408
14204
|
|
|
12409
14205
|
// ../terminal-png/src/font.ts
|
|
12410
|
-
import { readFileSync } from "node:fs";
|
|
14206
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
12411
14207
|
import { createRequire as createRequire2 } from "node:module";
|
|
12412
14208
|
import { dirname as dirname2, join as join2 } from "node:path";
|
|
12413
|
-
import { fileURLToPath as
|
|
14209
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
12414
14210
|
var require2 = createRequire2(import.meta.url);
|
|
12415
14211
|
var fontPackageRoot = dirname2(require2.resolve("jetbrains-mono/package.json"));
|
|
12416
14212
|
var webfontRoot = join2(fontPackageRoot, "fonts/webfonts");
|
|
12417
14213
|
function readWebfontBase64(filename) {
|
|
12418
|
-
return
|
|
14214
|
+
return readFileSync2(join2(webfontRoot, filename)).toString("base64");
|
|
12419
14215
|
}
|
|
12420
14216
|
function resolveAssetPath(filename) {
|
|
12421
|
-
return
|
|
14217
|
+
return fileURLToPath4(new URL(`../assets/${filename}`, import.meta.url));
|
|
12422
14218
|
}
|
|
12423
14219
|
function createFontFace(base64, weight, style) {
|
|
12424
14220
|
return `@font-face {
|
|
@@ -12804,10 +14600,10 @@ function measureLines(lines) {
|
|
|
12804
14600
|
0
|
|
12805
14601
|
);
|
|
12806
14602
|
}
|
|
12807
|
-
function displayWidth(
|
|
14603
|
+
function displayWidth(text5) {
|
|
12808
14604
|
const segmenter = new Intl.Segmenter();
|
|
12809
14605
|
let width = 0;
|
|
12810
|
-
for (const { segment } of segmenter.segment(
|
|
14606
|
+
for (const { segment } of segmenter.segment(text5)) {
|
|
12811
14607
|
const cp = segment.codePointAt(0);
|
|
12812
14608
|
width += cp !== void 0 && isWideCodePoint(cp) ? 2 : 1;
|
|
12813
14609
|
}
|
|
@@ -13071,7 +14867,7 @@ var waitForExit2 = defineCommand({
|
|
|
13071
14867
|
var children = [
|
|
13072
14868
|
install,
|
|
13073
14869
|
uninstall,
|
|
13074
|
-
|
|
14870
|
+
createSession2,
|
|
13075
14871
|
fill,
|
|
13076
14872
|
type,
|
|
13077
14873
|
pressKey,
|
|
@@ -13114,9 +14910,9 @@ async function isDirectExecution(argv) {
|
|
|
13114
14910
|
return false;
|
|
13115
14911
|
}
|
|
13116
14912
|
try {
|
|
13117
|
-
const modulePath =
|
|
14913
|
+
const modulePath = fileURLToPath5(import.meta.url);
|
|
13118
14914
|
const [resolvedEntryPoint, resolvedModulePath] = await Promise.all([
|
|
13119
|
-
realpath(
|
|
14915
|
+
realpath(path14.resolve(entryPoint)),
|
|
13120
14916
|
realpath(modulePath)
|
|
13121
14917
|
]);
|
|
13122
14918
|
return resolvedEntryPoint === resolvedModulePath;
|