@duyquangnvx/agent-cli 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +10 -2
  3. package/dist/built-ins.d.ts +4 -0
  4. package/dist/built-ins.js +20 -0
  5. package/dist/built-ins.js.map +1 -0
  6. package/dist/command-spec.d.ts +28 -0
  7. package/dist/command-spec.js +31 -0
  8. package/dist/command-spec.js.map +1 -0
  9. package/dist/confirm.d.ts +7 -0
  10. package/dist/confirm.js +22 -0
  11. package/dist/confirm.js.map +1 -0
  12. package/dist/define.d.ts +132 -0
  13. package/dist/define.js +10 -0
  14. package/dist/define.js.map +1 -0
  15. package/dist/doctor-rows.d.ts +3 -0
  16. package/dist/doctor-rows.js +115 -0
  17. package/dist/doctor-rows.js.map +1 -0
  18. package/dist/doctor.d.ts +3 -0
  19. package/dist/doctor.js +100 -0
  20. package/dist/doctor.js.map +1 -0
  21. package/dist/errors.d.ts +34 -0
  22. package/dist/errors.js +72 -0
  23. package/dist/errors.js.map +1 -0
  24. package/dist/execute.d.ts +21 -0
  25. package/dist/execute.js +26 -0
  26. package/dist/execute.js.map +1 -0
  27. package/dist/flags.d.ts +50 -0
  28. package/dist/flags.js +59 -0
  29. package/dist/flags.js.map +1 -0
  30. package/dist/global-install.d.ts +13 -0
  31. package/dist/global-install.js +51 -0
  32. package/dist/global-install.js.map +1 -0
  33. package/dist/help-json.d.ts +4 -0
  34. package/dist/help-json.js +44 -0
  35. package/dist/help-json.js.map +1 -0
  36. package/dist/help.d.ts +5 -0
  37. package/dist/help.js +64 -0
  38. package/dist/help.js.map +1 -0
  39. package/dist/index.d.ts +12 -0
  40. package/dist/index.js +7 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/input.d.ts +22 -0
  43. package/dist/input.js +63 -0
  44. package/dist/input.js.map +1 -0
  45. package/dist/interrupts.d.ts +18 -0
  46. package/dist/interrupts.js +118 -0
  47. package/dist/interrupts.js.map +1 -0
  48. package/dist/invocation.d.ts +9 -0
  49. package/dist/invocation.js +37 -0
  50. package/dist/invocation.js.map +1 -0
  51. package/dist/list.d.ts +44 -0
  52. package/dist/list.js +126 -0
  53. package/dist/list.js.map +1 -0
  54. package/dist/npm.d.ts +24 -0
  55. package/dist/npm.js +181 -0
  56. package/dist/npm.js.map +1 -0
  57. package/dist/output.d.ts +33 -0
  58. package/dist/output.js +65 -0
  59. package/dist/output.js.map +1 -0
  60. package/dist/parse-input.d.ts +19 -0
  61. package/dist/parse-input.js +147 -0
  62. package/dist/parse-input.js.map +1 -0
  63. package/dist/route.d.ts +25 -0
  64. package/dist/route.js +75 -0
  65. package/dist/route.js.map +1 -0
  66. package/dist/run-cli.d.ts +16 -0
  67. package/dist/run-cli.js +85 -0
  68. package/dist/run-cli.js.map +1 -0
  69. package/dist/run-process.d.ts +2 -0
  70. package/dist/run-process.js +37 -0
  71. package/dist/run-process.js.map +1 -0
  72. package/dist/semver.d.ts +9 -0
  73. package/dist/semver.js +70 -0
  74. package/dist/semver.js.map +1 -0
  75. package/dist/skills.d.ts +11 -0
  76. package/dist/skills.js +58 -0
  77. package/dist/skills.js.map +1 -0
  78. package/dist/style.d.ts +13 -0
  79. package/dist/style.js +38 -0
  80. package/dist/style.js.map +1 -0
  81. package/dist/suggest.d.ts +6 -0
  82. package/dist/suggest.js +49 -0
  83. package/dist/suggest.js.map +1 -0
  84. package/dist/tokenize.d.ts +20 -0
  85. package/dist/tokenize.js +79 -0
  86. package/dist/tokenize.js.map +1 -0
  87. package/dist/update.d.ts +3 -0
  88. package/dist/update.js +91 -0
  89. package/dist/update.js.map +1 -0
  90. package/dist/upgrade-notes.d.ts +9 -0
  91. package/dist/upgrade-notes.js +41 -0
  92. package/dist/upgrade-notes.js.map +1 -0
  93. package/dist/usage.d.ts +5 -0
  94. package/dist/usage.js +37 -0
  95. package/dist/usage.js.map +1 -0
  96. package/package.json +29 -3
package/dist/skills.js ADDED
@@ -0,0 +1,58 @@
1
+ import { readFile, realpath } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { isMissingFile } from "./errors.js";
5
+ import { isVersion, standingOf } from "./semver.js";
6
+ /** Where the skills CLI (`npx skills add`) puts a skill, under a project and under home. */
7
+ const SKILL_DIRS = [
8
+ [".claude", "skills"],
9
+ [".agents", "skills"],
10
+ ];
11
+ export function skillUpdateCommand(cliName) {
12
+ return `npx -y skills update ${cliName}`;
13
+ }
14
+ const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
15
+ const METADATA_VERSION = /^metadata:[ \t]*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:[ \t]*["']?([^"'\s]+)["']?[ \t]*$/m;
16
+ /** The version a SKILL.md's frontmatter `metadata.version` states. */
17
+ function skillVersionIn(skill) {
18
+ const frontmatter = FRONTMATTER.exec(skill)?.[1];
19
+ return frontmatter === undefined ? undefined : METADATA_VERSION.exec(`${frontmatter}\n`)?.[1];
20
+ }
21
+ function homeOf(env) {
22
+ return env.HOME ?? env.USERPROFILE ?? homedir();
23
+ }
24
+ async function copyAt(path, cliVersion) {
25
+ let skill;
26
+ try {
27
+ skill = await readFile(join(path, "SKILL.md"), "utf8");
28
+ }
29
+ catch (error) {
30
+ if (isMissingFile(error)) {
31
+ return undefined;
32
+ }
33
+ return { path, version: undefined, state: "unreadable" };
34
+ }
35
+ const version = skillVersionIn(skill);
36
+ if (version === undefined || !isVersion(version) || !isVersion(cliVersion)) {
37
+ return { path, version, state: "unversioned" };
38
+ }
39
+ return { path, version, state: standingOf(version, cliVersion) };
40
+ }
41
+ /** Every installed copy of the skill named after the CLI, in the project first, then under home. */
42
+ export async function skillCopies(skillName, cliVersion, cwd, env) {
43
+ const roots = [cwd, homeOf(env)];
44
+ const paths = roots.flatMap((root) => SKILL_DIRS.map((dir) => join(root, ...dir, skillName)));
45
+ const seen = new Set();
46
+ const copies = [];
47
+ for (const path of paths) {
48
+ const copy = await copyAt(path, cliVersion);
49
+ // The project may be home itself, or one skill dir a link to the other.
50
+ const real = copy === undefined ? undefined : await realpath(path);
51
+ if (copy !== undefined && real !== undefined && !seen.has(real)) {
52
+ seen.add(real);
53
+ copies.push(copy);
54
+ }
55
+ }
56
+ return copies;
57
+ }
58
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAiB,UAAU,EAAE,MAAM,aAAa,CAAC;AAEnE,4FAA4F;AAC5F,MAAM,UAAU,GAAG;IACjB,CAAC,SAAS,EAAE,QAAQ,CAAC;IACrB,CAAC,SAAS,EAAE,QAAQ,CAAC;CACb,CAAC;AAEX,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,OAAO,wBAAwB,OAAO,EAAE,CAAC;AAC3C,CAAC;AAUD,MAAM,WAAW,GAAG,6BAA6B,CAAC;AAClD,MAAM,gBAAgB,GACpB,0FAA0F,CAAC;AAE7F,sEAAsE;AACtE,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,WAAW,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,SAAS,MAAM,CAAC,GAAQ;IACtB,OAAO,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,WAAW,IAAI,OAAO,EAAE,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY,EAAE,UAAkB;IACpD,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAC3D,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,oGAAoG;AACpG,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB,EACjB,UAAkB,EAClB,GAAW,EACX,GAAQ;IAER,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAC9F,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC5C,wEAAwE;QACxE,MAAM,IAAI,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QACnE,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAChE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Env } from "./define.js";
2
+ type Paint = (text: string) => string;
3
+ /** Colours text when colour is on; every method returns the text unchanged when it is off. */
4
+ export interface Style {
5
+ readonly bold: Paint;
6
+ readonly dim: Paint;
7
+ readonly red: Paint;
8
+ readonly green: Paint;
9
+ readonly yellow: Paint;
10
+ readonly cyan: Paint;
11
+ }
12
+ export declare function styleFor(env: Env, stdoutIsTTY: boolean): Style;
13
+ export {};
package/dist/style.js ADDED
@@ -0,0 +1,38 @@
1
+ // Some Agent harnesses run commands in a PTY, so a TTY alone doesn't mean a person is watching.
2
+ const AGENT_VARIABLES = [
3
+ "CLAUDECODE",
4
+ "CODEX_CI",
5
+ "CODEX_SANDBOX",
6
+ "GEMINI_CLI",
7
+ "CURSOR_AGENT",
8
+ "CI",
9
+ ];
10
+ function colourEnabled(env, stdoutIsTTY) {
11
+ const noColor = env.NO_COLOR !== undefined && env.NO_COLOR !== "";
12
+ const agent = AGENT_VARIABLES.some((name) => env[name] !== undefined);
13
+ return stdoutIsTTY && !noColor && !agent;
14
+ }
15
+ function sgr(open, close) {
16
+ return (text) => `\u001b[${open}m${text}\u001b[${close}m`;
17
+ }
18
+ const COLOURED = {
19
+ bold: sgr(1, 22),
20
+ dim: sgr(2, 22),
21
+ red: sgr(31, 39),
22
+ green: sgr(32, 39),
23
+ yellow: sgr(33, 39),
24
+ cyan: sgr(36, 39),
25
+ };
26
+ const plain = (text) => text;
27
+ const PLAIN = {
28
+ bold: plain,
29
+ dim: plain,
30
+ red: plain,
31
+ green: plain,
32
+ yellow: plain,
33
+ cyan: plain,
34
+ };
35
+ export function styleFor(env, stdoutIsTTY) {
36
+ return colourEnabled(env, stdoutIsTTY) ? COLOURED : PLAIN;
37
+ }
38
+ //# sourceMappingURL=style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.js","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"AAcA,gGAAgG;AAChG,MAAM,eAAe,GAAG;IACtB,YAAY;IACZ,UAAU;IACV,eAAe;IACf,YAAY;IACZ,cAAc;IACd,IAAI;CACI,CAAC;AAEX,SAAS,aAAa,CAAC,GAAQ,EAAE,WAAoB;IACnD,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC;IAClE,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC;IACtE,OAAO,WAAW,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC;AAC3C,CAAC;AAED,SAAS,GAAG,CAAC,IAAY,EAAE,KAAa;IACtC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,IAAI,IAAI,IAAI,UAAU,KAAK,GAAG,CAAC;AAC5D,CAAC;AAED,MAAM,QAAQ,GAAU;IACtB,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;IAChB,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;IACf,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC;IAClB,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,KAAK,GAAU,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;AAEpC,MAAM,KAAK,GAAU;IACnB,IAAI,EAAE,KAAK;IACX,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,KAAK;CACZ,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,GAAQ,EAAE,WAAoB;IACrD,OAAO,aAAa,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** The names closest to `word`, sorted, several when they tie, or none when nothing is close. */
2
+ export declare function closestNames(word: string, names: readonly string[]): string[];
3
+ /** The long flags closest to `flag`, sorted, or none for a short flag or when nothing is close. */
4
+ export declare function closestFlags(flag: string, flags: readonly string[]): string[];
5
+ /** The one long flag closest to `flag`, or none when nothing is close or several tie. */
6
+ export declare function closestFlag(flag: string, flags: readonly string[]): string | undefined;
@@ -0,0 +1,49 @@
1
+ const MAX_DISTANCE = 3;
2
+ const MIN_SIMILARITY = 0.4;
3
+ // Optimal string alignment distance.
4
+ function distance(a, b) {
5
+ const width = b.length + 1;
6
+ const d = Array.from({ length: (a.length + 1) * width }, (_, k) => {
7
+ const i = Math.floor(k / width);
8
+ const j = k % width;
9
+ // The first row and column count the edits from an empty string.
10
+ return i === 0 || j === 0 ? i + j : 0;
11
+ });
12
+ const at = (i, j) => d[i * width + j] ?? 0;
13
+ for (let i = 1; i <= a.length; i++) {
14
+ for (let j = 1; j <= b.length; j++) {
15
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
16
+ const edit = Math.min(at(i - 1, j) + 1, at(i, j - 1) + 1, at(i - 1, j - 1) + cost);
17
+ const transposed = i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1];
18
+ d[i * width + j] = transposed ? Math.min(edit, at(i - 2, j - 2) + 1) : edit;
19
+ }
20
+ }
21
+ return at(a.length, b.length);
22
+ }
23
+ function isClose(word, candidate) {
24
+ const length = Math.max(word.length, candidate.length);
25
+ const edits = distance(word, candidate);
26
+ return candidate.length > 1 && edits < MAX_DISTANCE && (length - edits) / length > MIN_SIMILARITY;
27
+ }
28
+ /** The names closest to `word`, sorted, several when they tie, or none when nothing is close. */
29
+ export function closestNames(word, names) {
30
+ const close = [...new Set(names)].filter((candidate) => isClose(word, candidate));
31
+ const best = Math.min(...close.map((candidate) => distance(word, candidate)));
32
+ return close
33
+ .filter((candidate) => distance(word, candidate) === best)
34
+ .sort((a, b) => a.localeCompare(b));
35
+ }
36
+ /** The long flags closest to `flag`, sorted, or none for a short flag or when nothing is close. */
37
+ export function closestFlags(flag, flags) {
38
+ if (!flag.startsWith("--")) {
39
+ return [];
40
+ }
41
+ const names = flags.map((candidate) => candidate.slice(2));
42
+ return closestNames(flag.slice(2), names).map((name) => `--${name}`);
43
+ }
44
+ /** The one long flag closest to `flag`, or none when nothing is close or several tie. */
45
+ export function closestFlag(flag, flags) {
46
+ const closest = closestFlags(flag, flags);
47
+ return closest.length === 1 ? closest[0] : undefined;
48
+ }
49
+ //# sourceMappingURL=suggest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest.js","sourceRoot":"","sources":["../src/suggest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /** What a flag takes after it: nothing, the next word unless it is a flag, or the next word. */
2
+ export type Takes = "nothing" | "optional value" | "value";
3
+ export interface KnownFlag {
4
+ /** The flag as the caller types it, such as `--limit` or `--no-install`. */
5
+ readonly flag: string;
6
+ readonly takes: Takes;
7
+ }
8
+ export interface Operand {
9
+ readonly value: string;
10
+ readonly afterUnknownOption: boolean;
11
+ }
12
+ export interface Words {
13
+ readonly operands: readonly Operand[];
14
+ /** Each unknown option word as typed, `=value` included. */
15
+ readonly unknownOptions: readonly string[];
16
+ /** The last value of each known flag passed; `true` for a switch or a flag given no value. */
17
+ readonly values: ReadonlyMap<string, string | true>;
18
+ }
19
+ /** Splits a Command's words into operands, unknown options and the values of known flags. */
20
+ export declare function tokenize(words: readonly string[], known: readonly KnownFlag[]): Words;
@@ -0,0 +1,79 @@
1
+ import { parseArgs } from "node:util";
2
+ const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
3
+ function isOptionLike(word) {
4
+ return word !== undefined && word.length > 1 && word[0] === "-" && !NEGATIVE_NUMBER.test(word);
5
+ }
6
+ // A flag taking an optional value is declared a switch, so that parseArgs never swallows the next
7
+ // flag as its value; the value is then picked here from the word after it.
8
+ function parseArgsOptions(known) {
9
+ return Object.fromEntries(known.map(({ flag, takes }) => [
10
+ flag.slice(2),
11
+ { type: takes === "value" ? "string" : "boolean" },
12
+ ]));
13
+ }
14
+ function flagItem(token, { flag, takes }, words) {
15
+ if (takes !== "optional value" || token.inlineValue === true) {
16
+ return { kind: "flag", flag, value: token.value ?? true };
17
+ }
18
+ const took = token.index + 1;
19
+ const next = words[took];
20
+ return next === undefined || isOptionLike(next)
21
+ ? { kind: "flag", flag, value: true }
22
+ : { kind: "flag", flag, value: next, took };
23
+ }
24
+ function itemOf(token, words, byFlag) {
25
+ const word = words[token.index] ?? "";
26
+ if (token.kind === "option-terminator") {
27
+ return { kind: "end" };
28
+ }
29
+ if (token.kind === "positional" || NEGATIVE_NUMBER.test(word)) {
30
+ return { kind: "operand", value: word };
31
+ }
32
+ const flag = byFlag.get(token.rawName);
33
+ return flag === undefined || (flag.takes === "nothing" && token.inlineValue === true)
34
+ ? { kind: "unknown option", word }
35
+ : flagItem(token, flag, words);
36
+ }
37
+ /** Splits a Command's words into operands, unknown options and the values of known flags. */
38
+ export function tokenize(words, known) {
39
+ const byFlag = new Map(known.map((flag) => [flag.flag, flag]));
40
+ const { tokens } = parseArgs({
41
+ args: [...words],
42
+ options: parseArgsOptions(known),
43
+ strict: false,
44
+ allowPositionals: true,
45
+ tokens: true,
46
+ });
47
+ const operands = [];
48
+ const unknownOptions = [];
49
+ const values = new Map();
50
+ // A short group such as `-abc` yields one token per letter, all at the same index.
51
+ const done = new Set();
52
+ let literal = false;
53
+ let afterUnknownOption = false;
54
+ for (const token of tokens) {
55
+ if (done.has(token.index)) {
56
+ continue;
57
+ }
58
+ done.add(token.index);
59
+ const item = itemOf(token, words, byFlag);
60
+ if (item.kind === "end") {
61
+ literal = true;
62
+ }
63
+ else if (item.kind === "operand") {
64
+ operands.push({ value: item.value, afterUnknownOption: !literal && afterUnknownOption });
65
+ afterUnknownOption = false;
66
+ }
67
+ else if (item.kind === "unknown option") {
68
+ unknownOptions.push(item.word);
69
+ afterUnknownOption = true;
70
+ }
71
+ else {
72
+ values.set(item.flag, item.value);
73
+ if (item.took !== undefined)
74
+ done.add(item.took);
75
+ }
76
+ }
77
+ return { operands, unknownOptions, values };
78
+ }
79
+ //# sourceMappingURL=tokenize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenize.js","sourceRoot":"","sources":["../src/tokenize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Command, type CommandTreeCli, type GlobalInstall } from "./define.js";
2
+ /** The built-in `update`, for a CLI installed globally with npm. */
3
+ export declare function updateCommand(cli: CommandTreeCli, install: GlobalInstall, bin: string | undefined): Command;
package/dist/update.js ADDED
@@ -0,0 +1,91 @@
1
+ import * as z from "zod";
2
+ import { defineCommand } from "./define.js";
3
+ import { FailureWithData } from "./errors.js";
4
+ import { globalInstallOf } from "./global-install.js";
5
+ import { INTERRUPTED } from "./interrupts.js";
6
+ import { installGlobally, latestVersion, npmContext } from "./npm.js";
7
+ import { standingOf } from "./semver.js";
8
+ import { skillUpdateCommand } from "./skills.js";
9
+ import { upgradeNotes } from "./upgrade-notes.js";
10
+ const updateSchema = z.object({
11
+ from: z.string(),
12
+ latest: z.string(),
13
+ installed: z.object({ version: z.string(), prefix: z.string() }).nullable(),
14
+ upgrades: z.array(z.object({ version: z.string(), notes: z.string() })),
15
+ next: z.array(z.string()),
16
+ });
17
+ function nothingToInstall({ from, latest }) {
18
+ return standingOf(from, latest) === "current"
19
+ ? `already on ${from}, the latest release: nothing to install`
20
+ : `${from} is newer than the latest release ${latest}: nothing to install`;
21
+ }
22
+ function renderUpdate(cli, install, update) {
23
+ const { installed } = update;
24
+ if (installed === null) {
25
+ return nothingToInstall(update);
26
+ }
27
+ return [
28
+ `installed ${install.package}@${installed.version} with the npm under ${installed.prefix}, replacing ${update.from}`,
29
+ ...update.upgrades.map(({ version, notes }) => `\nchanges in ${version}:\n${notes}`),
30
+ "",
31
+ ...update.next.map((command) => `next: ${command}, so the ${cli.name} skill describes ${installed.version}`),
32
+ ].join("\n");
33
+ }
34
+ // The install ran to its end, so the run reports it rather than asking for a rerun.
35
+ function interruptedAfterInstall(plan, update) {
36
+ return new FailureWithData({
37
+ code: INTERRUPTED,
38
+ message: `interrupted, but ${plan.package}@${plan.latest} had already been installed with the npm under ${plan.prefix}, replacing ${plan.from}`,
39
+ hint: "nothing to run again: run the commands under next",
40
+ retryable: false,
41
+ }, update);
42
+ }
43
+ /** The built-in `update`, for a CLI installed globally with npm. */
44
+ export function updateCommand(cli, install, bin) {
45
+ return defineCommand({
46
+ name: "update",
47
+ description: "install the latest version of this CLI from its registry",
48
+ examples: [
49
+ { command: `${cli.name} update`, note: "install the latest version and show what changed" },
50
+ { command: `${cli.name} update --dry-run`, note: "show the version it would install" },
51
+ ],
52
+ effect: "write",
53
+ output: updateSchema,
54
+ plan: async (_input, ctx) => {
55
+ const npm = npmContext(cli, install, ctx);
56
+ const copy = await globalInstallOf(bin, npm);
57
+ return {
58
+ package: install.package,
59
+ from: cli.version,
60
+ latest: await latestVersion(npm),
61
+ prefix: copy.prefix,
62
+ packageDir: copy.packageDir,
63
+ };
64
+ },
65
+ apply: async (plan, ctx) => {
66
+ const { from, latest, prefix } = plan;
67
+ if (standingOf(from, latest) !== "behind") {
68
+ return { from, latest, installed: null, upgrades: [], next: [] };
69
+ }
70
+ ctx.signal.throwIfAborted();
71
+ ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
72
+ await ctx.runToEnd(() => installGlobally(latest, npmContext(cli, install, ctx)));
73
+ const update = {
74
+ from,
75
+ latest,
76
+ installed: { version: latest, prefix },
77
+ upgrades: await upgradeNotes(plan.packageDir, from, latest),
78
+ next: [skillUpdateCommand(cli.name)],
79
+ };
80
+ if (ctx.signal.aborted) {
81
+ throw interruptedAfterInstall(plan, update);
82
+ }
83
+ return update;
84
+ },
85
+ render: (update) => renderUpdate(cli, install, update),
86
+ renderPlan: (plan) => standingOf(plan.from, plan.latest) === "behind"
87
+ ? `would install ${plan.package}@${plan.latest} with the npm under ${plan.prefix}, replacing ${plan.from}`
88
+ : nothingToInstall(plan),
89
+ });
90
+ }
91
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface UpgradeNotes {
2
+ readonly version: string;
3
+ readonly notes: string;
4
+ }
5
+ /**
6
+ * What changed in each release after `from` up to `to`, oldest first, from the CHANGELOG.md in
7
+ * `packageDir`; none when the package ships no CHANGELOG.
8
+ */
9
+ export declare function upgradeNotes(packageDir: string, from: string, to: string): Promise<UpgradeNotes[]>;
@@ -0,0 +1,41 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { isMissingFile } from "./errors.js";
4
+ import { compareVersions, isVersion } from "./semver.js";
5
+ const RELEASE_HEADING = /^## v?(\S+)/;
6
+ function releasesIn(changelog) {
7
+ const releases = [];
8
+ let current;
9
+ for (const line of changelog.split(/\r?\n/)) {
10
+ const heading = RELEASE_HEADING.exec(line);
11
+ if (heading !== null) {
12
+ const version = heading[1] ?? "";
13
+ current = isVersion(version) ? { version, lines: [] } : undefined;
14
+ if (current !== undefined)
15
+ releases.push(current);
16
+ }
17
+ else {
18
+ current?.lines.push(line);
19
+ }
20
+ }
21
+ return releases.map(({ version, lines }) => ({ version, notes: lines.join("\n").trim() }));
22
+ }
23
+ /**
24
+ * What changed in each release after `from` up to `to`, oldest first, from the CHANGELOG.md in
25
+ * `packageDir`; none when the package ships no CHANGELOG.
26
+ */
27
+ export async function upgradeNotes(packageDir, from, to) {
28
+ let changelog;
29
+ try {
30
+ changelog = await readFile(join(packageDir, "CHANGELOG.md"), "utf8");
31
+ }
32
+ catch (error) {
33
+ if (isMissingFile(error))
34
+ return [];
35
+ throw error;
36
+ }
37
+ return releasesIn(changelog)
38
+ .filter(({ version }) => compareVersions(version, from) > 0 && compareVersions(version, to) <= 0)
39
+ .sort((a, b) => compareVersions(a.version, b.version));
40
+ }
41
+ //# sourceMappingURL=upgrade-notes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade-notes.js","sourceRoot":"","sources":["../src/upgrade-notes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAOzD,MAAM,eAAe,GAAG,aAAa,CAAC;AAEtC,SAAS,UAAU,CAAC,SAAiB;IACnC,MAAM,QAAQ,GAA2C,EAAE,CAAC;IAC5D,IAAI,OAAyD,CAAC;IAC9D,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACjC,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;YAClE,IAAI,OAAO,KAAK,SAAS;gBAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,UAAkB,EAClB,IAAY,EACZ,EAAU;IAEV,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,aAAa,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACpC,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,UAAU,CAAC,SAAS,CAAC;SACzB,MAAM,CACL,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,CACzF;SACA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { UsageError } from "./errors.js";
2
+ import { type Invocation } from "./invocation.js";
3
+ export declare function unknownOptionError(commandLine: string, invocation: Invocation, flag: string, suggestions: readonly string[]): UsageError;
4
+ export declare function unknownCommandError(commandLine: string, name: string, suggestions: readonly string[]): UsageError;
5
+ export declare function invalidInputError(commandLine: string, problem: string): UsageError;
package/dist/usage.js ADDED
@@ -0,0 +1,37 @@
1
+ import { UsageError } from "./errors.js";
2
+ import { commandLineRenaming } from "./invocation.js";
3
+ function unknownError({ code, problem, commandLine, corrections, listed }) {
4
+ return new UsageError({
5
+ code,
6
+ message: `${problem} for \`${commandLine}\``,
7
+ hint: corrections.length === 0
8
+ ? `run \`${commandLine} --help\` to see the ${listed}`
9
+ : `did you mean ${corrections.map((correction) => `\`${correction}\``).join(" or ")}?`,
10
+ });
11
+ }
12
+ export function unknownOptionError(commandLine, invocation, flag, suggestions) {
13
+ return unknownError({
14
+ code: "UNKNOWN_OPTION",
15
+ problem: `unknown option '${flag}'`,
16
+ commandLine,
17
+ corrections: suggestions.map((name) => commandLineRenaming(invocation, new Map([[flag, name]]))),
18
+ listed: "options",
19
+ });
20
+ }
21
+ export function unknownCommandError(commandLine, name, suggestions) {
22
+ return unknownError({
23
+ code: "UNKNOWN_COMMAND",
24
+ problem: `unknown command '${name}'`,
25
+ commandLine,
26
+ corrections: suggestions.map((suggestion) => `${commandLine} ${suggestion}`),
27
+ listed: "commands",
28
+ });
29
+ }
30
+ export function invalidInputError(commandLine, problem) {
31
+ return new UsageError({
32
+ code: "INVALID_INPUT",
33
+ message: problem,
34
+ hint: `run \`${commandLine} --help\` to see the expected input`,
35
+ });
36
+ }
37
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAmB,MAAM,iBAAiB,CAAC;AAUvE,SAAS,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAW;IAChF,OAAO,IAAI,UAAU,CAAC;QACpB,IAAI;QACJ,OAAO,EAAE,GAAG,OAAO,UAAU,WAAW,IAAI;QAC5C,IAAI,EACF,WAAW,CAAC,MAAM,KAAK,CAAC;YACtB,CAAC,CAAC,SAAS,WAAW,wBAAwB,MAAM,EAAE;YACtD,CAAC,CAAC,gBAAgB,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,KAAK,UAAU,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG;KAC3F,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,UAAsB,EACtB,IAAY,EACZ,WAA8B;IAE9B,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,mBAAmB,IAAI,GAAG;QACnC,WAAW;QACX,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACpC,mBAAmB,CAAC,UAAU,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CACzD;QACD,MAAM,EAAE,SAAS;KAClB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,IAAY,EACZ,WAA8B;IAE9B,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,oBAAoB,IAAI,GAAG;QACpC,WAAW;QACX,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,WAAW,IAAI,UAAU,EAAE,CAAC;QAC5E,MAAM,EAAE,UAAU;KACnB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,WAAmB,EAAE,OAAe;IACpE,OAAO,IAAI,UAAU,CAAC;QACpB,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,SAAS,WAAW,qCAAqC;KAChE,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "name": "@duyquangnvx/agent-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "Runtime for agent-first command-line tools: owns parsing, output, errors and exit codes.",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22.12.0"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "CHANGELOG.md"
18
+ ],
19
+ "peerDependencies": {
20
+ "zod": "^4.6.0"
21
+ },
22
+ "devDependencies": {
23
+ "zod": "4.6.7"
24
+ },
25
+ "publishConfig": {
26
+ "registry": "https://registry.npmjs.org/",
27
+ "access": "public"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc -p tsconfig.build.json"
31
+ }
6
32
  }