agentplane 0.1.4 → 0.1.6

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 (85) hide show
  1. package/dist/agents/agents-template.d.ts.map +1 -0
  2. package/dist/{agents-template.js → agents/agents-template.js} +2 -2
  3. package/dist/{task-backend.d.ts → backends/task-backend.d.ts} +5 -3
  4. package/dist/backends/task-backend.d.ts.map +1 -0
  5. package/dist/{task-backend.js → backends/task-backend.js} +102 -268
  6. package/dist/backends/task-index.d.ts +16 -0
  7. package/dist/backends/task-index.d.ts.map +1 -0
  8. package/dist/backends/task-index.js +84 -0
  9. package/dist/cli/archive.d.ts +16 -0
  10. package/dist/cli/archive.d.ts.map +1 -0
  11. package/dist/cli/archive.js +149 -0
  12. package/dist/cli/checksum.d.ts +3 -0
  13. package/dist/cli/checksum.d.ts.map +1 -0
  14. package/dist/cli/checksum.js +12 -0
  15. package/dist/cli/command-guide.d.ts.map +1 -0
  16. package/dist/cli/error-map.d.ts +4 -0
  17. package/dist/cli/error-map.d.ts.map +1 -0
  18. package/dist/cli/error-map.js +42 -0
  19. package/dist/cli/exit-codes.d.ts +3 -0
  20. package/dist/cli/exit-codes.d.ts.map +1 -0
  21. package/dist/cli/exit-codes.js +12 -0
  22. package/dist/cli/help.d.ts.map +1 -0
  23. package/dist/{help.js → cli/help.js} +1 -1
  24. package/dist/cli/http.d.ts +4 -0
  25. package/dist/cli/http.d.ts.map +1 -0
  26. package/dist/cli/http.js +95 -0
  27. package/dist/cli/output.d.ts +16 -0
  28. package/dist/cli/output.d.ts.map +1 -0
  29. package/dist/cli/output.js +47 -0
  30. package/dist/cli/recipes-bundled.js +2 -2
  31. package/dist/cli/run-cli.d.ts.map +1 -0
  32. package/dist/cli/run-cli.js +2681 -0
  33. package/dist/{run-cli.test-helpers.d.ts → cli/run-cli.test-helpers.d.ts} +6 -0
  34. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -0
  35. package/dist/{run-cli.test-helpers.js → cli/run-cli.test-helpers.js} +67 -0
  36. package/dist/cli/update-check.d.ts +31 -0
  37. package/dist/cli/update-check.d.ts.map +1 -0
  38. package/dist/cli/update-check.js +86 -0
  39. package/dist/cli.js +1 -1
  40. package/dist/commands/backend.d.ts +15 -0
  41. package/dist/commands/backend.d.ts.map +1 -0
  42. package/dist/commands/backend.js +211 -0
  43. package/dist/commands/recipes.d.ts +13 -0
  44. package/dist/commands/recipes.d.ts.map +1 -0
  45. package/dist/commands/recipes.js +1919 -0
  46. package/dist/commands/upgrade.d.ts +6 -0
  47. package/dist/commands/upgrade.d.ts.map +1 -0
  48. package/dist/commands/upgrade.js +291 -0
  49. package/dist/commands/workflow.d.ts +367 -0
  50. package/dist/commands/workflow.d.ts.map +1 -0
  51. package/dist/commands/workflow.js +4619 -0
  52. package/dist/meta/version.d.ts.map +1 -0
  53. package/dist/meta/version.js +20 -0
  54. package/dist/recipes/bundled-recipes.d.ts.map +1 -0
  55. package/dist/shared/comment-format.d.ts.map +1 -0
  56. package/dist/shared/env.d.ts.map +1 -0
  57. package/dist/{errors.d.ts → shared/errors.d.ts} +1 -3
  58. package/dist/shared/errors.d.ts.map +1 -0
  59. package/dist/{errors.js → shared/errors.js} +1 -3
  60. package/package.json +6 -2
  61. package/dist/agents-template.d.ts.map +0 -1
  62. package/dist/bundled-recipes.d.ts.map +0 -1
  63. package/dist/command-guide.d.ts.map +0 -1
  64. package/dist/comment-format.d.ts.map +0 -1
  65. package/dist/env.d.ts.map +0 -1
  66. package/dist/errors.d.ts.map +0 -1
  67. package/dist/help.d.ts.map +0 -1
  68. package/dist/run-cli.d.ts.map +0 -1
  69. package/dist/run-cli.js +0 -9454
  70. package/dist/run-cli.test-helpers.d.ts.map +0 -1
  71. package/dist/task-backend.d.ts.map +0 -1
  72. package/dist/version.d.ts.map +0 -1
  73. package/dist/version.js +0 -3
  74. /package/dist/{agents-template.d.ts → agents/agents-template.d.ts} +0 -0
  75. /package/dist/{command-guide.d.ts → cli/command-guide.d.ts} +0 -0
  76. /package/dist/{command-guide.js → cli/command-guide.js} +0 -0
  77. /package/dist/{help.d.ts → cli/help.d.ts} +0 -0
  78. /package/dist/{run-cli.d.ts → cli/run-cli.d.ts} +0 -0
  79. /package/dist/{version.d.ts → meta/version.d.ts} +0 -0
  80. /package/dist/{bundled-recipes.d.ts → recipes/bundled-recipes.d.ts} +0 -0
  81. /package/dist/{bundled-recipes.js → recipes/bundled-recipes.js} +0 -0
  82. /package/dist/{comment-format.d.ts → shared/comment-format.d.ts} +0 -0
  83. /package/dist/{comment-format.js → shared/comment-format.js} +0 -0
  84. /package/dist/{env.d.ts → shared/env.d.ts} +0 -0
  85. /package/dist/{env.js → shared/env.js} +0 -0
@@ -0,0 +1,2681 @@
1
+ import { mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { defaultConfig, findGitRoot, getStagedFiles, loadConfig, resolveProject, saveConfig, setByDottedKey, } from "@agentplaneorg/core";
5
+ import { renderHelp } from "./help.js";
6
+ import { listRoles, renderQuickstart, renderRole } from "./command-guide.js";
7
+ import { filterAgentsByWorkflow, loadAgentTemplates, loadAgentsTemplate, } from "../agents/agents-template.js";
8
+ import { backupPath, fileExists, getPathKind } from "./fs-utils.js";
9
+ import { promptChoice, promptInput, promptYesNo } from "./prompts.js";
10
+ import { listBundledRecipes, renderBundledRecipesHint, validateBundledRecipesSelection, } from "./recipes-bundled.js";
11
+ import { mapCoreError } from "./error-map.js";
12
+ import { infoMessage, invalidValueForFlag, missingValueMessage, usageMessage, warnMessage, } from "./output.js";
13
+ import { fetchLatestNpmVersion, readUpdateCheckCache, resolveUpdateCheckCachePath, shouldCheckNow, UPDATE_CHECK_SCHEMA_VERSION, UPDATE_CHECK_TIMEOUT_MS, UPDATE_CHECK_TTL_MS, writeUpdateCheckCache, } from "./update-check.js";
14
+ import { loadDotEnv } from "../shared/env.js";
15
+ import { CliError, formatJsonError } from "../shared/errors.js";
16
+ import { getVersion } from "../meta/version.js";
17
+ import { cmdUpgrade } from "../commands/upgrade.js";
18
+ import { BACKEND_SYNC_USAGE, BACKEND_SYNC_USAGE_EXAMPLE, cmdBackendSync, cmdSync, } from "../commands/backend.js";
19
+ import { cmdRecipes, cmdScenario } from "../commands/recipes.js";
20
+ import { BLOCK_USAGE, BLOCK_USAGE_EXAMPLE, BRANCH_BASE_USAGE, BRANCH_BASE_USAGE_EXAMPLE, BRANCH_REMOVE_USAGE, BRANCH_REMOVE_USAGE_EXAMPLE, BRANCH_STATUS_USAGE, BRANCH_STATUS_USAGE_EXAMPLE, CLEANUP_MERGED_USAGE, CLEANUP_MERGED_USAGE_EXAMPLE, COMMIT_USAGE, COMMIT_USAGE_EXAMPLE, FINISH_USAGE, FINISH_USAGE_EXAMPLE, GUARD_COMMIT_USAGE, GUARD_COMMIT_USAGE_EXAMPLE, HOOK_NAMES, INTEGRATE_USAGE, INTEGRATE_USAGE_EXAMPLE, PR_CHECK_USAGE, PR_CHECK_USAGE_EXAMPLE, PR_NOTE_USAGE, PR_NOTE_USAGE_EXAMPLE, PR_OPEN_USAGE, PR_OPEN_USAGE_EXAMPLE, PR_UPDATE_USAGE, PR_UPDATE_USAGE_EXAMPLE, START_USAGE, START_USAGE_EXAMPLE, TASK_DOC_SET_USAGE, TASK_DOC_SET_USAGE_EXAMPLE, TASK_DOC_SHOW_USAGE, TASK_DOC_SHOW_USAGE_EXAMPLE, VERIFY_USAGE, VERIFY_USAGE_EXAMPLE, WORK_START_USAGE, WORK_START_USAGE_EXAMPLE, cmdBlock, cmdBranchBaseGet, cmdBranchBaseSet, cmdBranchRemove, cmdBranchStatus, cmdCleanupMerged, cmdCommit, cmdFinish, cmdGuardClean, cmdGuardCommit, cmdGuardSuggestAllow, cmdHooksInstall, cmdHooksRun, cmdHooksUninstall, cmdIntegrate, cmdPrCheck, cmdPrNote, cmdPrOpen, cmdPrUpdate, cmdReady, cmdStart, cmdTaskAdd, cmdTaskComment, cmdTaskDocSet, cmdTaskDocShow, cmdTaskExport, cmdTaskLint, cmdTaskMigrate, cmdTaskNew, cmdTaskNext, cmdTaskNormalize, cmdTaskScaffold, cmdTaskScrub, cmdTaskSearch, cmdTaskSetStatus, cmdTaskShow, cmdTaskUpdate, cmdTaskList, cmdVerify, cmdWorkStart, dedupeStrings, ensureInitCommit, gitInitRepo, promptInitBaseBranch, resolveInitBaseBranch, suggestAllowPrefixes, } from "../commands/workflow.js";
21
+ function parseGlobalArgs(argv) {
22
+ let help = false;
23
+ let version = false;
24
+ let noUpdateCheck = false;
25
+ let jsonErrors = false;
26
+ let root;
27
+ const rest = [];
28
+ for (let i = 0; i < argv.length; i++) {
29
+ const arg = argv[i];
30
+ if (!arg)
31
+ continue;
32
+ if (arg === "--help" || arg === "-h") {
33
+ help = true;
34
+ continue;
35
+ }
36
+ if (arg === "--version" || arg === "-v") {
37
+ version = true;
38
+ continue;
39
+ }
40
+ if (arg === "--no-update-check") {
41
+ noUpdateCheck = true;
42
+ continue;
43
+ }
44
+ if (arg === "--json") {
45
+ jsonErrors = true;
46
+ continue;
47
+ }
48
+ if (arg === "--root") {
49
+ const next = argv[i + 1];
50
+ if (!next)
51
+ throw new CliError({
52
+ exitCode: 2,
53
+ code: "E_USAGE",
54
+ message: "Missing value after --root (expected repository path)",
55
+ });
56
+ root = next;
57
+ i++;
58
+ continue;
59
+ }
60
+ rest.push(arg);
61
+ }
62
+ return { globals: { help, version, noUpdateCheck, root, jsonErrors }, rest };
63
+ }
64
+ function writeError(err, jsonErrors) {
65
+ const hint = renderErrorHint(err);
66
+ if (jsonErrors) {
67
+ process.stdout.write(`${formatJsonError(err)}\n`);
68
+ }
69
+ else {
70
+ const header = `error [${err.code}]`;
71
+ if (err.message.includes("\n")) {
72
+ process.stderr.write(`${header}\n${err.message}\n`);
73
+ }
74
+ else {
75
+ process.stderr.write(`${header}: ${err.message}\n`);
76
+ }
77
+ if (hint) {
78
+ process.stderr.write(`hint: ${hint}\n`);
79
+ }
80
+ }
81
+ }
82
+ const AGENTPLANE_HOME_ENV = "AGENTPLANE_HOME";
83
+ function resolveAgentplaneHome() {
84
+ const overridden = process.env[AGENTPLANE_HOME_ENV]?.trim();
85
+ if (overridden)
86
+ return overridden;
87
+ return path.join(os.homedir(), ".agentplane");
88
+ }
89
+ function renderErrorHint(err) {
90
+ const command = typeof err.context?.command === "string" ? err.context.command : undefined;
91
+ const usage = command ? `agentplane ${command} --help` : "agentplane --help";
92
+ switch (err.code) {
93
+ case "E_USAGE": {
94
+ return `See \`${usage}\` for usage.`;
95
+ }
96
+ case "E_GIT": {
97
+ if (command?.startsWith("branch")) {
98
+ return "Check git repo/branch; run `git branch` or pass --root <path>.";
99
+ }
100
+ if (command === "guard commit" || command === "commit") {
101
+ return "Check git status/index; stage changes and retry.";
102
+ }
103
+ return "Check git repo context; pass --root <path> if needed.";
104
+ }
105
+ case "E_NETWORK": {
106
+ return "Check network access and credentials.";
107
+ }
108
+ case "E_BACKEND": {
109
+ if (command?.includes("sync")) {
110
+ return "Check backend config under .agentplane/backends and retry.";
111
+ }
112
+ return "Check backend config under .agentplane/backends.";
113
+ }
114
+ default: {
115
+ return undefined;
116
+ }
117
+ }
118
+ }
119
+ const UPDATE_CHECK_PACKAGE = "agentplane";
120
+ const UPDATE_CHECK_URL = `https://registry.npmjs.org/${UPDATE_CHECK_PACKAGE}/latest`;
121
+ function parseVersionParts(version) {
122
+ const cleaned = version.trim().replace(/^v/i, "").split("+")[0] ?? "";
123
+ const [mainRaw, prereleaseRaw] = cleaned.split("-", 2);
124
+ const main = (mainRaw ?? "")
125
+ .split(".")
126
+ .filter((part) => part.length > 0)
127
+ .map((part) => {
128
+ const parsed = Number.parseInt(part, 10);
129
+ return Number.isFinite(parsed) ? parsed : 0;
130
+ });
131
+ return { main, prerelease: prereleaseRaw ? prereleaseRaw.trim() : null };
132
+ }
133
+ function compareVersions(left, right) {
134
+ const a = parseVersionParts(left);
135
+ const b = parseVersionParts(right);
136
+ const length = Math.max(a.main.length, b.main.length);
137
+ for (let i = 0; i < length; i++) {
138
+ const partA = a.main[i] ?? 0;
139
+ const partB = b.main[i] ?? 0;
140
+ if (partA !== partB)
141
+ return partA > partB ? 1 : -1;
142
+ }
143
+ if (a.prerelease === b.prerelease)
144
+ return 0;
145
+ if (a.prerelease === null)
146
+ return 1;
147
+ if (b.prerelease === null)
148
+ return -1;
149
+ return a.prerelease.localeCompare(b.prerelease);
150
+ }
151
+ function isTruthyEnv(value) {
152
+ if (!value)
153
+ return false;
154
+ const normalized = value.trim().toLowerCase();
155
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
156
+ }
157
+ async function maybeWarnOnUpdate(opts) {
158
+ if (opts.skip || opts.jsonErrors)
159
+ return;
160
+ if (isTruthyEnv(process.env.AGENTPLANE_NO_UPDATE_CHECK))
161
+ return;
162
+ const now = new Date();
163
+ const cachePath = resolveUpdateCheckCachePath(resolveAgentplaneHome());
164
+ const cache = await readUpdateCheckCache(cachePath);
165
+ if (cache && !shouldCheckNow(cache.checked_at, now, UPDATE_CHECK_TTL_MS)) {
166
+ if (cache.status === "ok" &&
167
+ cache.latest_version &&
168
+ compareVersions(cache.latest_version, opts.currentVersion) > 0) {
169
+ const message = `Update available: ${UPDATE_CHECK_PACKAGE} ${opts.currentVersion} → ${cache.latest_version}. Run: npm i -g ${UPDATE_CHECK_PACKAGE}@latest`;
170
+ process.stderr.write(`${warnMessage(message)}\n`);
171
+ }
172
+ return;
173
+ }
174
+ const result = await fetchLatestNpmVersion({
175
+ url: UPDATE_CHECK_URL,
176
+ timeoutMs: UPDATE_CHECK_TIMEOUT_MS,
177
+ etag: cache?.etag ?? null,
178
+ });
179
+ const nextCache = {
180
+ schema_version: UPDATE_CHECK_SCHEMA_VERSION,
181
+ checked_at: now.toISOString(),
182
+ latest_version: cache?.latest_version ?? null,
183
+ etag: cache?.etag ?? null,
184
+ status: "error",
185
+ };
186
+ if (result.status === "ok") {
187
+ nextCache.status = "ok";
188
+ nextCache.latest_version = result.latestVersion;
189
+ nextCache.etag = result.etag;
190
+ }
191
+ else if (result.status === "not_modified") {
192
+ nextCache.status = "not_modified";
193
+ nextCache.etag = result.etag ?? nextCache.etag;
194
+ }
195
+ try {
196
+ await writeUpdateCheckCache(cachePath, nextCache);
197
+ }
198
+ catch {
199
+ // Best-effort cache: ignore write failures.
200
+ }
201
+ const latest = result.status === "ok" ? result.latestVersion : nextCache.latest_version;
202
+ if (!latest || result.status === "error")
203
+ return;
204
+ if (compareVersions(latest, opts.currentVersion) <= 0)
205
+ return;
206
+ const message = `Update available: ${UPDATE_CHECK_PACKAGE} ${opts.currentVersion} → ${latest}. Run: npm i -g ${UPDATE_CHECK_PACKAGE}@latest`;
207
+ process.stderr.write(`${warnMessage(message)}\n`);
208
+ }
209
+ async function maybeLoadDotEnv(opts) {
210
+ try {
211
+ const resolved = await resolveProject({
212
+ cwd: opts.cwd,
213
+ rootOverride: opts.rootOverride ?? null,
214
+ });
215
+ await loadDotEnv(resolved.gitRoot);
216
+ }
217
+ catch (err) {
218
+ if (err instanceof Error && err.message.startsWith("Not a git repository")) {
219
+ return;
220
+ }
221
+ throw err;
222
+ }
223
+ }
224
+ async function writeFileIfChanged(filePath, content) {
225
+ try {
226
+ const existing = await readFile(filePath, "utf8");
227
+ if (existing === content)
228
+ return false;
229
+ }
230
+ catch (err) {
231
+ const code = err?.code;
232
+ if (code !== "ENOENT")
233
+ throw err;
234
+ }
235
+ await writeFile(filePath, content, "utf8");
236
+ return true;
237
+ }
238
+ async function cmdConfigShow(opts) {
239
+ try {
240
+ const resolved = await resolveProject({
241
+ cwd: opts.cwd,
242
+ rootOverride: opts.rootOverride ?? null,
243
+ });
244
+ const loaded = await loadConfig(resolved.agentplaneDir);
245
+ process.stdout.write(`${JSON.stringify(loaded.raw, null, 2)}\n`);
246
+ return 0;
247
+ }
248
+ catch (err) {
249
+ throw mapCoreError(err, { command: "config show", root: opts.rootOverride ?? null });
250
+ }
251
+ }
252
+ async function cmdConfigSet(opts) {
253
+ try {
254
+ const resolved = await resolveProject({
255
+ cwd: opts.cwd,
256
+ rootOverride: opts.rootOverride ?? null,
257
+ });
258
+ const loaded = await loadConfig(resolved.agentplaneDir);
259
+ const raw = { ...loaded.raw };
260
+ setByDottedKey(raw, opts.key, opts.value);
261
+ await saveConfig(resolved.agentplaneDir, raw);
262
+ process.stdout.write(`${path.relative(resolved.gitRoot, path.join(resolved.agentplaneDir, "config.json"))}\n`);
263
+ return 0;
264
+ }
265
+ catch (err) {
266
+ throw mapCoreError(err, {
267
+ command: "config set",
268
+ key: opts.key,
269
+ root: opts.rootOverride ?? null,
270
+ });
271
+ }
272
+ }
273
+ async function cmdModeGet(opts) {
274
+ try {
275
+ const resolved = await resolveProject({
276
+ cwd: opts.cwd,
277
+ rootOverride: opts.rootOverride ?? null,
278
+ });
279
+ const loaded = await loadConfig(resolved.agentplaneDir);
280
+ process.stdout.write(`${loaded.config.workflow_mode}\n`);
281
+ return 0;
282
+ }
283
+ catch (err) {
284
+ throw mapCoreError(err, { command: "mode get", root: opts.rootOverride ?? null });
285
+ }
286
+ }
287
+ async function cmdModeSet(opts) {
288
+ try {
289
+ const resolved = await resolveProject({
290
+ cwd: opts.cwd,
291
+ rootOverride: opts.rootOverride ?? null,
292
+ });
293
+ const loaded = await loadConfig(resolved.agentplaneDir);
294
+ const raw = { ...loaded.raw };
295
+ setByDottedKey(raw, "workflow_mode", opts.mode);
296
+ await saveConfig(resolved.agentplaneDir, raw);
297
+ process.stdout.write(`${opts.mode}\n`);
298
+ return 0;
299
+ }
300
+ catch (err) {
301
+ throw mapCoreError(err, {
302
+ command: "mode set",
303
+ root: opts.rootOverride ?? null,
304
+ mode: opts.mode,
305
+ });
306
+ }
307
+ }
308
+ const READY_USAGE = "Usage: agentplane ready <task-id>";
309
+ const READY_USAGE_EXAMPLE = "agentplane ready 202602030608-F1Q8AB";
310
+ const ROLE_USAGE = "Usage: agentplane role <role>";
311
+ const ROLE_USAGE_EXAMPLE = "agentplane role ORCHESTRATOR";
312
+ const AGENTS_USAGE = "Usage: agentplane agents";
313
+ const AGENTS_USAGE_EXAMPLE = "agentplane agents";
314
+ const INIT_USAGE = "Usage: agentplane init --ide <...> --workflow <...> --backend <local|redmine> --hooks <...> --require-plan-approval <...> --require-network-approval <...> --require-verify-approval <...> [--recipes <...>] [--yes] [--force|--backup]";
315
+ const INIT_USAGE_EXAMPLE = "agentplane init --ide codex --workflow direct --backend local --hooks false --require-plan-approval true --require-network-approval true --require-verify-approval true --yes";
316
+ const CONFIG_SET_USAGE = "Usage: agentplane config set <key> <value>";
317
+ const CONFIG_SET_USAGE_EXAMPLE = "agentplane config set workflow_mode branch_pr";
318
+ const MODE_SET_USAGE = "Usage: agentplane mode set <direct|branch_pr>";
319
+ const MODE_SET_USAGE_EXAMPLE = "agentplane mode set direct";
320
+ const QUICKSTART_USAGE = "Usage: agentplane quickstart";
321
+ const QUICKSTART_USAGE_EXAMPLE = "agentplane quickstart";
322
+ const IDE_SYNC_USAGE = "Usage: agentplane ide sync";
323
+ const IDE_SYNC_USAGE_EXAMPLE = "agentplane ide sync";
324
+ const TASK_SHOW_USAGE = "Usage: agentplane task show <task-id>";
325
+ const TASK_SHOW_USAGE_EXAMPLE = "agentplane task show 202602030608-F1Q8AB";
326
+ const TASK_SEARCH_USAGE = "Usage: agentplane task search <query> [flags]";
327
+ const TASK_SEARCH_USAGE_EXAMPLE = 'agentplane task search "cli"';
328
+ const TASK_COMMENT_USAGE = "Usage: agentplane task comment <task-id>";
329
+ const TASK_COMMENT_USAGE_EXAMPLE = 'agentplane task comment 202602030608-F1Q8AB --author CODER --body "..."';
330
+ const TASK_SET_STATUS_USAGE = "Usage: agentplane task set-status <task-id> <status> [flags]";
331
+ const TASK_SET_STATUS_USAGE_EXAMPLE = "agentplane task set-status 202602030608-F1Q8AB DONE";
332
+ const PR_GROUP_USAGE = "Usage: agentplane pr open|update|check|note <task-id>";
333
+ const PR_GROUP_USAGE_EXAMPLE = "agentplane pr open 202602030608-F1Q8AB --author CODER";
334
+ const GUARD_USAGE = "Usage: agentplane guard <subcommand>";
335
+ const GUARD_USAGE_EXAMPLE = 'agentplane guard commit 202602030608-F1Q8AB -m "✨ F1Q8AB update" --allow packages/agentplane';
336
+ const HOOKS_RUN_USAGE = "Usage: agentplane hooks run <hook>";
337
+ const HOOKS_RUN_USAGE_EXAMPLE = "agentplane hooks run pre-commit";
338
+ const HOOKS_INSTALL_USAGE = "Usage: agentplane hooks install|uninstall";
339
+ const HOOKS_INSTALL_USAGE_EXAMPLE = "agentplane hooks install";
340
+ function parseBooleanFlag(value, flag) {
341
+ const normalized = value.trim().toLowerCase();
342
+ if (["1", "true", "yes", "y", "on"].includes(normalized))
343
+ return true;
344
+ if (["0", "false", "no", "n", "off"].includes(normalized))
345
+ return false;
346
+ throw new CliError({
347
+ exitCode: 2,
348
+ code: "E_USAGE",
349
+ message: invalidValueForFlag(flag, value, "true|false"),
350
+ });
351
+ }
352
+ function parseInitFlags(args) {
353
+ const out = { yes: false };
354
+ for (let i = 0; i < args.length; i++) {
355
+ const arg = args[i];
356
+ if (!arg)
357
+ continue;
358
+ if (!arg.startsWith("--")) {
359
+ throw new CliError({ exitCode: 2, code: "E_USAGE", message: `Unexpected argument: ${arg}` });
360
+ }
361
+ if (arg === "--yes") {
362
+ out.yes = true;
363
+ continue;
364
+ }
365
+ if (arg === "--force") {
366
+ out.force = true;
367
+ continue;
368
+ }
369
+ if (arg === "--backup") {
370
+ out.backup = true;
371
+ continue;
372
+ }
373
+ const next = args[i + 1];
374
+ if (!next) {
375
+ throw new CliError({ exitCode: 2, code: "E_USAGE", message: missingValueMessage(arg) });
376
+ }
377
+ switch (arg) {
378
+ case "--ide": {
379
+ const normalized = next.trim().toLowerCase();
380
+ if (normalized !== "codex" && normalized !== "cursor" && normalized !== "windsurf") {
381
+ throw new CliError({
382
+ exitCode: 2,
383
+ code: "E_USAGE",
384
+ message: invalidValueForFlag("--ide", next, "codex|cursor|windsurf"),
385
+ });
386
+ }
387
+ out.ide = normalized;
388
+ break;
389
+ }
390
+ case "--workflow": {
391
+ if (next !== "direct" && next !== "branch_pr") {
392
+ throw new CliError({
393
+ exitCode: 2,
394
+ code: "E_USAGE",
395
+ message: invalidValueForFlag("--workflow", next, "direct|branch_pr"),
396
+ });
397
+ }
398
+ out.workflow = next;
399
+ break;
400
+ }
401
+ case "--backend": {
402
+ const normalized = next.trim().toLowerCase();
403
+ if (normalized !== "local" && normalized !== "redmine") {
404
+ throw new CliError({
405
+ exitCode: 2,
406
+ code: "E_USAGE",
407
+ message: invalidValueForFlag("--backend", next, "local|redmine"),
408
+ });
409
+ }
410
+ out.backend = normalized;
411
+ break;
412
+ }
413
+ case "--hooks": {
414
+ out.hooks = parseBooleanFlag(next, "--hooks");
415
+ break;
416
+ }
417
+ case "--require-plan-approval": {
418
+ out.requirePlanApproval = parseBooleanFlag(next, "--require-plan-approval");
419
+ break;
420
+ }
421
+ case "--require-network-approval": {
422
+ out.requireNetworkApproval = parseBooleanFlag(next, "--require-network-approval");
423
+ break;
424
+ }
425
+ case "--require-verify-approval": {
426
+ out.requireVerifyApproval = parseBooleanFlag(next, "--require-verify-approval");
427
+ break;
428
+ }
429
+ case "--recipes": {
430
+ const normalized = next.trim().toLowerCase();
431
+ out.recipes =
432
+ normalized === "none" || normalized === ""
433
+ ? []
434
+ : next
435
+ .split(",")
436
+ .map((item) => item.trim())
437
+ .filter(Boolean);
438
+ break;
439
+ }
440
+ default: {
441
+ throw new CliError({ exitCode: 2, code: "E_USAGE", message: `Unknown flag: ${arg}` });
442
+ }
443
+ }
444
+ i++;
445
+ }
446
+ if (out.force && out.backup) {
447
+ throw new CliError({
448
+ exitCode: 2,
449
+ code: "E_USAGE",
450
+ message: "Use either --force or --backup (not both).",
451
+ });
452
+ }
453
+ return out;
454
+ }
455
+ async function cmdInit(opts) {
456
+ const flags = parseInitFlags(opts.args);
457
+ const defaults = {
458
+ ide: "codex",
459
+ workflow: "direct",
460
+ backend: "local",
461
+ hooks: false,
462
+ recipes: [],
463
+ requirePlanApproval: true,
464
+ requireNetworkApproval: true,
465
+ requireVerifyApproval: true,
466
+ };
467
+ let ide = flags.ide ?? defaults.ide;
468
+ let workflow = flags.workflow ?? defaults.workflow;
469
+ let backend = flags.backend ?? defaults.backend;
470
+ let hooks = flags.hooks ?? defaults.hooks;
471
+ let recipes = flags.recipes ?? defaults.recipes;
472
+ let requirePlanApproval = flags.requirePlanApproval ?? defaults.requirePlanApproval;
473
+ let requireNetworkApproval = flags.requireNetworkApproval ?? defaults.requireNetworkApproval;
474
+ let requireVerifyApproval = flags.requireVerifyApproval ?? defaults.requireVerifyApproval;
475
+ const isInteractive = process.stdin.isTTY && !flags.yes;
476
+ if (!process.stdin.isTTY &&
477
+ !flags.yes &&
478
+ (!flags.workflow ||
479
+ flags.hooks === undefined ||
480
+ flags.requirePlanApproval === undefined ||
481
+ flags.requireNetworkApproval === undefined ||
482
+ flags.requireVerifyApproval === undefined)) {
483
+ throw new CliError({
484
+ exitCode: 2,
485
+ code: "E_USAGE",
486
+ message: usageMessage(INIT_USAGE, INIT_USAGE_EXAMPLE),
487
+ });
488
+ }
489
+ if (isInteractive) {
490
+ ide = flags.ide ?? defaults.ide;
491
+ if (!flags.workflow) {
492
+ const choice = await promptChoice("Select workflow mode", ["direct", "branch_pr"], workflow);
493
+ workflow = choice === "branch_pr" ? "branch_pr" : "direct";
494
+ }
495
+ if (!flags.backend) {
496
+ const choice = await promptChoice("Select task backend", ["local", "redmine"], backend);
497
+ backend = choice === "redmine" ? "redmine" : "local";
498
+ }
499
+ if (flags.hooks === undefined) {
500
+ hooks = await promptYesNo("Install git hooks?", hooks);
501
+ }
502
+ if (flags.requirePlanApproval === undefined) {
503
+ requirePlanApproval = await promptYesNo("Require plan approval?", requirePlanApproval);
504
+ }
505
+ if (flags.requireNetworkApproval === undefined) {
506
+ requireNetworkApproval = await promptYesNo("Require explicit approval for network access?", requireNetworkApproval);
507
+ }
508
+ if (flags.requireVerifyApproval === undefined) {
509
+ requireVerifyApproval = await promptYesNo("Require explicit approval for verification?", requireVerifyApproval);
510
+ }
511
+ if (!flags.recipes) {
512
+ process.stdout.write(`${renderBundledRecipesHint()}\n`);
513
+ const answer = await promptInput("Install optional recipes (comma separated, or none): ");
514
+ recipes = answer
515
+ ? answer
516
+ .split(",")
517
+ .map((item) => item.trim())
518
+ .filter(Boolean)
519
+ : [];
520
+ }
521
+ }
522
+ if (flags.yes) {
523
+ ide = flags.ide ?? defaults.ide;
524
+ workflow = flags.workflow ?? defaults.workflow;
525
+ backend = flags.backend ?? defaults.backend;
526
+ hooks = flags.hooks ?? defaults.hooks;
527
+ recipes = flags.recipes ?? defaults.recipes;
528
+ requirePlanApproval = flags.requirePlanApproval ?? defaults.requirePlanApproval;
529
+ requireNetworkApproval = flags.requireNetworkApproval ?? defaults.requireNetworkApproval;
530
+ requireVerifyApproval = flags.requireVerifyApproval ?? defaults.requireVerifyApproval;
531
+ }
532
+ validateBundledRecipesSelection(recipes);
533
+ try {
534
+ const initRoot = path.resolve(opts.rootOverride ?? opts.cwd);
535
+ const existingGitRoot = await findGitRoot(initRoot);
536
+ const gitRootExisted = Boolean(existingGitRoot);
537
+ let gitRoot = existingGitRoot;
538
+ const baseBranchFallback = defaultConfig().base_branch;
539
+ if (!gitRoot) {
540
+ await gitInitRepo(initRoot, baseBranchFallback);
541
+ gitRoot = initRoot;
542
+ }
543
+ const resolved = await resolveProject({
544
+ cwd: gitRoot,
545
+ rootOverride: gitRoot,
546
+ });
547
+ let initBaseBranch = await resolveInitBaseBranch(resolved.gitRoot, baseBranchFallback);
548
+ if (isInteractive && workflow === "branch_pr" && gitRootExisted) {
549
+ initBaseBranch = await promptInitBaseBranch({
550
+ gitRoot: resolved.gitRoot,
551
+ fallback: initBaseBranch,
552
+ });
553
+ }
554
+ const configPath = path.join(resolved.agentplaneDir, "config.json");
555
+ const localBackendPath = path.join(resolved.agentplaneDir, "backends", "local", "backend.json");
556
+ const redmineBackendPath = path.join(resolved.agentplaneDir, "backends", "redmine", "backend.json");
557
+ const backendPath = backend === "redmine" ? redmineBackendPath : localBackendPath;
558
+ const initDirs = [
559
+ resolved.agentplaneDir,
560
+ path.join(resolved.agentplaneDir, "tasks"),
561
+ path.join(resolved.agentplaneDir, "agents"),
562
+ path.join(resolved.agentplaneDir, "cache"),
563
+ path.join(resolved.agentplaneDir, "backends"),
564
+ path.join(resolved.agentplaneDir, "backends", "local"),
565
+ path.join(resolved.agentplaneDir, "backends", "redmine"),
566
+ ];
567
+ const initFiles = [configPath, localBackendPath, redmineBackendPath];
568
+ const conflicts = [];
569
+ for (const dir of initDirs) {
570
+ const kind = await getPathKind(dir);
571
+ if (kind && kind !== "dir")
572
+ conflicts.push(dir);
573
+ }
574
+ for (const filePath of initFiles) {
575
+ if (await fileExists(filePath))
576
+ conflicts.push(filePath);
577
+ }
578
+ if (conflicts.length > 0) {
579
+ if (flags.backup) {
580
+ for (const conflict of conflicts) {
581
+ await backupPath(conflict);
582
+ }
583
+ }
584
+ else if (flags.force) {
585
+ for (const conflict of conflicts) {
586
+ await rm(conflict, { recursive: true, force: true });
587
+ }
588
+ }
589
+ else {
590
+ const rendered = conflicts
591
+ .map((conflict) => `- ${path.relative(resolved.gitRoot, conflict)}`)
592
+ .join("\n");
593
+ throw new CliError({
594
+ exitCode: 5,
595
+ code: "E_IO",
596
+ message: `Init conflicts detected:\n${rendered}\n` +
597
+ "Re-run with --force to overwrite or --backup to preserve existing files.",
598
+ });
599
+ }
600
+ }
601
+ await mkdir(resolved.agentplaneDir, { recursive: true });
602
+ await mkdir(path.join(resolved.agentplaneDir, "tasks"), { recursive: true });
603
+ await mkdir(path.join(resolved.agentplaneDir, "agents"), { recursive: true });
604
+ await mkdir(path.join(resolved.agentplaneDir, "cache"), { recursive: true });
605
+ await mkdir(path.join(resolved.agentplaneDir, "backends", "local"), { recursive: true });
606
+ await mkdir(path.join(resolved.agentplaneDir, "backends", "redmine"), { recursive: true });
607
+ const rawConfig = defaultConfig();
608
+ setByDottedKey(rawConfig, "base_branch", initBaseBranch);
609
+ setByDottedKey(rawConfig, "workflow_mode", workflow);
610
+ setByDottedKey(rawConfig, "tasks_backend.config_path", path.relative(resolved.gitRoot, backendPath));
611
+ setByDottedKey(rawConfig, "agents.approvals.require_plan", String(requirePlanApproval));
612
+ setByDottedKey(rawConfig, "agents.approvals.require_network", String(requireNetworkApproval));
613
+ setByDottedKey(rawConfig, "agents.approvals.require_verify", String(requireVerifyApproval));
614
+ await saveConfig(resolved.agentplaneDir, rawConfig);
615
+ const localBackendPayload = {
616
+ id: "local",
617
+ version: 1,
618
+ module: "backend.py",
619
+ class: "LocalBackend",
620
+ settings: { dir: ".agentplane/tasks" },
621
+ };
622
+ const redmineBackendPayload = {
623
+ id: "redmine",
624
+ version: 1,
625
+ module: "backend.py",
626
+ class: "RedmineBackend",
627
+ settings: {
628
+ url: "https://redmine.example",
629
+ api_key: "replace-me",
630
+ project_id: "replace-me",
631
+ owner_agent: "REDMINE",
632
+ custom_fields: { task_id: 1 },
633
+ },
634
+ };
635
+ await writeFile(localBackendPath, `${JSON.stringify(localBackendPayload, null, 2)}\n`, "utf8");
636
+ await writeFile(redmineBackendPath, `${JSON.stringify(redmineBackendPayload, null, 2)}\n`, "utf8");
637
+ const agentsPath = path.join(resolved.gitRoot, "AGENTS.md");
638
+ const installPaths = [
639
+ path.relative(resolved.gitRoot, configPath),
640
+ path.relative(resolved.gitRoot, backendPath),
641
+ ];
642
+ let wroteAgents = false;
643
+ if (!(await fileExists(agentsPath))) {
644
+ const template = await loadAgentsTemplate();
645
+ const filtered = filterAgentsByWorkflow(template, workflow);
646
+ await writeFile(agentsPath, filtered, "utf8");
647
+ wroteAgents = true;
648
+ }
649
+ if (wroteAgents) {
650
+ installPaths.push(path.relative(resolved.gitRoot, agentsPath));
651
+ }
652
+ const agentTemplates = await loadAgentTemplates();
653
+ for (const agent of agentTemplates) {
654
+ const targetPath = path.join(resolved.agentplaneDir, "agents", agent.fileName);
655
+ if (await fileExists(targetPath))
656
+ continue;
657
+ await writeFile(targetPath, agent.contents, "utf8");
658
+ installPaths.push(path.relative(resolved.gitRoot, targetPath));
659
+ }
660
+ if (hooks) {
661
+ await cmdHooksInstall({ cwd: opts.cwd, rootOverride: opts.rootOverride, quiet: true });
662
+ }
663
+ if (ide !== "codex") {
664
+ await cmdIdeSync({ cwd: opts.cwd, rootOverride: opts.rootOverride, ide });
665
+ const cursorPath = path.join(resolved.gitRoot, ".cursor", "rules", "agentplane.mdc");
666
+ const windsurfPath = path.join(resolved.gitRoot, ".windsurf", "rules", "agentplane.md");
667
+ if (ide === "cursor" && (await fileExists(cursorPath))) {
668
+ installPaths.push(path.relative(resolved.gitRoot, cursorPath));
669
+ }
670
+ if (ide === "windsurf" && (await fileExists(windsurfPath))) {
671
+ installPaths.push(path.relative(resolved.gitRoot, windsurfPath));
672
+ }
673
+ }
674
+ if (recipes.length > 0) {
675
+ if (listBundledRecipes().length === 0) {
676
+ process.stdout.write(`${infoMessage("bundled recipes are empty; nothing to install")}\n`);
677
+ }
678
+ else {
679
+ process.stdout.write(`${infoMessage("bundled recipe install is not implemented; skipping")}\n`);
680
+ }
681
+ }
682
+ await ensureInitCommit({
683
+ gitRoot: resolved.gitRoot,
684
+ baseBranch: initBaseBranch,
685
+ installPaths,
686
+ version: getVersion(),
687
+ skipHooks: hooks,
688
+ });
689
+ process.stdout.write(`${path.relative(resolved.gitRoot, resolved.agentplaneDir)}\n`);
690
+ return 0;
691
+ }
692
+ catch (err) {
693
+ if (err instanceof CliError)
694
+ throw err;
695
+ throw mapCoreError(err, { command: "init", root: opts.rootOverride ?? null });
696
+ }
697
+ }
698
+ async function cmdIdeSync(opts) {
699
+ try {
700
+ const resolved = await resolveProject({
701
+ cwd: opts.cwd,
702
+ rootOverride: opts.rootOverride ?? null,
703
+ });
704
+ const agentsPath = path.join(resolved.gitRoot, "AGENTS.md");
705
+ const agentsText = await readFile(agentsPath, "utf8");
706
+ const header = [
707
+ "<!--",
708
+ " AUTOGENERATED by agentplane ide sync.",
709
+ " DO NOT EDIT MANUALLY.",
710
+ " Source: AGENTS.md",
711
+ "-->",
712
+ "",
713
+ ].join("\n");
714
+ const content = `${header}${agentsText.trimEnd()}\n`;
715
+ const targets = opts.ide === "cursor"
716
+ ? ["cursor"]
717
+ : opts.ide === "windsurf"
718
+ ? ["windsurf"]
719
+ : ["cursor", "windsurf"];
720
+ if (targets.includes("cursor")) {
721
+ const cursorDir = path.join(resolved.gitRoot, ".cursor", "rules");
722
+ await mkdir(cursorDir, { recursive: true });
723
+ const cursorPath = path.join(cursorDir, "agentplane.mdc");
724
+ await writeFileIfChanged(cursorPath, content);
725
+ process.stdout.write(`${path.relative(resolved.gitRoot, cursorPath)}\n`);
726
+ }
727
+ if (targets.includes("windsurf")) {
728
+ const windsurfDir = path.join(resolved.gitRoot, ".windsurf", "rules");
729
+ await mkdir(windsurfDir, { recursive: true });
730
+ const windsurfPath = path.join(windsurfDir, "agentplane.md");
731
+ await writeFileIfChanged(windsurfPath, content);
732
+ process.stdout.write(`${path.relative(resolved.gitRoot, windsurfPath)}\n`);
733
+ }
734
+ return 0;
735
+ }
736
+ catch (err) {
737
+ throw mapCoreError(err, { command: "ide sync", root: opts.rootOverride ?? null });
738
+ }
739
+ }
740
+ function cmdRole(opts) {
741
+ try {
742
+ const roleRaw = opts.role.trim();
743
+ if (!roleRaw) {
744
+ throw new CliError({
745
+ exitCode: 2,
746
+ code: "E_USAGE",
747
+ message: usageMessage(ROLE_USAGE, ROLE_USAGE_EXAMPLE),
748
+ });
749
+ }
750
+ const guide = renderRole(roleRaw);
751
+ if (!guide) {
752
+ const roles = listRoles();
753
+ const available = roles.length > 0 ? `\nAvailable roles: ${roles.join(", ")}` : "";
754
+ throw new CliError({
755
+ exitCode: 2,
756
+ code: "E_USAGE",
757
+ message: usageMessage(`${ROLE_USAGE}${available}`, ROLE_USAGE_EXAMPLE),
758
+ });
759
+ }
760
+ process.stdout.write(`${guide}\n`);
761
+ return 0;
762
+ }
763
+ catch (err) {
764
+ if (err instanceof CliError)
765
+ throw err;
766
+ throw mapCoreError(err, { command: "role", root: opts.rootOverride ?? null });
767
+ }
768
+ }
769
+ function cmdQuickstart(opts) {
770
+ try {
771
+ process.stdout.write(`${renderQuickstart()}\n`);
772
+ return 0;
773
+ }
774
+ catch (err) {
775
+ if (err instanceof CliError)
776
+ throw err;
777
+ throw mapCoreError(err, { command: "quickstart", root: opts.rootOverride ?? null });
778
+ }
779
+ }
780
+ async function cmdAgents(opts) {
781
+ try {
782
+ const resolved = await resolveProject({
783
+ cwd: opts.cwd,
784
+ rootOverride: opts.rootOverride ?? null,
785
+ });
786
+ const agentsDir = path.join(resolved.agentplaneDir, "agents");
787
+ if (!(await fileExists(agentsDir))) {
788
+ throw new CliError({
789
+ exitCode: 2,
790
+ code: "E_USAGE",
791
+ message: `Agents directory not found: ${agentsDir} (run \`agentplane init\`)`,
792
+ });
793
+ }
794
+ const entriesRaw = await readdir(agentsDir);
795
+ const entries = entriesRaw.filter((name) => name.endsWith(".json")).toSorted();
796
+ if (entries.length === 0) {
797
+ throw new CliError({
798
+ exitCode: 2,
799
+ code: "E_USAGE",
800
+ message: `No agent definitions found under ${agentsDir} (expected *.json)`,
801
+ });
802
+ }
803
+ const rows = [];
804
+ const seen = new Set();
805
+ const duplicates = [];
806
+ for (const entry of entries) {
807
+ const filePath = path.join(agentsDir, entry);
808
+ const raw = JSON.parse(await readFile(filePath, "utf8"));
809
+ const rawId = typeof raw.id === "string" ? raw.id : "";
810
+ const rawRole = typeof raw.role === "string" ? raw.role : "";
811
+ const agentId = rawId.trim() || "<missing-id>";
812
+ const role = rawRole.trim() || "-";
813
+ if (seen.has(agentId)) {
814
+ duplicates.push(agentId);
815
+ }
816
+ else {
817
+ seen.add(agentId);
818
+ }
819
+ rows.push([agentId, role, entry]);
820
+ }
821
+ const widthId = Math.max(...rows.map((row) => row[0].length), "ID".length);
822
+ const widthFile = Math.max(...rows.map((row) => row[2].length), "FILE".length);
823
+ process.stdout.write(`${"ID".padEnd(widthId)} ${"FILE".padEnd(widthFile)} ROLE\n`);
824
+ process.stdout.write(`${"-".repeat(widthId)} ${"-".repeat(widthFile)} ----\n`);
825
+ for (const [agentId, role, filename] of rows) {
826
+ process.stdout.write(`${agentId.padEnd(widthId)} ${filename.padEnd(widthFile)} ${role}\n`);
827
+ }
828
+ if (duplicates.length > 0) {
829
+ throw new CliError({
830
+ exitCode: 2,
831
+ code: "E_USAGE",
832
+ message: `Duplicate agent ids: ${dedupeStrings(duplicates).toSorted().join(", ")}`,
833
+ });
834
+ }
835
+ return 0;
836
+ }
837
+ catch (err) {
838
+ if (err instanceof CliError)
839
+ throw err;
840
+ throw mapCoreError(err, { command: "agents", root: opts.rootOverride ?? null });
841
+ }
842
+ }
843
+ export async function runCli(argv) {
844
+ let jsonErrors = argv.includes("--json");
845
+ try {
846
+ const { globals, rest } = parseGlobalArgs(argv);
847
+ jsonErrors = globals.jsonErrors;
848
+ if (globals.version) {
849
+ process.stdout.write(`${getVersion()}\n`);
850
+ return 0;
851
+ }
852
+ if (globals.help || rest.length === 0) {
853
+ process.stdout.write(`${renderHelp()}\n`);
854
+ return 0;
855
+ }
856
+ await maybeLoadDotEnv({ cwd: process.cwd(), rootOverride: globals.root });
857
+ await maybeWarnOnUpdate({
858
+ currentVersion: getVersion(),
859
+ skip: globals.noUpdateCheck,
860
+ jsonErrors: globals.jsonErrors,
861
+ });
862
+ const [namespace, command, ...args] = rest;
863
+ if (namespace === "init") {
864
+ const initArgs = command ? [command, ...args] : [];
865
+ if (command && !command.startsWith("--")) {
866
+ throw new CliError({
867
+ exitCode: 2,
868
+ code: "E_USAGE",
869
+ message: usageMessage(INIT_USAGE, INIT_USAGE_EXAMPLE),
870
+ });
871
+ }
872
+ return await cmdInit({ cwd: process.cwd(), rootOverride: globals.root, args: initArgs });
873
+ }
874
+ if (namespace === "upgrade") {
875
+ const upgradeArgs = command ? [command, ...args] : [];
876
+ return await cmdUpgrade({
877
+ cwd: process.cwd(),
878
+ rootOverride: globals.root,
879
+ args: upgradeArgs,
880
+ });
881
+ }
882
+ if (namespace === "config" && command === "show") {
883
+ return await cmdConfigShow({ cwd: process.cwd(), rootOverride: globals.root });
884
+ }
885
+ if (namespace === "config" && command === "set") {
886
+ const [key, value] = args;
887
+ if (!key || value === undefined) {
888
+ throw new CliError({
889
+ exitCode: 2,
890
+ code: "E_USAGE",
891
+ message: usageMessage(CONFIG_SET_USAGE, CONFIG_SET_USAGE_EXAMPLE),
892
+ });
893
+ }
894
+ return await cmdConfigSet({ cwd: process.cwd(), rootOverride: globals.root, key, value });
895
+ }
896
+ if (namespace === "mode" && command === "get") {
897
+ return await cmdModeGet({ cwd: process.cwd(), rootOverride: globals.root });
898
+ }
899
+ if (namespace === "mode" && command === "set") {
900
+ const [mode] = args;
901
+ if (mode !== "direct" && mode !== "branch_pr") {
902
+ throw new CliError({
903
+ exitCode: 2,
904
+ code: "E_USAGE",
905
+ message: usageMessage(MODE_SET_USAGE, MODE_SET_USAGE_EXAMPLE),
906
+ });
907
+ }
908
+ return await cmdModeSet({ cwd: process.cwd(), rootOverride: globals.root, mode });
909
+ }
910
+ if (namespace === "quickstart") {
911
+ if (command) {
912
+ throw new CliError({
913
+ exitCode: 2,
914
+ code: "E_USAGE",
915
+ message: usageMessage(QUICKSTART_USAGE, QUICKSTART_USAGE_EXAMPLE),
916
+ });
917
+ }
918
+ return cmdQuickstart({ cwd: process.cwd(), rootOverride: globals.root });
919
+ }
920
+ if (namespace === "role") {
921
+ if (!command || command.startsWith("--") || args.length > 0) {
922
+ throw new CliError({
923
+ exitCode: 2,
924
+ code: "E_USAGE",
925
+ message: usageMessage(ROLE_USAGE, ROLE_USAGE_EXAMPLE),
926
+ });
927
+ }
928
+ return cmdRole({ cwd: process.cwd(), rootOverride: globals.root, role: command });
929
+ }
930
+ if (namespace === "agents") {
931
+ if (command) {
932
+ throw new CliError({
933
+ exitCode: 2,
934
+ code: "E_USAGE",
935
+ message: usageMessage(AGENTS_USAGE, AGENTS_USAGE_EXAMPLE),
936
+ });
937
+ }
938
+ return await cmdAgents({ cwd: process.cwd(), rootOverride: globals.root });
939
+ }
940
+ if (namespace === "ready") {
941
+ if (!command || command.startsWith("--") || args.length > 0) {
942
+ throw new CliError({
943
+ exitCode: 2,
944
+ code: "E_USAGE",
945
+ message: usageMessage(READY_USAGE, READY_USAGE_EXAMPLE),
946
+ });
947
+ }
948
+ return await cmdReady({ cwd: process.cwd(), rootOverride: globals.root, taskId: command });
949
+ }
950
+ if (namespace === "ide") {
951
+ if (command !== "sync" || args.length > 0) {
952
+ throw new CliError({
953
+ exitCode: 2,
954
+ code: "E_USAGE",
955
+ message: usageMessage(IDE_SYNC_USAGE, IDE_SYNC_USAGE_EXAMPLE),
956
+ });
957
+ }
958
+ return await cmdIdeSync({ cwd: process.cwd(), rootOverride: globals.root });
959
+ }
960
+ if (namespace === "task" && command === "new") {
961
+ return await cmdTaskNew({ cwd: process.cwd(), rootOverride: globals.root, args });
962
+ }
963
+ if (namespace === "task" && command === "add") {
964
+ return await cmdTaskAdd({ cwd: process.cwd(), rootOverride: globals.root, args });
965
+ }
966
+ if (namespace === "task" && command === "update") {
967
+ return await cmdTaskUpdate({ cwd: process.cwd(), rootOverride: globals.root, args });
968
+ }
969
+ if (namespace === "task" && command === "scrub") {
970
+ return await cmdTaskScrub({ cwd: process.cwd(), rootOverride: globals.root, args });
971
+ }
972
+ if (namespace === "task" && command === "show") {
973
+ const [taskId] = args;
974
+ if (!taskId) {
975
+ throw new CliError({
976
+ exitCode: 2,
977
+ code: "E_USAGE",
978
+ message: usageMessage(TASK_SHOW_USAGE, TASK_SHOW_USAGE_EXAMPLE),
979
+ });
980
+ }
981
+ return await cmdTaskShow({ cwd: process.cwd(), rootOverride: globals.root, taskId });
982
+ }
983
+ if (namespace === "task" && command === "list") {
984
+ return await cmdTaskList({ cwd: process.cwd(), rootOverride: globals.root, args });
985
+ }
986
+ if (namespace === "task" && command === "next") {
987
+ return await cmdTaskNext({ cwd: process.cwd(), rootOverride: globals.root, args });
988
+ }
989
+ if (namespace === "task" && command === "search") {
990
+ const [query, ...restArgs] = args;
991
+ if (!query) {
992
+ throw new CliError({
993
+ exitCode: 2,
994
+ code: "E_USAGE",
995
+ message: usageMessage(TASK_SEARCH_USAGE, TASK_SEARCH_USAGE_EXAMPLE),
996
+ });
997
+ }
998
+ return await cmdTaskSearch({
999
+ cwd: process.cwd(),
1000
+ rootOverride: globals.root,
1001
+ query,
1002
+ args: restArgs,
1003
+ });
1004
+ }
1005
+ if (namespace === "task" && command === "scaffold") {
1006
+ return await cmdTaskScaffold({ cwd: process.cwd(), rootOverride: globals.root, args });
1007
+ }
1008
+ if (namespace === "task" && command === "normalize") {
1009
+ return await cmdTaskNormalize({ cwd: process.cwd(), rootOverride: globals.root, args });
1010
+ }
1011
+ if (namespace === "task" && command === "migrate") {
1012
+ return await cmdTaskMigrate({ cwd: process.cwd(), rootOverride: globals.root, args });
1013
+ }
1014
+ if (namespace === "task" && command === "export") {
1015
+ return await cmdTaskExport({ cwd: process.cwd(), rootOverride: globals.root });
1016
+ }
1017
+ if (namespace === "task" && command === "lint") {
1018
+ return await cmdTaskLint({ cwd: process.cwd(), rootOverride: globals.root });
1019
+ }
1020
+ if (namespace === "task" && command === "doc") {
1021
+ const [subcommand, taskId, ...restArgs] = args;
1022
+ if (subcommand === "show") {
1023
+ if (!taskId) {
1024
+ throw new CliError({
1025
+ exitCode: 2,
1026
+ code: "E_USAGE",
1027
+ message: usageMessage(TASK_DOC_SHOW_USAGE, TASK_DOC_SHOW_USAGE_EXAMPLE),
1028
+ });
1029
+ }
1030
+ return await cmdTaskDocShow({
1031
+ cwd: process.cwd(),
1032
+ rootOverride: globals.root,
1033
+ taskId,
1034
+ args: restArgs,
1035
+ });
1036
+ }
1037
+ if (subcommand === "set") {
1038
+ if (!taskId) {
1039
+ throw new CliError({
1040
+ exitCode: 2,
1041
+ code: "E_USAGE",
1042
+ message: usageMessage(TASK_DOC_SET_USAGE, TASK_DOC_SET_USAGE_EXAMPLE),
1043
+ });
1044
+ }
1045
+ return await cmdTaskDocSet({
1046
+ cwd: process.cwd(),
1047
+ rootOverride: globals.root,
1048
+ taskId,
1049
+ args: restArgs,
1050
+ });
1051
+ }
1052
+ throw new CliError({
1053
+ exitCode: 2,
1054
+ code: "E_USAGE",
1055
+ message: usageMessage(TASK_DOC_SET_USAGE, TASK_DOC_SET_USAGE_EXAMPLE),
1056
+ });
1057
+ }
1058
+ if (namespace === "task" && command === "comment") {
1059
+ const [taskId, ...restArgs] = args;
1060
+ if (!taskId) {
1061
+ throw new CliError({
1062
+ exitCode: 2,
1063
+ code: "E_USAGE",
1064
+ message: usageMessage(TASK_COMMENT_USAGE, TASK_COMMENT_USAGE_EXAMPLE),
1065
+ });
1066
+ }
1067
+ let author = "";
1068
+ let body = "";
1069
+ for (let i = 0; i < restArgs.length; i++) {
1070
+ const arg = restArgs[i];
1071
+ if (!arg)
1072
+ continue;
1073
+ if (arg === "--author") {
1074
+ const next = restArgs[i + 1];
1075
+ if (!next) {
1076
+ throw new CliError({
1077
+ exitCode: 2,
1078
+ code: "E_USAGE",
1079
+ message: missingValueMessage("--author"),
1080
+ });
1081
+ }
1082
+ author = next;
1083
+ i++;
1084
+ continue;
1085
+ }
1086
+ if (arg === "--body") {
1087
+ const next = restArgs[i + 1];
1088
+ if (!next) {
1089
+ throw new CliError({
1090
+ exitCode: 2,
1091
+ code: "E_USAGE",
1092
+ message: missingValueMessage("--body"),
1093
+ });
1094
+ }
1095
+ body = next;
1096
+ i++;
1097
+ continue;
1098
+ }
1099
+ if (arg.startsWith("--")) {
1100
+ throw new CliError({
1101
+ exitCode: 2,
1102
+ code: "E_USAGE",
1103
+ message: usageMessage(TASK_COMMENT_USAGE, TASK_COMMENT_USAGE_EXAMPLE),
1104
+ });
1105
+ }
1106
+ }
1107
+ if (!author || !body) {
1108
+ throw new CliError({
1109
+ exitCode: 2,
1110
+ code: "E_USAGE",
1111
+ message: usageMessage(TASK_COMMENT_USAGE, TASK_COMMENT_USAGE_EXAMPLE),
1112
+ });
1113
+ }
1114
+ return await cmdTaskComment({
1115
+ cwd: process.cwd(),
1116
+ rootOverride: globals.root,
1117
+ taskId,
1118
+ author,
1119
+ body,
1120
+ });
1121
+ }
1122
+ if (namespace === "task" && command === "set-status") {
1123
+ const [taskId, status, ...restArgs] = args;
1124
+ if (!taskId || !status) {
1125
+ throw new CliError({
1126
+ exitCode: 2,
1127
+ code: "E_USAGE",
1128
+ message: usageMessage(TASK_SET_STATUS_USAGE, TASK_SET_STATUS_USAGE_EXAMPLE),
1129
+ });
1130
+ }
1131
+ let author;
1132
+ let body;
1133
+ let commit;
1134
+ let force = false;
1135
+ let commitFromComment = false;
1136
+ let commitEmoji;
1137
+ const commitAllow = [];
1138
+ let commitAutoAllow = false;
1139
+ let commitAllowTasks = true;
1140
+ let commitRequireClean = false;
1141
+ let confirmStatusCommit = false;
1142
+ let quiet = false;
1143
+ for (let i = 0; i < restArgs.length; i++) {
1144
+ const arg = restArgs[i];
1145
+ if (!arg)
1146
+ continue;
1147
+ if (arg === "--author") {
1148
+ const next = restArgs[i + 1];
1149
+ if (!next)
1150
+ throw new CliError({
1151
+ exitCode: 2,
1152
+ code: "E_USAGE",
1153
+ message: missingValueMessage("--author"),
1154
+ });
1155
+ author = next;
1156
+ i++;
1157
+ continue;
1158
+ }
1159
+ if (arg === "--body") {
1160
+ const next = restArgs[i + 1];
1161
+ if (!next)
1162
+ throw new CliError({
1163
+ exitCode: 2,
1164
+ code: "E_USAGE",
1165
+ message: missingValueMessage("--body"),
1166
+ });
1167
+ body = next;
1168
+ i++;
1169
+ continue;
1170
+ }
1171
+ if (arg === "--commit") {
1172
+ const next = restArgs[i + 1];
1173
+ if (!next)
1174
+ throw new CliError({
1175
+ exitCode: 2,
1176
+ code: "E_USAGE",
1177
+ message: missingValueMessage("--commit"),
1178
+ });
1179
+ commit = next;
1180
+ i++;
1181
+ continue;
1182
+ }
1183
+ if (arg === "--force") {
1184
+ force = true;
1185
+ continue;
1186
+ }
1187
+ if (arg === "--commit-from-comment") {
1188
+ commitFromComment = true;
1189
+ continue;
1190
+ }
1191
+ if (arg === "--commit-emoji") {
1192
+ const next = restArgs[i + 1];
1193
+ if (!next)
1194
+ throw new CliError({
1195
+ exitCode: 2,
1196
+ code: "E_USAGE",
1197
+ message: missingValueMessage("--commit-emoji"),
1198
+ });
1199
+ commitEmoji = next;
1200
+ i++;
1201
+ continue;
1202
+ }
1203
+ if (arg === "--commit-allow") {
1204
+ const next = restArgs[i + 1];
1205
+ if (!next)
1206
+ throw new CliError({
1207
+ exitCode: 2,
1208
+ code: "E_USAGE",
1209
+ message: missingValueMessage("--commit-allow"),
1210
+ });
1211
+ commitAllow.push(next);
1212
+ i++;
1213
+ continue;
1214
+ }
1215
+ if (arg === "--commit-auto-allow") {
1216
+ commitAutoAllow = true;
1217
+ continue;
1218
+ }
1219
+ if (arg === "--commit-allow-tasks") {
1220
+ commitAllowTasks = true;
1221
+ continue;
1222
+ }
1223
+ if (arg === "--commit-require-clean") {
1224
+ commitRequireClean = true;
1225
+ continue;
1226
+ }
1227
+ if (arg === "--confirm-status-commit") {
1228
+ confirmStatusCommit = true;
1229
+ continue;
1230
+ }
1231
+ if (arg === "--quiet") {
1232
+ quiet = true;
1233
+ continue;
1234
+ }
1235
+ if (arg.startsWith("--")) {
1236
+ throw new CliError({
1237
+ exitCode: 2,
1238
+ code: "E_USAGE",
1239
+ message: usageMessage(TASK_SET_STATUS_USAGE, TASK_SET_STATUS_USAGE_EXAMPLE),
1240
+ });
1241
+ }
1242
+ }
1243
+ return await cmdTaskSetStatus({
1244
+ cwd: process.cwd(),
1245
+ rootOverride: globals.root,
1246
+ taskId,
1247
+ status,
1248
+ author,
1249
+ body,
1250
+ commit,
1251
+ force,
1252
+ commitFromComment,
1253
+ commitEmoji,
1254
+ commitAllow,
1255
+ commitAutoAllow,
1256
+ commitAllowTasks,
1257
+ commitRequireClean,
1258
+ confirmStatusCommit,
1259
+ quiet,
1260
+ });
1261
+ }
1262
+ if (namespace === "branch") {
1263
+ if (command === "base") {
1264
+ const [subcommand, value] = args;
1265
+ if (subcommand === "get") {
1266
+ return await cmdBranchBaseGet({ cwd: process.cwd(), rootOverride: globals.root });
1267
+ }
1268
+ if (subcommand === "set") {
1269
+ if (!value) {
1270
+ throw new CliError({
1271
+ exitCode: 2,
1272
+ code: "E_USAGE",
1273
+ message: usageMessage(BRANCH_BASE_USAGE, BRANCH_BASE_USAGE_EXAMPLE),
1274
+ });
1275
+ }
1276
+ return await cmdBranchBaseSet({
1277
+ cwd: process.cwd(),
1278
+ rootOverride: globals.root,
1279
+ value,
1280
+ });
1281
+ }
1282
+ throw new CliError({
1283
+ exitCode: 2,
1284
+ code: "E_USAGE",
1285
+ message: usageMessage(BRANCH_BASE_USAGE, BRANCH_BASE_USAGE_EXAMPLE),
1286
+ });
1287
+ }
1288
+ if (command === "status") {
1289
+ let branch;
1290
+ let base;
1291
+ for (let i = 0; i < args.length; i++) {
1292
+ const arg = args[i];
1293
+ if (!arg)
1294
+ continue;
1295
+ if (arg === "--branch") {
1296
+ const next = args[i + 1];
1297
+ if (!next)
1298
+ throw new CliError({
1299
+ exitCode: 2,
1300
+ code: "E_USAGE",
1301
+ message: usageMessage(BRANCH_STATUS_USAGE, BRANCH_STATUS_USAGE_EXAMPLE),
1302
+ });
1303
+ branch = next;
1304
+ i++;
1305
+ continue;
1306
+ }
1307
+ if (arg === "--base") {
1308
+ const next = args[i + 1];
1309
+ if (!next)
1310
+ throw new CliError({
1311
+ exitCode: 2,
1312
+ code: "E_USAGE",
1313
+ message: usageMessage(BRANCH_STATUS_USAGE, BRANCH_STATUS_USAGE_EXAMPLE),
1314
+ });
1315
+ base = next;
1316
+ i++;
1317
+ continue;
1318
+ }
1319
+ if (arg.startsWith("--")) {
1320
+ throw new CliError({
1321
+ exitCode: 2,
1322
+ code: "E_USAGE",
1323
+ message: usageMessage(BRANCH_STATUS_USAGE, BRANCH_STATUS_USAGE_EXAMPLE),
1324
+ });
1325
+ }
1326
+ }
1327
+ return await cmdBranchStatus({
1328
+ cwd: process.cwd(),
1329
+ rootOverride: globals.root,
1330
+ branch,
1331
+ base,
1332
+ });
1333
+ }
1334
+ if (command === "remove") {
1335
+ let branch;
1336
+ let worktree;
1337
+ let force = false;
1338
+ let quiet = false;
1339
+ for (let i = 0; i < args.length; i++) {
1340
+ const arg = args[i];
1341
+ if (!arg)
1342
+ continue;
1343
+ if (arg === "--branch") {
1344
+ const next = args[i + 1];
1345
+ if (!next)
1346
+ throw new CliError({
1347
+ exitCode: 2,
1348
+ code: "E_USAGE",
1349
+ message: usageMessage(BRANCH_REMOVE_USAGE, BRANCH_REMOVE_USAGE_EXAMPLE),
1350
+ });
1351
+ branch = next;
1352
+ i++;
1353
+ continue;
1354
+ }
1355
+ if (arg === "--worktree") {
1356
+ const next = args[i + 1];
1357
+ if (!next)
1358
+ throw new CliError({
1359
+ exitCode: 2,
1360
+ code: "E_USAGE",
1361
+ message: usageMessage(BRANCH_REMOVE_USAGE, BRANCH_REMOVE_USAGE_EXAMPLE),
1362
+ });
1363
+ worktree = next;
1364
+ i++;
1365
+ continue;
1366
+ }
1367
+ if (arg === "--force") {
1368
+ force = true;
1369
+ continue;
1370
+ }
1371
+ if (arg === "--quiet") {
1372
+ quiet = true;
1373
+ continue;
1374
+ }
1375
+ if (arg.startsWith("--")) {
1376
+ throw new CliError({
1377
+ exitCode: 2,
1378
+ code: "E_USAGE",
1379
+ message: usageMessage(BRANCH_REMOVE_USAGE, BRANCH_REMOVE_USAGE_EXAMPLE),
1380
+ });
1381
+ }
1382
+ }
1383
+ return await cmdBranchRemove({
1384
+ cwd: process.cwd(),
1385
+ rootOverride: globals.root,
1386
+ branch,
1387
+ worktree,
1388
+ force,
1389
+ quiet,
1390
+ });
1391
+ }
1392
+ throw new CliError({
1393
+ exitCode: 2,
1394
+ code: "E_USAGE",
1395
+ message: usageMessage(BRANCH_BASE_USAGE, BRANCH_BASE_USAGE_EXAMPLE),
1396
+ });
1397
+ }
1398
+ if (namespace === "work" && command === "start") {
1399
+ const [taskId, ...restArgs] = args;
1400
+ if (!taskId) {
1401
+ throw new CliError({
1402
+ exitCode: 2,
1403
+ code: "E_USAGE",
1404
+ message: usageMessage(WORK_START_USAGE, WORK_START_USAGE_EXAMPLE),
1405
+ });
1406
+ }
1407
+ let agent = "";
1408
+ let slug = "";
1409
+ let worktree = false;
1410
+ for (let i = 0; i < restArgs.length; i++) {
1411
+ const arg = restArgs[i];
1412
+ if (!arg)
1413
+ continue;
1414
+ if (arg === "--agent") {
1415
+ const next = restArgs[i + 1];
1416
+ if (!next)
1417
+ throw new CliError({
1418
+ exitCode: 2,
1419
+ code: "E_USAGE",
1420
+ message: usageMessage(WORK_START_USAGE, WORK_START_USAGE_EXAMPLE),
1421
+ });
1422
+ agent = next;
1423
+ i++;
1424
+ continue;
1425
+ }
1426
+ if (arg === "--slug") {
1427
+ const next = restArgs[i + 1];
1428
+ if (!next)
1429
+ throw new CliError({
1430
+ exitCode: 2,
1431
+ code: "E_USAGE",
1432
+ message: usageMessage(WORK_START_USAGE, WORK_START_USAGE_EXAMPLE),
1433
+ });
1434
+ slug = next;
1435
+ i++;
1436
+ continue;
1437
+ }
1438
+ if (arg === "--worktree") {
1439
+ worktree = true;
1440
+ continue;
1441
+ }
1442
+ throw new CliError({
1443
+ exitCode: 2,
1444
+ code: "E_USAGE",
1445
+ message: usageMessage(WORK_START_USAGE, WORK_START_USAGE_EXAMPLE),
1446
+ });
1447
+ }
1448
+ if (!agent || !slug || !worktree) {
1449
+ throw new CliError({
1450
+ exitCode: 2,
1451
+ code: "E_USAGE",
1452
+ message: usageMessage(WORK_START_USAGE, WORK_START_USAGE_EXAMPLE),
1453
+ });
1454
+ }
1455
+ return await cmdWorkStart({
1456
+ cwd: process.cwd(),
1457
+ rootOverride: globals.root,
1458
+ taskId,
1459
+ agent,
1460
+ slug,
1461
+ worktree,
1462
+ });
1463
+ }
1464
+ if (namespace === "pr") {
1465
+ const [taskId, ...restArgs] = args;
1466
+ if (!taskId) {
1467
+ throw new CliError({
1468
+ exitCode: 2,
1469
+ code: "E_USAGE",
1470
+ message: usageMessage(PR_OPEN_USAGE, PR_OPEN_USAGE_EXAMPLE),
1471
+ });
1472
+ }
1473
+ if (command === "open") {
1474
+ let author = "";
1475
+ let branch;
1476
+ for (let i = 0; i < restArgs.length; i++) {
1477
+ const arg = restArgs[i];
1478
+ if (!arg)
1479
+ continue;
1480
+ if (arg === "--author") {
1481
+ const next = restArgs[i + 1];
1482
+ if (!next)
1483
+ throw new CliError({
1484
+ exitCode: 2,
1485
+ code: "E_USAGE",
1486
+ message: usageMessage(PR_OPEN_USAGE, PR_OPEN_USAGE_EXAMPLE),
1487
+ });
1488
+ author = next;
1489
+ i++;
1490
+ continue;
1491
+ }
1492
+ if (arg === "--branch") {
1493
+ const next = restArgs[i + 1];
1494
+ if (!next)
1495
+ throw new CliError({
1496
+ exitCode: 2,
1497
+ code: "E_USAGE",
1498
+ message: usageMessage(PR_OPEN_USAGE, PR_OPEN_USAGE_EXAMPLE),
1499
+ });
1500
+ branch = next;
1501
+ i++;
1502
+ continue;
1503
+ }
1504
+ throw new CliError({
1505
+ exitCode: 2,
1506
+ code: "E_USAGE",
1507
+ message: usageMessage(PR_OPEN_USAGE, PR_OPEN_USAGE_EXAMPLE),
1508
+ });
1509
+ }
1510
+ if (!author) {
1511
+ throw new CliError({
1512
+ exitCode: 2,
1513
+ code: "E_USAGE",
1514
+ message: usageMessage(PR_OPEN_USAGE, PR_OPEN_USAGE_EXAMPLE),
1515
+ });
1516
+ }
1517
+ return await cmdPrOpen({
1518
+ cwd: process.cwd(),
1519
+ rootOverride: globals.root,
1520
+ taskId,
1521
+ author,
1522
+ branch,
1523
+ });
1524
+ }
1525
+ if (command === "update") {
1526
+ if (restArgs.length > 0) {
1527
+ throw new CliError({
1528
+ exitCode: 2,
1529
+ code: "E_USAGE",
1530
+ message: usageMessage(PR_UPDATE_USAGE, PR_UPDATE_USAGE_EXAMPLE),
1531
+ });
1532
+ }
1533
+ return await cmdPrUpdate({
1534
+ cwd: process.cwd(),
1535
+ rootOverride: globals.root,
1536
+ taskId,
1537
+ });
1538
+ }
1539
+ if (command === "check") {
1540
+ if (restArgs.length > 0) {
1541
+ throw new CliError({
1542
+ exitCode: 2,
1543
+ code: "E_USAGE",
1544
+ message: usageMessage(PR_CHECK_USAGE, PR_CHECK_USAGE_EXAMPLE),
1545
+ });
1546
+ }
1547
+ return await cmdPrCheck({
1548
+ cwd: process.cwd(),
1549
+ rootOverride: globals.root,
1550
+ taskId,
1551
+ });
1552
+ }
1553
+ if (command === "note") {
1554
+ let author = "";
1555
+ let body = "";
1556
+ for (let i = 0; i < restArgs.length; i++) {
1557
+ const arg = restArgs[i];
1558
+ if (!arg)
1559
+ continue;
1560
+ if (arg === "--author") {
1561
+ const next = restArgs[i + 1];
1562
+ if (!next)
1563
+ throw new CliError({
1564
+ exitCode: 2,
1565
+ code: "E_USAGE",
1566
+ message: usageMessage(PR_NOTE_USAGE, PR_NOTE_USAGE_EXAMPLE),
1567
+ });
1568
+ author = next;
1569
+ i++;
1570
+ continue;
1571
+ }
1572
+ if (arg === "--body") {
1573
+ const next = restArgs[i + 1];
1574
+ if (!next)
1575
+ throw new CliError({
1576
+ exitCode: 2,
1577
+ code: "E_USAGE",
1578
+ message: usageMessage(PR_NOTE_USAGE, PR_NOTE_USAGE_EXAMPLE),
1579
+ });
1580
+ body = next;
1581
+ i++;
1582
+ continue;
1583
+ }
1584
+ throw new CliError({
1585
+ exitCode: 2,
1586
+ code: "E_USAGE",
1587
+ message: usageMessage(PR_NOTE_USAGE, PR_NOTE_USAGE_EXAMPLE),
1588
+ });
1589
+ }
1590
+ if (!author || !body) {
1591
+ throw new CliError({
1592
+ exitCode: 2,
1593
+ code: "E_USAGE",
1594
+ message: usageMessage(PR_NOTE_USAGE, PR_NOTE_USAGE_EXAMPLE),
1595
+ });
1596
+ }
1597
+ return await cmdPrNote({
1598
+ cwd: process.cwd(),
1599
+ rootOverride: globals.root,
1600
+ taskId,
1601
+ author,
1602
+ body,
1603
+ });
1604
+ }
1605
+ throw new CliError({
1606
+ exitCode: 2,
1607
+ code: "E_USAGE",
1608
+ message: usageMessage(PR_GROUP_USAGE, PR_GROUP_USAGE_EXAMPLE),
1609
+ });
1610
+ }
1611
+ if (namespace === "guard") {
1612
+ const subcommand = command;
1613
+ const restArgs = args;
1614
+ if (subcommand === "clean") {
1615
+ const quiet = restArgs.includes("--quiet");
1616
+ return await cmdGuardClean({ cwd: process.cwd(), rootOverride: globals.root, quiet });
1617
+ }
1618
+ if (subcommand === "suggest-allow") {
1619
+ const formatFlagIndex = restArgs.indexOf("--format");
1620
+ let format = "lines";
1621
+ if (formatFlagIndex !== -1) {
1622
+ const next = restArgs[formatFlagIndex + 1];
1623
+ if (next !== "lines" && next !== "args") {
1624
+ throw new CliError({
1625
+ exitCode: 2,
1626
+ code: "E_USAGE",
1627
+ message: invalidValueForFlag("--format", String(next), "lines|args"),
1628
+ });
1629
+ }
1630
+ format = next;
1631
+ }
1632
+ return await cmdGuardSuggestAllow({
1633
+ cwd: process.cwd(),
1634
+ rootOverride: globals.root,
1635
+ format,
1636
+ });
1637
+ }
1638
+ if (subcommand === "commit") {
1639
+ const taskId = restArgs[0];
1640
+ if (!taskId) {
1641
+ throw new CliError({
1642
+ exitCode: 2,
1643
+ code: "E_USAGE",
1644
+ message: usageMessage(GUARD_COMMIT_USAGE, GUARD_COMMIT_USAGE_EXAMPLE),
1645
+ });
1646
+ }
1647
+ const allow = [];
1648
+ let message = "";
1649
+ let autoAllow = false;
1650
+ let allowTasks = false;
1651
+ let allowDirty = false;
1652
+ let requireClean = false;
1653
+ let quiet = false;
1654
+ for (let i = 1; i < restArgs.length; i++) {
1655
+ const arg = restArgs[i];
1656
+ if (!arg)
1657
+ continue;
1658
+ if (arg === "--allow") {
1659
+ const next = restArgs[i + 1];
1660
+ if (!next)
1661
+ throw new CliError({
1662
+ exitCode: 2,
1663
+ code: "E_USAGE",
1664
+ message: usageMessage(GUARD_COMMIT_USAGE, GUARD_COMMIT_USAGE_EXAMPLE),
1665
+ });
1666
+ allow.push(next);
1667
+ i++;
1668
+ continue;
1669
+ }
1670
+ if (arg === "-m" || arg === "--message") {
1671
+ const next = restArgs[i + 1];
1672
+ if (!next)
1673
+ throw new CliError({
1674
+ exitCode: 2,
1675
+ code: "E_USAGE",
1676
+ message: usageMessage(GUARD_COMMIT_USAGE, GUARD_COMMIT_USAGE_EXAMPLE),
1677
+ });
1678
+ message = next;
1679
+ i++;
1680
+ continue;
1681
+ }
1682
+ if (arg === "--allow-tasks") {
1683
+ allowTasks = true;
1684
+ continue;
1685
+ }
1686
+ if (arg === "--auto-allow") {
1687
+ autoAllow = true;
1688
+ continue;
1689
+ }
1690
+ if (arg === "--allow-dirty") {
1691
+ allowDirty = true;
1692
+ continue;
1693
+ }
1694
+ if (arg === "--require-clean") {
1695
+ requireClean = true;
1696
+ continue;
1697
+ }
1698
+ if (arg === "--quiet") {
1699
+ quiet = true;
1700
+ continue;
1701
+ }
1702
+ if (arg.startsWith("--")) {
1703
+ throw new CliError({
1704
+ exitCode: 2,
1705
+ code: "E_USAGE",
1706
+ message: usageMessage(GUARD_COMMIT_USAGE, GUARD_COMMIT_USAGE_EXAMPLE),
1707
+ });
1708
+ }
1709
+ }
1710
+ if (!message) {
1711
+ throw new CliError({
1712
+ exitCode: 2,
1713
+ code: "E_USAGE",
1714
+ message: usageMessage(GUARD_COMMIT_USAGE, GUARD_COMMIT_USAGE_EXAMPLE),
1715
+ });
1716
+ }
1717
+ if (autoAllow && allow.length === 0) {
1718
+ const staged = await getStagedFiles({
1719
+ cwd: process.cwd(),
1720
+ rootOverride: globals.root ?? null,
1721
+ });
1722
+ const prefixes = suggestAllowPrefixes(staged);
1723
+ if (prefixes.length === 0) {
1724
+ throw new CliError({
1725
+ exitCode: 5,
1726
+ code: "E_GIT",
1727
+ message: "No staged files (git index empty)",
1728
+ });
1729
+ }
1730
+ allow.push(...prefixes);
1731
+ }
1732
+ if (allowDirty) {
1733
+ // Deprecated no-op retained for compatibility.
1734
+ }
1735
+ return await cmdGuardCommit({
1736
+ cwd: process.cwd(),
1737
+ rootOverride: globals.root,
1738
+ taskId,
1739
+ message,
1740
+ allow,
1741
+ allowTasks,
1742
+ requireClean,
1743
+ quiet,
1744
+ });
1745
+ }
1746
+ throw new CliError({
1747
+ exitCode: 2,
1748
+ code: "E_USAGE",
1749
+ message: usageMessage(GUARD_USAGE, GUARD_USAGE_EXAMPLE),
1750
+ });
1751
+ }
1752
+ if (namespace === "commit") {
1753
+ const taskId = command;
1754
+ if (!taskId) {
1755
+ throw new CliError({
1756
+ exitCode: 2,
1757
+ code: "E_USAGE",
1758
+ message: usageMessage(COMMIT_USAGE, COMMIT_USAGE_EXAMPLE),
1759
+ });
1760
+ }
1761
+ const allow = [];
1762
+ let message = "";
1763
+ let autoAllow = false;
1764
+ let allowTasks = false;
1765
+ let allowBase = false;
1766
+ let requireClean = false;
1767
+ let quiet = false;
1768
+ for (let i = 0; i < args.length; i++) {
1769
+ const arg = args[i];
1770
+ if (!arg)
1771
+ continue;
1772
+ if (arg === "--allow") {
1773
+ const next = args[i + 1];
1774
+ if (!next)
1775
+ throw new CliError({
1776
+ exitCode: 2,
1777
+ code: "E_USAGE",
1778
+ message: usageMessage(COMMIT_USAGE, COMMIT_USAGE_EXAMPLE),
1779
+ });
1780
+ allow.push(next);
1781
+ i++;
1782
+ continue;
1783
+ }
1784
+ if (arg === "-m" || arg === "--message") {
1785
+ const next = args[i + 1];
1786
+ if (!next)
1787
+ throw new CliError({
1788
+ exitCode: 2,
1789
+ code: "E_USAGE",
1790
+ message: usageMessage(COMMIT_USAGE, COMMIT_USAGE_EXAMPLE),
1791
+ });
1792
+ message = next;
1793
+ i++;
1794
+ continue;
1795
+ }
1796
+ if (arg === "--auto-allow") {
1797
+ autoAllow = true;
1798
+ continue;
1799
+ }
1800
+ if (arg === "--allow-tasks") {
1801
+ allowTasks = true;
1802
+ continue;
1803
+ }
1804
+ if (arg === "--allow-base") {
1805
+ allowBase = true;
1806
+ continue;
1807
+ }
1808
+ if (arg === "--require-clean") {
1809
+ requireClean = true;
1810
+ continue;
1811
+ }
1812
+ if (arg === "--quiet") {
1813
+ quiet = true;
1814
+ continue;
1815
+ }
1816
+ if (arg.startsWith("--")) {
1817
+ throw new CliError({
1818
+ exitCode: 2,
1819
+ code: "E_USAGE",
1820
+ message: usageMessage(COMMIT_USAGE, COMMIT_USAGE_EXAMPLE),
1821
+ });
1822
+ }
1823
+ }
1824
+ if (!message) {
1825
+ throw new CliError({
1826
+ exitCode: 2,
1827
+ code: "E_USAGE",
1828
+ message: usageMessage(COMMIT_USAGE, COMMIT_USAGE_EXAMPLE),
1829
+ });
1830
+ }
1831
+ return await cmdCommit({
1832
+ cwd: process.cwd(),
1833
+ rootOverride: globals.root,
1834
+ taskId,
1835
+ message,
1836
+ allow,
1837
+ autoAllow,
1838
+ allowTasks,
1839
+ allowBase,
1840
+ requireClean,
1841
+ quiet,
1842
+ });
1843
+ }
1844
+ if (namespace === "start") {
1845
+ let taskId = command;
1846
+ let startArgs = args;
1847
+ if (!taskId || taskId.startsWith("-")) {
1848
+ if (taskId?.startsWith("-")) {
1849
+ startArgs = [taskId, ...args];
1850
+ }
1851
+ taskId = process.env.AGENTPLANE_TASK_ID ?? "";
1852
+ }
1853
+ if (!taskId) {
1854
+ throw new CliError({
1855
+ exitCode: 2,
1856
+ code: "E_USAGE",
1857
+ message: usageMessage(START_USAGE, START_USAGE_EXAMPLE),
1858
+ });
1859
+ }
1860
+ let author = "";
1861
+ let body = "";
1862
+ let commitFromComment = false;
1863
+ let commitEmoji;
1864
+ const commitAllow = [];
1865
+ let commitAutoAllow = false;
1866
+ let commitAllowTasks = true;
1867
+ let commitRequireClean = false;
1868
+ let confirmStatusCommit = false;
1869
+ let force = false;
1870
+ let quiet = false;
1871
+ for (let i = 0; i < startArgs.length; i++) {
1872
+ const arg = startArgs[i];
1873
+ if (!arg)
1874
+ continue;
1875
+ if (arg === "--author") {
1876
+ const next = startArgs[i + 1];
1877
+ if (!next)
1878
+ throw new CliError({
1879
+ exitCode: 2,
1880
+ code: "E_USAGE",
1881
+ message: usageMessage(START_USAGE, START_USAGE_EXAMPLE),
1882
+ });
1883
+ author = next;
1884
+ i++;
1885
+ continue;
1886
+ }
1887
+ if (arg === "--body") {
1888
+ const next = startArgs[i + 1];
1889
+ if (!next)
1890
+ throw new CliError({
1891
+ exitCode: 2,
1892
+ code: "E_USAGE",
1893
+ message: usageMessage(START_USAGE, START_USAGE_EXAMPLE),
1894
+ });
1895
+ body = next;
1896
+ i++;
1897
+ continue;
1898
+ }
1899
+ if (arg === "--commit-from-comment") {
1900
+ commitFromComment = true;
1901
+ continue;
1902
+ }
1903
+ if (arg === "--commit-emoji") {
1904
+ const next = startArgs[i + 1];
1905
+ if (!next)
1906
+ throw new CliError({
1907
+ exitCode: 2,
1908
+ code: "E_USAGE",
1909
+ message: usageMessage(START_USAGE, START_USAGE_EXAMPLE),
1910
+ });
1911
+ commitEmoji = next;
1912
+ i++;
1913
+ continue;
1914
+ }
1915
+ if (arg === "--commit-allow") {
1916
+ const next = startArgs[i + 1];
1917
+ if (!next)
1918
+ throw new CliError({
1919
+ exitCode: 2,
1920
+ code: "E_USAGE",
1921
+ message: usageMessage(START_USAGE, START_USAGE_EXAMPLE),
1922
+ });
1923
+ commitAllow.push(next);
1924
+ i++;
1925
+ continue;
1926
+ }
1927
+ if (arg === "--commit-auto-allow") {
1928
+ commitAutoAllow = true;
1929
+ continue;
1930
+ }
1931
+ if (arg === "--commit-allow-tasks") {
1932
+ commitAllowTasks = true;
1933
+ continue;
1934
+ }
1935
+ if (arg === "--commit-require-clean") {
1936
+ commitRequireClean = true;
1937
+ continue;
1938
+ }
1939
+ if (arg === "--confirm-status-commit") {
1940
+ confirmStatusCommit = true;
1941
+ continue;
1942
+ }
1943
+ if (arg === "--force") {
1944
+ force = true;
1945
+ continue;
1946
+ }
1947
+ if (arg === "--quiet") {
1948
+ quiet = true;
1949
+ continue;
1950
+ }
1951
+ if (arg.startsWith("--")) {
1952
+ throw new CliError({
1953
+ exitCode: 2,
1954
+ code: "E_USAGE",
1955
+ message: usageMessage(START_USAGE, START_USAGE_EXAMPLE),
1956
+ });
1957
+ }
1958
+ }
1959
+ if (!author || !body) {
1960
+ throw new CliError({
1961
+ exitCode: 2,
1962
+ code: "E_USAGE",
1963
+ message: usageMessage(START_USAGE, START_USAGE_EXAMPLE),
1964
+ });
1965
+ }
1966
+ return await cmdStart({
1967
+ cwd: process.cwd(),
1968
+ rootOverride: globals.root,
1969
+ taskId,
1970
+ author,
1971
+ body,
1972
+ commitFromComment,
1973
+ commitEmoji,
1974
+ commitAllow,
1975
+ commitAutoAllow,
1976
+ commitAllowTasks,
1977
+ commitRequireClean,
1978
+ confirmStatusCommit,
1979
+ force,
1980
+ quiet,
1981
+ });
1982
+ }
1983
+ if (namespace === "block") {
1984
+ let taskId = command;
1985
+ let blockArgs = args;
1986
+ if (!taskId || taskId.startsWith("-")) {
1987
+ if (taskId?.startsWith("-")) {
1988
+ blockArgs = [taskId, ...args];
1989
+ }
1990
+ taskId = process.env.AGENTPLANE_TASK_ID ?? "";
1991
+ }
1992
+ if (!taskId) {
1993
+ throw new CliError({
1994
+ exitCode: 2,
1995
+ code: "E_USAGE",
1996
+ message: usageMessage(BLOCK_USAGE, BLOCK_USAGE_EXAMPLE),
1997
+ });
1998
+ }
1999
+ let author = "";
2000
+ let body = "";
2001
+ let commitFromComment = false;
2002
+ let commitEmoji;
2003
+ const commitAllow = [];
2004
+ let commitAutoAllow = false;
2005
+ let commitAllowTasks = true;
2006
+ let commitRequireClean = false;
2007
+ let confirmStatusCommit = false;
2008
+ let force = false;
2009
+ let quiet = false;
2010
+ for (let i = 0; i < blockArgs.length; i++) {
2011
+ const arg = blockArgs[i];
2012
+ if (!arg)
2013
+ continue;
2014
+ if (arg === "--author") {
2015
+ const next = blockArgs[i + 1];
2016
+ if (!next)
2017
+ throw new CliError({
2018
+ exitCode: 2,
2019
+ code: "E_USAGE",
2020
+ message: usageMessage(BLOCK_USAGE, BLOCK_USAGE_EXAMPLE),
2021
+ });
2022
+ author = next;
2023
+ i++;
2024
+ continue;
2025
+ }
2026
+ if (arg === "--body") {
2027
+ const next = blockArgs[i + 1];
2028
+ if (!next)
2029
+ throw new CliError({
2030
+ exitCode: 2,
2031
+ code: "E_USAGE",
2032
+ message: usageMessage(BLOCK_USAGE, BLOCK_USAGE_EXAMPLE),
2033
+ });
2034
+ body = next;
2035
+ i++;
2036
+ continue;
2037
+ }
2038
+ if (arg === "--commit-from-comment") {
2039
+ commitFromComment = true;
2040
+ continue;
2041
+ }
2042
+ if (arg === "--commit-emoji") {
2043
+ const next = blockArgs[i + 1];
2044
+ if (!next)
2045
+ throw new CliError({
2046
+ exitCode: 2,
2047
+ code: "E_USAGE",
2048
+ message: usageMessage(BLOCK_USAGE, BLOCK_USAGE_EXAMPLE),
2049
+ });
2050
+ commitEmoji = next;
2051
+ i++;
2052
+ continue;
2053
+ }
2054
+ if (arg === "--commit-allow") {
2055
+ const next = blockArgs[i + 1];
2056
+ if (!next)
2057
+ throw new CliError({
2058
+ exitCode: 2,
2059
+ code: "E_USAGE",
2060
+ message: usageMessage(BLOCK_USAGE, BLOCK_USAGE_EXAMPLE),
2061
+ });
2062
+ commitAllow.push(next);
2063
+ i++;
2064
+ continue;
2065
+ }
2066
+ if (arg === "--commit-auto-allow") {
2067
+ commitAutoAllow = true;
2068
+ continue;
2069
+ }
2070
+ if (arg === "--commit-allow-tasks") {
2071
+ commitAllowTasks = true;
2072
+ continue;
2073
+ }
2074
+ if (arg === "--commit-require-clean") {
2075
+ commitRequireClean = true;
2076
+ continue;
2077
+ }
2078
+ if (arg === "--confirm-status-commit") {
2079
+ confirmStatusCommit = true;
2080
+ continue;
2081
+ }
2082
+ if (arg === "--force") {
2083
+ force = true;
2084
+ continue;
2085
+ }
2086
+ if (arg === "--quiet") {
2087
+ quiet = true;
2088
+ continue;
2089
+ }
2090
+ if (arg.startsWith("--")) {
2091
+ throw new CliError({
2092
+ exitCode: 2,
2093
+ code: "E_USAGE",
2094
+ message: usageMessage(BLOCK_USAGE, BLOCK_USAGE_EXAMPLE),
2095
+ });
2096
+ }
2097
+ }
2098
+ if (!author || !body) {
2099
+ throw new CliError({
2100
+ exitCode: 2,
2101
+ code: "E_USAGE",
2102
+ message: usageMessage(BLOCK_USAGE, BLOCK_USAGE_EXAMPLE),
2103
+ });
2104
+ }
2105
+ return await cmdBlock({
2106
+ cwd: process.cwd(),
2107
+ rootOverride: globals.root,
2108
+ taskId,
2109
+ author,
2110
+ body,
2111
+ commitFromComment,
2112
+ commitEmoji,
2113
+ commitAllow,
2114
+ commitAutoAllow,
2115
+ commitAllowTasks,
2116
+ commitRequireClean,
2117
+ confirmStatusCommit,
2118
+ force,
2119
+ quiet,
2120
+ });
2121
+ }
2122
+ if (namespace === "finish") {
2123
+ let finishArgs = args;
2124
+ const taskIds = [];
2125
+ if (command && !command.startsWith("--")) {
2126
+ taskIds.push(command);
2127
+ }
2128
+ else if (command?.startsWith("-")) {
2129
+ finishArgs = [command, ...args];
2130
+ }
2131
+ let argIndex = 0;
2132
+ while (argIndex < finishArgs.length) {
2133
+ const arg = finishArgs[argIndex];
2134
+ if (!arg || arg.startsWith("--"))
2135
+ break;
2136
+ taskIds.push(arg);
2137
+ argIndex += 1;
2138
+ }
2139
+ const flagArgs = finishArgs.slice(argIndex);
2140
+ if (taskIds.length === 0) {
2141
+ const envTaskId = process.env.AGENTPLANE_TASK_ID ?? "";
2142
+ if (envTaskId)
2143
+ taskIds.push(envTaskId);
2144
+ }
2145
+ if (taskIds.length === 0) {
2146
+ throw new CliError({
2147
+ exitCode: 2,
2148
+ code: "E_USAGE",
2149
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2150
+ });
2151
+ }
2152
+ let author = "";
2153
+ let body = "";
2154
+ let commit;
2155
+ let skipVerify = false;
2156
+ let force = false;
2157
+ let noRequireTaskIdInCommit = false;
2158
+ let commitFromComment = false;
2159
+ let commitEmoji;
2160
+ const commitAllow = [];
2161
+ let commitAutoAllow = false;
2162
+ let commitAllowTasks = true;
2163
+ let commitRequireClean = false;
2164
+ let statusCommit = false;
2165
+ let statusCommitEmoji;
2166
+ const statusCommitAllow = [];
2167
+ let statusCommitAutoAllow = false;
2168
+ let statusCommitRequireClean = false;
2169
+ let confirmStatusCommit = false;
2170
+ let quiet = false;
2171
+ for (let i = 0; i < flagArgs.length; i++) {
2172
+ const arg = flagArgs[i];
2173
+ if (!arg)
2174
+ continue;
2175
+ if (arg === "--author") {
2176
+ const next = flagArgs[i + 1];
2177
+ if (!next)
2178
+ throw new CliError({
2179
+ exitCode: 2,
2180
+ code: "E_USAGE",
2181
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2182
+ });
2183
+ author = next;
2184
+ i++;
2185
+ continue;
2186
+ }
2187
+ if (arg === "--body") {
2188
+ const next = flagArgs[i + 1];
2189
+ if (!next)
2190
+ throw new CliError({
2191
+ exitCode: 2,
2192
+ code: "E_USAGE",
2193
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2194
+ });
2195
+ body = next;
2196
+ i++;
2197
+ continue;
2198
+ }
2199
+ if (arg === "--commit") {
2200
+ const next = flagArgs[i + 1];
2201
+ if (!next)
2202
+ throw new CliError({
2203
+ exitCode: 2,
2204
+ code: "E_USAGE",
2205
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2206
+ });
2207
+ commit = next;
2208
+ i++;
2209
+ continue;
2210
+ }
2211
+ if (arg === "--skip-verify") {
2212
+ skipVerify = true;
2213
+ continue;
2214
+ }
2215
+ if (arg === "--quiet") {
2216
+ quiet = true;
2217
+ continue;
2218
+ }
2219
+ if (arg === "--force") {
2220
+ force = true;
2221
+ continue;
2222
+ }
2223
+ if (arg === "--no-require-task-id-in-commit") {
2224
+ noRequireTaskIdInCommit = true;
2225
+ continue;
2226
+ }
2227
+ if (arg === "--commit-from-comment") {
2228
+ commitFromComment = true;
2229
+ continue;
2230
+ }
2231
+ if (arg === "--commit-emoji") {
2232
+ const next = flagArgs[i + 1];
2233
+ if (!next)
2234
+ throw new CliError({
2235
+ exitCode: 2,
2236
+ code: "E_USAGE",
2237
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2238
+ });
2239
+ commitEmoji = next;
2240
+ i++;
2241
+ continue;
2242
+ }
2243
+ if (arg === "--commit-allow") {
2244
+ const next = flagArgs[i + 1];
2245
+ if (!next)
2246
+ throw new CliError({
2247
+ exitCode: 2,
2248
+ code: "E_USAGE",
2249
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2250
+ });
2251
+ commitAllow.push(next);
2252
+ i++;
2253
+ continue;
2254
+ }
2255
+ if (arg === "--commit-auto-allow") {
2256
+ commitAutoAllow = true;
2257
+ continue;
2258
+ }
2259
+ if (arg === "--commit-allow-tasks") {
2260
+ commitAllowTasks = true;
2261
+ continue;
2262
+ }
2263
+ if (arg === "--commit-require-clean") {
2264
+ commitRequireClean = true;
2265
+ continue;
2266
+ }
2267
+ if (arg === "--status-commit") {
2268
+ statusCommit = true;
2269
+ continue;
2270
+ }
2271
+ if (arg === "--status-commit-emoji") {
2272
+ const next = flagArgs[i + 1];
2273
+ if (!next)
2274
+ throw new CliError({
2275
+ exitCode: 2,
2276
+ code: "E_USAGE",
2277
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2278
+ });
2279
+ statusCommitEmoji = next;
2280
+ i++;
2281
+ continue;
2282
+ }
2283
+ if (arg === "--status-commit-allow") {
2284
+ const next = flagArgs[i + 1];
2285
+ if (!next)
2286
+ throw new CliError({
2287
+ exitCode: 2,
2288
+ code: "E_USAGE",
2289
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2290
+ });
2291
+ statusCommitAllow.push(next);
2292
+ i++;
2293
+ continue;
2294
+ }
2295
+ if (arg === "--status-commit-auto-allow") {
2296
+ statusCommitAutoAllow = true;
2297
+ continue;
2298
+ }
2299
+ if (arg === "--status-commit-require-clean") {
2300
+ statusCommitRequireClean = true;
2301
+ continue;
2302
+ }
2303
+ if (arg === "--confirm-status-commit") {
2304
+ confirmStatusCommit = true;
2305
+ continue;
2306
+ }
2307
+ if (arg.startsWith("--")) {
2308
+ throw new CliError({
2309
+ exitCode: 2,
2310
+ code: "E_USAGE",
2311
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2312
+ });
2313
+ }
2314
+ }
2315
+ if (!author || !body) {
2316
+ throw new CliError({
2317
+ exitCode: 2,
2318
+ code: "E_USAGE",
2319
+ message: usageMessage(FINISH_USAGE, FINISH_USAGE_EXAMPLE),
2320
+ });
2321
+ }
2322
+ return await cmdFinish({
2323
+ cwd: process.cwd(),
2324
+ rootOverride: globals.root,
2325
+ taskIds,
2326
+ author,
2327
+ body,
2328
+ commit,
2329
+ skipVerify,
2330
+ force,
2331
+ noRequireTaskIdInCommit,
2332
+ commitFromComment,
2333
+ commitEmoji,
2334
+ commitAllow,
2335
+ commitAutoAllow,
2336
+ commitAllowTasks,
2337
+ commitRequireClean,
2338
+ statusCommit,
2339
+ statusCommitEmoji,
2340
+ statusCommitAllow,
2341
+ statusCommitAutoAllow,
2342
+ statusCommitRequireClean,
2343
+ confirmStatusCommit,
2344
+ quiet,
2345
+ });
2346
+ }
2347
+ if (namespace === "verify") {
2348
+ let taskId = command;
2349
+ let verifyArgs = args;
2350
+ if (!taskId || taskId.startsWith("-")) {
2351
+ if (taskId?.startsWith("-")) {
2352
+ verifyArgs = [taskId, ...args];
2353
+ }
2354
+ taskId = process.env.AGENTPLANE_TASK_ID ?? "";
2355
+ }
2356
+ if (!taskId) {
2357
+ throw new CliError({
2358
+ exitCode: 2,
2359
+ code: "E_USAGE",
2360
+ message: usageMessage(VERIFY_USAGE, VERIFY_USAGE_EXAMPLE),
2361
+ });
2362
+ }
2363
+ let cwdOverride;
2364
+ let logPath;
2365
+ let skipIfUnchanged = false;
2366
+ let quiet = false;
2367
+ let require = false;
2368
+ let yes = false;
2369
+ for (let i = 0; i < verifyArgs.length; i++) {
2370
+ const arg = verifyArgs[i];
2371
+ if (!arg)
2372
+ continue;
2373
+ if (arg === "--cwd") {
2374
+ const next = verifyArgs[i + 1];
2375
+ if (!next)
2376
+ throw new CliError({
2377
+ exitCode: 2,
2378
+ code: "E_USAGE",
2379
+ message: usageMessage(VERIFY_USAGE, VERIFY_USAGE_EXAMPLE),
2380
+ });
2381
+ cwdOverride = next;
2382
+ i++;
2383
+ continue;
2384
+ }
2385
+ if (arg === "--log") {
2386
+ const next = verifyArgs[i + 1];
2387
+ if (!next)
2388
+ throw new CliError({
2389
+ exitCode: 2,
2390
+ code: "E_USAGE",
2391
+ message: usageMessage(VERIFY_USAGE, VERIFY_USAGE_EXAMPLE),
2392
+ });
2393
+ logPath = next;
2394
+ i++;
2395
+ continue;
2396
+ }
2397
+ if (arg === "--skip-if-unchanged") {
2398
+ skipIfUnchanged = true;
2399
+ continue;
2400
+ }
2401
+ if (arg === "--quiet") {
2402
+ quiet = true;
2403
+ continue;
2404
+ }
2405
+ if (arg === "--require") {
2406
+ require = true;
2407
+ continue;
2408
+ }
2409
+ if (arg === "--yes") {
2410
+ yes = true;
2411
+ continue;
2412
+ }
2413
+ if (arg.startsWith("--")) {
2414
+ throw new CliError({
2415
+ exitCode: 2,
2416
+ code: "E_USAGE",
2417
+ message: usageMessage(VERIFY_USAGE, VERIFY_USAGE_EXAMPLE),
2418
+ });
2419
+ }
2420
+ }
2421
+ return await cmdVerify({
2422
+ cwd: process.cwd(),
2423
+ rootOverride: globals.root,
2424
+ taskId,
2425
+ execCwd: cwdOverride,
2426
+ logPath,
2427
+ skipIfUnchanged,
2428
+ quiet,
2429
+ require,
2430
+ yes,
2431
+ });
2432
+ }
2433
+ if (namespace === "integrate") {
2434
+ const taskId = command;
2435
+ if (!taskId) {
2436
+ throw new CliError({
2437
+ exitCode: 2,
2438
+ code: "E_USAGE",
2439
+ message: usageMessage(INTEGRATE_USAGE, INTEGRATE_USAGE_EXAMPLE),
2440
+ });
2441
+ }
2442
+ let branch;
2443
+ let base;
2444
+ let mergeStrategy = "squash";
2445
+ let runVerify = false;
2446
+ let dryRun = false;
2447
+ let quiet = false;
2448
+ for (let i = 0; i < args.length; i++) {
2449
+ const arg = args[i];
2450
+ if (!arg)
2451
+ continue;
2452
+ if (arg === "--branch") {
2453
+ const next = args[i + 1];
2454
+ if (!next)
2455
+ throw new CliError({
2456
+ exitCode: 2,
2457
+ code: "E_USAGE",
2458
+ message: usageMessage(INTEGRATE_USAGE, INTEGRATE_USAGE_EXAMPLE),
2459
+ });
2460
+ branch = next;
2461
+ i++;
2462
+ continue;
2463
+ }
2464
+ if (arg === "--base") {
2465
+ const next = args[i + 1];
2466
+ if (!next)
2467
+ throw new CliError({
2468
+ exitCode: 2,
2469
+ code: "E_USAGE",
2470
+ message: usageMessage(INTEGRATE_USAGE, INTEGRATE_USAGE_EXAMPLE),
2471
+ });
2472
+ base = next;
2473
+ i++;
2474
+ continue;
2475
+ }
2476
+ if (arg === "--merge-strategy") {
2477
+ const next = args[i + 1];
2478
+ if (next !== "squash" && next !== "merge" && next !== "rebase") {
2479
+ throw new CliError({
2480
+ exitCode: 2,
2481
+ code: "E_USAGE",
2482
+ message: usageMessage(INTEGRATE_USAGE, INTEGRATE_USAGE_EXAMPLE),
2483
+ });
2484
+ }
2485
+ mergeStrategy = next;
2486
+ i++;
2487
+ continue;
2488
+ }
2489
+ if (arg === "--run-verify") {
2490
+ runVerify = true;
2491
+ continue;
2492
+ }
2493
+ if (arg === "--dry-run") {
2494
+ dryRun = true;
2495
+ continue;
2496
+ }
2497
+ if (arg === "--quiet") {
2498
+ quiet = true;
2499
+ continue;
2500
+ }
2501
+ if (arg.startsWith("--")) {
2502
+ throw new CliError({
2503
+ exitCode: 2,
2504
+ code: "E_USAGE",
2505
+ message: usageMessage(INTEGRATE_USAGE, INTEGRATE_USAGE_EXAMPLE),
2506
+ });
2507
+ }
2508
+ throw new CliError({
2509
+ exitCode: 2,
2510
+ code: "E_USAGE",
2511
+ message: usageMessage(INTEGRATE_USAGE, INTEGRATE_USAGE_EXAMPLE),
2512
+ });
2513
+ }
2514
+ return await cmdIntegrate({
2515
+ cwd: process.cwd(),
2516
+ rootOverride: globals.root,
2517
+ taskId,
2518
+ branch,
2519
+ base,
2520
+ mergeStrategy,
2521
+ runVerify,
2522
+ dryRun,
2523
+ quiet,
2524
+ });
2525
+ }
2526
+ if (namespace === "cleanup") {
2527
+ const subcommand = command;
2528
+ if (subcommand !== "merged") {
2529
+ throw new CliError({
2530
+ exitCode: 2,
2531
+ code: "E_USAGE",
2532
+ message: usageMessage(CLEANUP_MERGED_USAGE, CLEANUP_MERGED_USAGE_EXAMPLE),
2533
+ });
2534
+ }
2535
+ let base;
2536
+ let yes = false;
2537
+ let archive = false;
2538
+ let quiet = false;
2539
+ for (let i = 0; i < args.length; i++) {
2540
+ const arg = args[i];
2541
+ if (!arg)
2542
+ continue;
2543
+ if (arg === "--base") {
2544
+ const next = args[i + 1];
2545
+ if (!next)
2546
+ throw new CliError({
2547
+ exitCode: 2,
2548
+ code: "E_USAGE",
2549
+ message: usageMessage(CLEANUP_MERGED_USAGE, CLEANUP_MERGED_USAGE_EXAMPLE),
2550
+ });
2551
+ base = next;
2552
+ i++;
2553
+ continue;
2554
+ }
2555
+ if (arg === "--yes") {
2556
+ yes = true;
2557
+ continue;
2558
+ }
2559
+ if (arg === "--archive") {
2560
+ archive = true;
2561
+ continue;
2562
+ }
2563
+ if (arg === "--quiet") {
2564
+ quiet = true;
2565
+ continue;
2566
+ }
2567
+ if (arg.startsWith("--")) {
2568
+ throw new CliError({
2569
+ exitCode: 2,
2570
+ code: "E_USAGE",
2571
+ message: usageMessage(CLEANUP_MERGED_USAGE, CLEANUP_MERGED_USAGE_EXAMPLE),
2572
+ });
2573
+ }
2574
+ throw new CliError({
2575
+ exitCode: 2,
2576
+ code: "E_USAGE",
2577
+ message: usageMessage(CLEANUP_MERGED_USAGE, CLEANUP_MERGED_USAGE_EXAMPLE),
2578
+ });
2579
+ }
2580
+ return await cmdCleanupMerged({
2581
+ cwd: process.cwd(),
2582
+ rootOverride: globals.root,
2583
+ base,
2584
+ yes,
2585
+ archive,
2586
+ quiet,
2587
+ });
2588
+ }
2589
+ if (namespace === "scenario") {
2590
+ return await cmdScenario({
2591
+ cwd: process.cwd(),
2592
+ rootOverride: globals.root,
2593
+ command,
2594
+ args,
2595
+ });
2596
+ }
2597
+ if (namespace === "recipe" || namespace === "recipes") {
2598
+ return await cmdRecipes({
2599
+ cwd: process.cwd(),
2600
+ rootOverride: globals.root,
2601
+ command,
2602
+ args,
2603
+ });
2604
+ }
2605
+ if (namespace === "backend") {
2606
+ const subcommand = command;
2607
+ if (subcommand !== "sync") {
2608
+ throw new CliError({
2609
+ exitCode: 2,
2610
+ code: "E_USAGE",
2611
+ message: usageMessage(BACKEND_SYNC_USAGE, BACKEND_SYNC_USAGE_EXAMPLE),
2612
+ });
2613
+ }
2614
+ return await cmdBackendSync({
2615
+ cwd: process.cwd(),
2616
+ rootOverride: globals.root,
2617
+ args,
2618
+ });
2619
+ }
2620
+ if (namespace === "sync") {
2621
+ const syncArgs = command ? [command, ...args] : [];
2622
+ if (command?.startsWith("--")) {
2623
+ syncArgs.shift();
2624
+ syncArgs.unshift(command, ...args);
2625
+ }
2626
+ return await cmdSync({
2627
+ cwd: process.cwd(),
2628
+ rootOverride: globals.root,
2629
+ args: syncArgs,
2630
+ });
2631
+ }
2632
+ if (namespace === "hooks") {
2633
+ const subcommand = command;
2634
+ const restArgs = args;
2635
+ if (subcommand === "install") {
2636
+ const quiet = restArgs.includes("--quiet");
2637
+ return await cmdHooksInstall({ cwd: process.cwd(), rootOverride: globals.root, quiet });
2638
+ }
2639
+ if (subcommand === "uninstall") {
2640
+ const quiet = restArgs.includes("--quiet");
2641
+ return await cmdHooksUninstall({ cwd: process.cwd(), rootOverride: globals.root, quiet });
2642
+ }
2643
+ if (subcommand === "run") {
2644
+ const hook = restArgs[0];
2645
+ if (!hook || !HOOK_NAMES.includes(hook)) {
2646
+ throw new CliError({
2647
+ exitCode: 2,
2648
+ code: "E_USAGE",
2649
+ message: usageMessage(HOOKS_RUN_USAGE, HOOKS_RUN_USAGE_EXAMPLE),
2650
+ });
2651
+ }
2652
+ return await cmdHooksRun({
2653
+ cwd: process.cwd(),
2654
+ rootOverride: globals.root,
2655
+ hook,
2656
+ args: restArgs.slice(1),
2657
+ });
2658
+ }
2659
+ throw new CliError({
2660
+ exitCode: 2,
2661
+ code: "E_USAGE",
2662
+ message: usageMessage(HOOKS_INSTALL_USAGE, HOOKS_INSTALL_USAGE_EXAMPLE),
2663
+ });
2664
+ }
2665
+ throw new CliError({
2666
+ exitCode: 2,
2667
+ code: "E_USAGE",
2668
+ message: "Not implemented yet. Run `agentplane --help`.",
2669
+ });
2670
+ }
2671
+ catch (err) {
2672
+ if (err instanceof CliError) {
2673
+ writeError(err, jsonErrors);
2674
+ return err.exitCode;
2675
+ }
2676
+ const message = err instanceof Error ? err.message : String(err);
2677
+ const wrapped = new CliError({ exitCode: 1, code: "E_INTERNAL", message });
2678
+ writeError(wrapped, jsonErrors);
2679
+ return wrapped.exitCode;
2680
+ }
2681
+ }