agentplane 0.1.3 → 0.1.5

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 (86) hide show
  1. package/README.md +51 -30
  2. package/dist/agents/agents-template.d.ts.map +1 -0
  3. package/dist/{agents-template.js → agents/agents-template.js} +2 -2
  4. package/dist/{task-backend.d.ts → backends/task-backend.d.ts} +5 -3
  5. package/dist/backends/task-backend.d.ts.map +1 -0
  6. package/dist/{task-backend.js → backends/task-backend.js} +139 -156
  7. package/dist/backends/task-index.d.ts +16 -0
  8. package/dist/backends/task-index.d.ts.map +1 -0
  9. package/dist/backends/task-index.js +84 -0
  10. package/dist/cli/archive.d.ts +16 -0
  11. package/dist/cli/archive.d.ts.map +1 -0
  12. package/dist/cli/archive.js +149 -0
  13. package/dist/cli/checksum.d.ts +3 -0
  14. package/dist/cli/checksum.d.ts.map +1 -0
  15. package/dist/cli/checksum.js +12 -0
  16. package/dist/cli/command-guide.d.ts.map +1 -0
  17. package/dist/cli/error-map.d.ts +4 -0
  18. package/dist/cli/error-map.d.ts.map +1 -0
  19. package/dist/cli/error-map.js +42 -0
  20. package/dist/cli/exit-codes.d.ts +3 -0
  21. package/dist/cli/exit-codes.d.ts.map +1 -0
  22. package/dist/cli/exit-codes.js +12 -0
  23. package/dist/cli/help.d.ts.map +1 -0
  24. package/dist/{help.js → cli/help.js} +1 -1
  25. package/dist/cli/http.d.ts +4 -0
  26. package/dist/cli/http.d.ts.map +1 -0
  27. package/dist/cli/http.js +95 -0
  28. package/dist/cli/output.d.ts +16 -0
  29. package/dist/cli/output.d.ts.map +1 -0
  30. package/dist/cli/output.js +47 -0
  31. package/dist/cli/recipes-bundled.js +2 -2
  32. package/dist/cli/run-cli.d.ts.map +1 -0
  33. package/dist/cli/run-cli.js +2681 -0
  34. package/dist/{run-cli.test-helpers.d.ts → cli/run-cli.test-helpers.d.ts} +6 -0
  35. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -0
  36. package/dist/{run-cli.test-helpers.js → cli/run-cli.test-helpers.js} +67 -0
  37. package/dist/cli/update-check.d.ts +31 -0
  38. package/dist/cli/update-check.d.ts.map +1 -0
  39. package/dist/cli/update-check.js +86 -0
  40. package/dist/cli.js +1 -1
  41. package/dist/commands/backend.d.ts +15 -0
  42. package/dist/commands/backend.d.ts.map +1 -0
  43. package/dist/commands/backend.js +211 -0
  44. package/dist/commands/recipes.d.ts +13 -0
  45. package/dist/commands/recipes.d.ts.map +1 -0
  46. package/dist/commands/recipes.js +1919 -0
  47. package/dist/commands/upgrade.d.ts +6 -0
  48. package/dist/commands/upgrade.d.ts.map +1 -0
  49. package/dist/commands/upgrade.js +291 -0
  50. package/dist/commands/workflow.d.ts +367 -0
  51. package/dist/commands/workflow.d.ts.map +1 -0
  52. package/dist/commands/workflow.js +4619 -0
  53. package/dist/meta/version.d.ts.map +1 -0
  54. package/dist/meta/version.js +20 -0
  55. package/dist/recipes/bundled-recipes.d.ts.map +1 -0
  56. package/dist/shared/comment-format.d.ts.map +1 -0
  57. package/dist/shared/env.d.ts.map +1 -0
  58. package/dist/{errors.d.ts → shared/errors.d.ts} +1 -3
  59. package/dist/shared/errors.d.ts.map +1 -0
  60. package/dist/{errors.js → shared/errors.js} +1 -3
  61. package/package.json +6 -2
  62. package/dist/agents-template.d.ts.map +0 -1
  63. package/dist/bundled-recipes.d.ts.map +0 -1
  64. package/dist/command-guide.d.ts.map +0 -1
  65. package/dist/comment-format.d.ts.map +0 -1
  66. package/dist/env.d.ts.map +0 -1
  67. package/dist/errors.d.ts.map +0 -1
  68. package/dist/help.d.ts.map +0 -1
  69. package/dist/run-cli.d.ts.map +0 -1
  70. package/dist/run-cli.js +0 -9431
  71. package/dist/run-cli.test-helpers.d.ts.map +0 -1
  72. package/dist/task-backend.d.ts.map +0 -1
  73. package/dist/version.d.ts.map +0 -1
  74. package/dist/version.js +0 -3
  75. /package/dist/{agents-template.d.ts → agents/agents-template.d.ts} +0 -0
  76. /package/dist/{command-guide.d.ts → cli/command-guide.d.ts} +0 -0
  77. /package/dist/{command-guide.js → cli/command-guide.js} +0 -0
  78. /package/dist/{help.d.ts → cli/help.d.ts} +0 -0
  79. /package/dist/{run-cli.d.ts → cli/run-cli.d.ts} +0 -0
  80. /package/dist/{version.d.ts → meta/version.d.ts} +0 -0
  81. /package/dist/{bundled-recipes.d.ts → recipes/bundled-recipes.d.ts} +0 -0
  82. /package/dist/{bundled-recipes.js → recipes/bundled-recipes.js} +0 -0
  83. /package/dist/{comment-format.d.ts → shared/comment-format.d.ts} +0 -0
  84. /package/dist/{comment-format.js → shared/comment-format.js} +0 -0
  85. /package/dist/{env.d.ts → shared/env.d.ts} +0 -0
  86. /package/dist/{env.js → shared/env.js} +0 -0
@@ -0,0 +1,84 @@
1
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ export const TASK_INDEX_SCHEMA_VERSION = 1;
4
+ const TASK_INDEX_FILENAME = "tasks-index.v1.json";
5
+ export function resolveTaskIndexPath(tasksDir) {
6
+ const normalized = path.normalize(tasksDir);
7
+ const parts = normalized.split(path.sep);
8
+ const tail = parts.slice(-2).join(path.sep);
9
+ if (tail === path.join(".agentplane", "tasks")) {
10
+ const cacheDir = path.join(path.dirname(tasksDir), "cache");
11
+ return path.join(cacheDir, TASK_INDEX_FILENAME);
12
+ }
13
+ const cacheDir = path.join(tasksDir, ".cache");
14
+ return path.join(cacheDir, TASK_INDEX_FILENAME);
15
+ }
16
+ function isRecord(value) {
17
+ return !!value && typeof value === "object" && !Array.isArray(value);
18
+ }
19
+ function isTaskIndexEntry(value) {
20
+ if (!isRecord(value))
21
+ return false;
22
+ if (!isRecord(value.task))
23
+ return false;
24
+ if (typeof value.readmePath !== "string")
25
+ return false;
26
+ if (typeof value.mtimeMs !== "number")
27
+ return false;
28
+ const task = value.task;
29
+ if (typeof task.id !== "string")
30
+ return false;
31
+ if (typeof task.title !== "string")
32
+ return false;
33
+ if (typeof task.description !== "string")
34
+ return false;
35
+ if (typeof task.status !== "string")
36
+ return false;
37
+ if (typeof task.owner !== "string")
38
+ return false;
39
+ if (!Array.isArray(task.depends_on))
40
+ return false;
41
+ if (!Array.isArray(task.tags))
42
+ return false;
43
+ if (!Array.isArray(task.verify))
44
+ return false;
45
+ return true;
46
+ }
47
+ export async function loadTaskIndex(indexPath) {
48
+ let raw = "";
49
+ try {
50
+ raw = await readFile(indexPath, "utf8");
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(raw);
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ if (!isRecord(parsed))
63
+ return null;
64
+ if (parsed.schema_version !== TASK_INDEX_SCHEMA_VERSION)
65
+ return null;
66
+ if (!Array.isArray(parsed.tasks))
67
+ return null;
68
+ const tasks = parsed.tasks.filter((entry) => isTaskIndexEntry(entry));
69
+ return { schema_version: TASK_INDEX_SCHEMA_VERSION, tasks };
70
+ }
71
+ export async function saveTaskIndex(indexPath, index) {
72
+ const dir = path.dirname(indexPath);
73
+ await mkdir(dir, { recursive: true });
74
+ const tmpPath = `${indexPath}.tmp-${process.pid}`;
75
+ await writeFile(tmpPath, `${JSON.stringify(index, null, 2)}\n`, "utf8");
76
+ await rename(tmpPath, indexPath);
77
+ }
78
+ export function buildTaskIndexEntry(task, readmePath, mtimeMs) {
79
+ return {
80
+ task,
81
+ readmePath,
82
+ mtimeMs,
83
+ };
84
+ }
@@ -0,0 +1,16 @@
1
+ type ArchiveType = "tar" | "zip";
2
+ export type ArchiveEntryIssue = {
3
+ entry: string;
4
+ reason: string;
5
+ };
6
+ export declare function validateArchive(archivePath: string, type: ArchiveType): Promise<ArchiveEntryIssue[]>;
7
+ export declare function detectArchiveType(filePath: string): ArchiveType | null;
8
+ export declare function extractArchive(opts: {
9
+ archivePath: string;
10
+ destDir: string;
11
+ usage: string;
12
+ example?: string;
13
+ }): Promise<void>;
14
+ export declare function validateArchiveEntries(entries: string[], symlinks: string[]): ArchiveEntryIssue[];
15
+ export {};
16
+ //# sourceMappingURL=archive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/cli/archive.ts"],"names":[],"mappings":"AAYA,KAAK,WAAW,GAAG,KAAK,GAAG,KAAK,CAAC;AAOjC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAU9B;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAKtE;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhB;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE,CA2BjG"}
@@ -0,0 +1,149 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import path from "node:path";
4
+ import yauzl from "yauzl";
5
+ import { CliError } from "../shared/errors.js";
6
+ import { exitCodeForError } from "./exit-codes.js";
7
+ import { usageMessage } from "./output.js";
8
+ const execFileAsync = promisify(execFile);
9
+ export async function validateArchive(archivePath, type) {
10
+ if (type === "zip") {
11
+ const entries = await listZipEntries(archivePath);
12
+ const entryNames = entries.map((entry) => entry.name);
13
+ const symlinks = entries.filter((entry) => entry.isSymlink).map((entry) => entry.name);
14
+ return validateArchiveEntries(entryNames, symlinks);
15
+ }
16
+ const entries = await listArchiveEntries(archivePath, type);
17
+ const symlinks = await listArchiveSymlinks(archivePath, type);
18
+ return validateArchiveEntries(entries, symlinks);
19
+ }
20
+ export function detectArchiveType(filePath) {
21
+ const lower = filePath.toLowerCase();
22
+ if (lower.endsWith(".tar.gz") || lower.endsWith(".tgz"))
23
+ return "tar";
24
+ if (lower.endsWith(".zip"))
25
+ return "zip";
26
+ return null;
27
+ }
28
+ export async function extractArchive(opts) {
29
+ const archiveType = detectArchiveType(opts.archivePath);
30
+ if (!archiveType) {
31
+ throw new CliError({
32
+ exitCode: 2,
33
+ code: "E_USAGE",
34
+ message: usageMessage(opts.usage, opts.example),
35
+ });
36
+ }
37
+ const issues = await validateArchive(opts.archivePath, archiveType);
38
+ if (issues.length > 0) {
39
+ const first = issues[0];
40
+ const suffix = issues.length > 1 ? ` (+${issues.length - 1} more)` : "";
41
+ throw new CliError({
42
+ exitCode: exitCodeForError("E_VALIDATION"),
43
+ code: "E_VALIDATION",
44
+ message: `Unsafe archive entry: ${first.entry} (${first.reason})${suffix}`,
45
+ });
46
+ }
47
+ if (archiveType === "tar") {
48
+ await execFileAsync("tar", ["-xzf", opts.archivePath, "-C", opts.destDir]);
49
+ return;
50
+ }
51
+ await execFileAsync("unzip", ["-q", opts.archivePath, "-d", opts.destDir]);
52
+ }
53
+ export function validateArchiveEntries(entries, symlinks) {
54
+ const issues = [];
55
+ const symlinkSet = new Set(symlinks);
56
+ for (const rawEntry of entries) {
57
+ const entry = rawEntry.replaceAll("\\", "/");
58
+ if (entry.includes("\u0000")) {
59
+ issues.push({ entry: rawEntry, reason: "null byte" });
60
+ continue;
61
+ }
62
+ if (entry.startsWith("/") || entry.startsWith("\\")) {
63
+ issues.push({ entry: rawEntry, reason: "absolute path" });
64
+ continue;
65
+ }
66
+ if (/^[A-Za-z]:/.test(entry)) {
67
+ issues.push({ entry: rawEntry, reason: "drive letter path" });
68
+ continue;
69
+ }
70
+ const normalized = path.posix.normalize(entry);
71
+ if (normalized === ".." || normalized.startsWith("../")) {
72
+ issues.push({ entry: rawEntry, reason: "path traversal" });
73
+ continue;
74
+ }
75
+ if (symlinkSet.has(rawEntry) || symlinkSet.has(entry) || symlinkSet.has(normalized)) {
76
+ issues.push({ entry: rawEntry, reason: "symlink entry" });
77
+ }
78
+ }
79
+ return issues;
80
+ }
81
+ async function listArchiveEntries(archivePath, type) {
82
+ if (type === "tar") {
83
+ const { stdout } = await execFileAsync("tar", ["-tzf", archivePath]);
84
+ return stdout
85
+ .split("\n")
86
+ .map((line) => line.trim())
87
+ .filter((line) => line.length > 0);
88
+ }
89
+ const { stdout } = await execFileAsync("unzip", ["-Z1", archivePath]);
90
+ return stdout
91
+ .split("\n")
92
+ .map((line) => line.trim())
93
+ .filter((line) => line.length > 0);
94
+ }
95
+ async function listArchiveSymlinks(archivePath, type) {
96
+ if (type === "tar") {
97
+ const { stdout } = await execFileAsync("tar", ["-tvzf", archivePath]);
98
+ return stdout
99
+ .split("\n")
100
+ .map((line) => line.trim())
101
+ .filter((line) => line.startsWith("l"))
102
+ .map((line) => {
103
+ const arrowIndex = line.indexOf(" -> ");
104
+ const left = arrowIndex === -1 ? line : line.slice(0, arrowIndex);
105
+ const tokens = left.trim().split(/\s+/);
106
+ return tokens.at(-1) ?? "";
107
+ })
108
+ .filter((entry) => entry.length > 0);
109
+ }
110
+ const { stdout } = await execFileAsync("unzip", ["-Z", "-v", archivePath]);
111
+ return stdout
112
+ .split("\n")
113
+ .map((line) => line.trim())
114
+ .filter((line) => /\bsymlink\b/i.test(line) || /\blrwx/.test(line))
115
+ .map((line) => line.split(/\s+/).at(-1) ?? "")
116
+ .filter((entry) => entry.length > 0);
117
+ }
118
+ function listZipEntries(archivePath) {
119
+ return new Promise((resolve, reject) => {
120
+ yauzl.open(archivePath, { lazyEntries: true }, (openErr, zipfile) => {
121
+ if (openErr || !zipfile) {
122
+ reject(openErr ?? new Error("Failed to open zip archive"));
123
+ return;
124
+ }
125
+ const entries = [];
126
+ zipfile.readEntry();
127
+ zipfile.on("entry", (entry) => {
128
+ entries.push({
129
+ name: entry.fileName,
130
+ isSymlink: isZipEntrySymlink(entry),
131
+ });
132
+ zipfile.readEntry();
133
+ });
134
+ zipfile.on("end", () => {
135
+ zipfile.close();
136
+ resolve(entries);
137
+ });
138
+ zipfile.on("error", (err) => {
139
+ zipfile.close();
140
+ reject(err);
141
+ });
142
+ });
143
+ });
144
+ }
145
+ function isZipEntrySymlink(entry) {
146
+ const attrs = entry.externalFileAttributes >>> 16;
147
+ const fileType = attrs & 0xf0_00;
148
+ return fileType === 0xa0_00;
149
+ }
@@ -0,0 +1,3 @@
1
+ export declare function sha256File(filePath: string): Promise<string>;
2
+ export declare function parseSha256Text(text: string): string;
3
+ //# sourceMappingURL=checksum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checksum.d.ts","sourceRoot":"","sources":["../../src/cli/checksum.ts"],"names":[],"mappings":"AAGA,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIpD"}
@@ -0,0 +1,12 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFile } from "node:fs/promises";
3
+ export async function sha256File(filePath) {
4
+ const data = await readFile(filePath);
5
+ return createHash("sha256").update(data).digest("hex");
6
+ }
7
+ export function parseSha256Text(text) {
8
+ const trimmed = text.trim();
9
+ if (!trimmed)
10
+ return "";
11
+ return trimmed.split(/\s+/)[0];
12
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-guide.d.ts","sourceRoot":"","sources":["../../src/cli/command-guide.ts"],"names":[],"mappings":"AA4KA,wBAAgB,SAAS,IAAI,MAAM,EAAE,CAEpC;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOzD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CA4EzC"}
@@ -0,0 +1,4 @@
1
+ import { CliError } from "../shared/errors.js";
2
+ export declare function mapCoreError(err: unknown, context: Record<string, unknown>): CliError;
3
+ export declare function mapBackendError(err: unknown, context: Record<string, unknown>): CliError;
4
+ //# sourceMappingURL=error-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-map.d.ts","sourceRoot":"","sources":["../../src/cli/error-map.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CA+BrF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CAUxF"}
@@ -0,0 +1,42 @@
1
+ import { exitCodeForError } from "./exit-codes.js";
2
+ import { CliError } from "../shared/errors.js";
3
+ import { BackendError } from "../backends/task-backend.js";
4
+ export function mapCoreError(err, context) {
5
+ const message = err instanceof Error ? err.message : String(err);
6
+ if (message.startsWith("Not a git repository")) {
7
+ return new CliError({
8
+ exitCode: exitCodeForError("E_GIT"),
9
+ code: "E_GIT",
10
+ message,
11
+ context,
12
+ });
13
+ }
14
+ if (err instanceof SyntaxError) {
15
+ return new CliError({
16
+ exitCode: exitCodeForError("E_VALIDATION"),
17
+ code: "E_VALIDATION",
18
+ message: `Invalid JSON: ${message}`,
19
+ context,
20
+ });
21
+ }
22
+ if (message.includes("schema_version") || message.startsWith("config.")) {
23
+ return new CliError({
24
+ exitCode: exitCodeForError("E_VALIDATION"),
25
+ code: "E_VALIDATION",
26
+ message,
27
+ context,
28
+ });
29
+ }
30
+ return new CliError({ exitCode: exitCodeForError("E_IO"), code: "E_IO", message, context });
31
+ }
32
+ export function mapBackendError(err, context) {
33
+ if (err instanceof BackendError) {
34
+ return new CliError({
35
+ exitCode: exitCodeForError(err.code),
36
+ code: err.code,
37
+ message: err.message,
38
+ context,
39
+ });
40
+ }
41
+ return mapCoreError(err, context);
42
+ }
@@ -0,0 +1,3 @@
1
+ import type { ErrorCode } from "../shared/errors.js";
2
+ export declare function exitCodeForError(code: ErrorCode): number;
3
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../../src/cli/exit-codes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAYrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAExD"}
@@ -0,0 +1,12 @@
1
+ const EXIT_CODE_BY_ERROR = {
2
+ E_USAGE: 2,
3
+ E_VALIDATION: 3,
4
+ E_IO: 4,
5
+ E_GIT: 5,
6
+ E_BACKEND: 6,
7
+ E_NETWORK: 7,
8
+ E_INTERNAL: 1,
9
+ };
10
+ export function exitCodeForError(code) {
11
+ return EXIT_CODE_BY_ERROR[code];
12
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,IAAI,MAAM,CA4HnC"}
@@ -18,7 +18,7 @@ export function renderHelp() {
18
18
  " agentplane quickstart",
19
19
  "",
20
20
  "Init commands:",
21
- " agentplane init [--ide <codex|cursor|windsurf>] [--workflow <direct|branch_pr>] [--hooks <yes|no>] [--require-plan-approval <yes|no>] [--require-network-approval <yes|no>] [--recipes <list>] [--yes] [--force|--backup]",
21
+ " agentplane init [--ide <codex|cursor|windsurf>] [--workflow <direct|branch_pr>] [--hooks <yes|no>] [--require-plan-approval <yes|no>] [--require-network-approval <yes|no>] [--require-verify-approval <yes|no>] [--recipes <list>] [--yes] [--force|--backup]",
22
22
  "",
23
23
  "Upgrade commands:",
24
24
  " agentplane upgrade [--tag <tag>] [--dry-run] [--no-backup] [--source <repo-url>] [--bundle <path|url>] [--checksum <path|url>]",
@@ -0,0 +1,4 @@
1
+ export declare function fetchJson(url: string, timeoutMs?: number): Promise<unknown>;
2
+ export declare function fetchText(url: string, timeoutMs?: number): Promise<string>;
3
+ export declare function downloadToFile(url: string, destPath: string, timeoutMs?: number): Promise<void>;
4
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/cli/http.ts"],"names":[],"mappings":"AAOA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAqB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0B7F;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B5F;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
@@ -0,0 +1,95 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { exitCodeForError } from "./exit-codes.js";
3
+ import { CliError } from "../shared/errors.js";
4
+ const DEFAULT_TIMEOUT_MS = 1500;
5
+ export async function fetchJson(url, timeoutMs = DEFAULT_TIMEOUT_MS) {
6
+ const controller = new AbortController();
7
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
8
+ try {
9
+ const res = await fetch(url, {
10
+ headers: { "User-Agent": "agentplane" },
11
+ signal: controller.signal,
12
+ });
13
+ if (!res.ok) {
14
+ throw new CliError({
15
+ exitCode: exitCodeForError("E_NETWORK"),
16
+ code: "E_NETWORK",
17
+ message: `Failed to fetch ${url} (${res.status} ${res.statusText})`,
18
+ });
19
+ }
20
+ return await res.json();
21
+ }
22
+ catch (err) {
23
+ if (err instanceof CliError)
24
+ throw err;
25
+ throw new CliError({
26
+ exitCode: exitCodeForError("E_NETWORK"),
27
+ code: "E_NETWORK",
28
+ message: `Failed to fetch ${url}`,
29
+ });
30
+ }
31
+ finally {
32
+ clearTimeout(timeout);
33
+ }
34
+ }
35
+ export async function fetchText(url, timeoutMs = DEFAULT_TIMEOUT_MS) {
36
+ const controller = new AbortController();
37
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
38
+ try {
39
+ const res = await fetch(url, {
40
+ headers: { "User-Agent": "agentplane" },
41
+ signal: controller.signal,
42
+ });
43
+ if (!res.ok) {
44
+ throw new CliError({
45
+ exitCode: exitCodeForError("E_NETWORK"),
46
+ code: "E_NETWORK",
47
+ message: `Failed to fetch ${url} (${res.status} ${res.statusText})`,
48
+ });
49
+ }
50
+ return await res.text();
51
+ }
52
+ catch (err) {
53
+ if (err instanceof CliError)
54
+ throw err;
55
+ throw new CliError({
56
+ exitCode: exitCodeForError("E_NETWORK"),
57
+ code: "E_NETWORK",
58
+ message: `Failed to fetch ${url}`,
59
+ });
60
+ }
61
+ finally {
62
+ clearTimeout(timeout);
63
+ }
64
+ }
65
+ export async function downloadToFile(url, destPath, timeoutMs = DEFAULT_TIMEOUT_MS) {
66
+ const controller = new AbortController();
67
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
68
+ try {
69
+ const res = await fetch(url, {
70
+ headers: { "User-Agent": "agentplane" },
71
+ signal: controller.signal,
72
+ });
73
+ if (!res.ok) {
74
+ throw new CliError({
75
+ exitCode: exitCodeForError("E_NETWORK"),
76
+ code: "E_NETWORK",
77
+ message: `Failed to download ${url} (${res.status} ${res.statusText})`,
78
+ });
79
+ }
80
+ const buffer = Buffer.from(await res.arrayBuffer());
81
+ await writeFile(destPath, buffer);
82
+ }
83
+ catch (err) {
84
+ if (err instanceof CliError)
85
+ throw err;
86
+ throw new CliError({
87
+ exitCode: exitCodeForError("E_NETWORK"),
88
+ code: "E_NETWORK",
89
+ message: `Failed to download ${url}`,
90
+ });
91
+ }
92
+ finally {
93
+ clearTimeout(timeout);
94
+ }
95
+ }
@@ -0,0 +1,16 @@
1
+ export declare function successMessage(action: string, target?: string, details?: string): string;
2
+ export declare function infoMessage(message: string): string;
3
+ export declare function warnMessage(message: string): string;
4
+ export declare function usageMessage(usage: string, example?: string): string;
5
+ export declare function backendNotSupportedMessage(feature: string): string;
6
+ export declare function missingValueMessage(flag: string): string;
7
+ export declare function invalidValueMessage(label: string, value: string, expected: string): string;
8
+ export declare function invalidValueForFlag(flag: string, value: string, expected: string): string;
9
+ export declare function unknownEntityMessage(entity: string, value: string): string;
10
+ export declare function emptyStateMessage(resource: string, hint?: string): string;
11
+ export declare function requiredFieldMessage(field: string, source?: string): string;
12
+ export declare function invalidFieldMessage(field: string, expected: string, source?: string): string;
13
+ export declare function invalidPathMessage(field: string, reason: string, source?: string): string;
14
+ export declare function missingFileMessage(filename: string, rootHint?: string): string;
15
+ export declare function workflowModeMessage(actual: string | undefined, expected: string): string;
16
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAIxF;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1F;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExF"}
@@ -0,0 +1,47 @@
1
+ export function successMessage(action, target, details) {
2
+ const base = target ? `${action} ${target}` : action;
3
+ const suffix = details ? ` (${details})` : "";
4
+ return `✅ ${base}${suffix}`;
5
+ }
6
+ export function infoMessage(message) {
7
+ return `ℹ️ ${message}`;
8
+ }
9
+ export function warnMessage(message) {
10
+ return `⚠️ ${message}`;
11
+ }
12
+ export function usageMessage(usage, example) {
13
+ return example ? `${usage}\nExample: ${example}` : usage;
14
+ }
15
+ export function backendNotSupportedMessage(feature) {
16
+ return `Backend does not support ${feature}`;
17
+ }
18
+ export function missingValueMessage(flag) {
19
+ return `Missing value for ${flag} (expected value after flag)`;
20
+ }
21
+ export function invalidValueMessage(label, value, expected) {
22
+ return `Invalid ${label}: ${value} (expected ${expected})`;
23
+ }
24
+ export function invalidValueForFlag(flag, value, expected) {
25
+ return invalidValueMessage(`value for ${flag}`, value, expected);
26
+ }
27
+ export function unknownEntityMessage(entity, value) {
28
+ return `Unknown ${entity}: ${value}`;
29
+ }
30
+ export function emptyStateMessage(resource, hint) {
31
+ return `No ${resource} found.${hint ? ` ${hint}` : ""}`;
32
+ }
33
+ export function requiredFieldMessage(field, source) {
34
+ return `Missing required field: ${field}${source ? ` (${source})` : ""}`;
35
+ }
36
+ export function invalidFieldMessage(field, expected, source) {
37
+ return `Invalid field ${field}: expected ${expected}${source ? ` (${source})` : ""}`;
38
+ }
39
+ export function invalidPathMessage(field, reason, source) {
40
+ return `Invalid ${field}: ${reason}${source ? ` (${source})` : ""}`;
41
+ }
42
+ export function missingFileMessage(filename, rootHint) {
43
+ return `Missing ${filename}${rootHint ? ` at ${rootHint}` : ""}`;
44
+ }
45
+ export function workflowModeMessage(actual, expected) {
46
+ return `Invalid workflow_mode: ${actual ?? "unknown"} (expected ${expected})`;
47
+ }
@@ -1,5 +1,5 @@
1
- import { BUNDLED_RECIPES_CATALOG } from "../bundled-recipes.js";
2
- import { CliError } from "../errors.js";
1
+ import { BUNDLED_RECIPES_CATALOG } from "../recipes/bundled-recipes.js";
2
+ import { CliError } from "../shared/errors.js";
3
3
  export function listBundledRecipes() {
4
4
  return BUNDLED_RECIPES_CATALOG.recipes.map((recipe) => ({
5
5
  id: recipe.id,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.ts"],"names":[],"mappings":"AA0iCA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA62D5D"}