agentplane 0.2.12 → 0.2.13

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 (43) hide show
  1. package/dist/cli/command-guide.js +1 -1
  2. package/dist/cli/run-cli/command-catalog.js +4 -4
  3. package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
  4. package/dist/cli/run-cli/commands/config.js +17 -38
  5. package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
  6. package/dist/cli/run-cli/commands/core.js +100 -71
  7. package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
  8. package/dist/cli/run-cli/commands/ide.js +3 -9
  9. package/dist/cli/run-cli/commands/init/write-gitignore.d.ts +2 -1
  10. package/dist/cli/run-cli/commands/init/write-gitignore.d.ts.map +1 -1
  11. package/dist/cli/run-cli/commands/init/write-gitignore.js +19 -6
  12. package/dist/cli/run-cli/commands/init.js +5 -2
  13. package/dist/cli/run-cli/commands/wrap-command.d.ts +6 -0
  14. package/dist/cli/run-cli/commands/wrap-command.d.ts.map +1 -0
  15. package/dist/cli/run-cli/commands/wrap-command.js +17 -0
  16. package/dist/cli/run-cli.d.ts.map +1 -1
  17. package/dist/cli/run-cli.js +5 -3
  18. package/dist/commands/doctor.command.d.ts +2 -7
  19. package/dist/commands/doctor.command.d.ts.map +1 -1
  20. package/dist/commands/doctor.command.js +2 -137
  21. package/dist/commands/doctor.run.d.ts +4 -0
  22. package/dist/commands/doctor.run.d.ts.map +1 -0
  23. package/dist/commands/doctor.run.js +174 -0
  24. package/dist/commands/doctor.spec.d.ts +7 -0
  25. package/dist/commands/doctor.spec.d.ts.map +1 -0
  26. package/dist/commands/doctor.spec.js +20 -0
  27. package/dist/commands/recipes/install.command.d.ts +2 -11
  28. package/dist/commands/recipes/install.command.d.ts.map +1 -1
  29. package/dist/commands/recipes/install.command.js +2 -161
  30. package/dist/commands/recipes/install.run.d.ts +4 -0
  31. package/dist/commands/recipes/install.run.d.ts.map +1 -0
  32. package/dist/commands/recipes/install.run.js +23 -0
  33. package/dist/commands/recipes/install.spec.d.ts +11 -0
  34. package/dist/commands/recipes/install.spec.d.ts.map +1 -0
  35. package/dist/commands/recipes/install.spec.js +140 -0
  36. package/dist/commands/shared/git-context.d.ts +3 -0
  37. package/dist/commands/shared/git-context.d.ts.map +1 -1
  38. package/dist/commands/shared/git-context.js +10 -0
  39. package/dist/commands/task/finish.d.ts.map +1 -1
  40. package/dist/commands/task/finish.js +34 -2
  41. package/dist/commands/upgrade.d.ts.map +1 -1
  42. package/dist/commands/upgrade.js +23 -2
  43. package/package.json +1 -1
@@ -244,7 +244,7 @@ export function renderQuickstart() {
244
244
  "## Global flags",
245
245
  "",
246
246
  "- `--root <path>`: treat <path> as project root",
247
- "- `--json`: emit JSON-formatted errors",
247
+ "- `--json-errors`: emit JSON-formatted errors",
248
248
  "- `--help` / `-h`: show help",
249
249
  "- `--version`: show version",
250
250
  "- `--no-update-check`: skip checking npm for a newer CLI version",
@@ -34,7 +34,7 @@ import { workStartSpec } from "../../commands/branch/work-start.command.js";
34
34
  import { branchBaseClearSpec, branchBaseExplainSpec, branchBaseGetSpec, branchBaseSetSpec, branchBaseSpec, } from "../../commands/branch/base.command.js";
35
35
  import { branchStatusSpec } from "../../commands/branch/status.command.js";
36
36
  import { branchRemoveSpec } from "../../commands/branch/remove.command.js";
37
- import { recipesInstallSpec } from "../../commands/recipes/install.command.js";
37
+ import { recipesInstallSpec } from "../../commands/recipes/install.spec.js";
38
38
  import { recipesListSpec } from "../../commands/recipes/list.command.js";
39
39
  import { recipesListRemoteSpec } from "../../commands/recipes/list-remote.command.js";
40
40
  import { recipesInfoSpec } from "../../commands/recipes/info.command.js";
@@ -58,7 +58,7 @@ import { blockSpec } from "../../commands/block.spec.js";
58
58
  import { verifySpec } from "../../commands/verify.spec.js";
59
59
  import { finishSpec } from "../../commands/finish.spec.js";
60
60
  import { readySpec } from "../../commands/ready.command.js";
61
- import { doctorSpec } from "../../commands/doctor.command.js";
61
+ import { doctorSpec } from "../../commands/doctor.spec.js";
62
62
  import { docsCliSpec } from "../../commands/docs/cli.command.js";
63
63
  import { hooksSpec } from "../../commands/hooks/hooks.command.js";
64
64
  import { hooksInstallSpec } from "../../commands/hooks/install.command.js";
@@ -147,7 +147,7 @@ export const COMMANDS = [
147
147
  needsConfig: true,
148
148
  needsTaskContext: false,
149
149
  }),
150
- entry(doctorSpec, () => import("../../commands/doctor.command.js").then((m) => m.runDoctor), {
150
+ entry(doctorSpec, () => import("../../commands/doctor.run.js").then((m) => m.runDoctor), {
151
151
  needsProject: true,
152
152
  needsConfig: false,
153
153
  needsTaskContext: false,
@@ -189,7 +189,7 @@ export const COMMANDS = [
189
189
  entry(recipesExplainSpec, () => import("../../commands/recipes/explain.command.js").then((m) => m.runRecipesExplain)),
190
190
  entry(recipesRemoveSpec, () => import("../../commands/recipes/remove.command.js").then((m) => m.runRecipesRemove)),
191
191
  entry(recipesCachePruneSpec, () => import("../../commands/recipes/cache-prune.command.js").then((m) => m.runRecipesCachePrune)),
192
- entry(recipesInstallSpec, () => import("../../commands/recipes/install.command.js").then((m) => m.runRecipesInstall)),
192
+ entry(recipesInstallSpec, () => import("../../commands/recipes/install.run.js").then((m) => m.runRecipesInstall)),
193
193
  entry(scenarioSpec, () => import("../../commands/scenario/scenario.command.js").then((m) => m.runScenario)),
194
194
  entry(scenarioListSpec, () => import("../../commands/scenario/list.command.js").then((m) => m.runScenarioList)),
195
195
  entry(scenarioInfoSpec, () => import("../../commands/scenario/info.command.js").then((m) => m.runScenarioInfo)),
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE9C,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAMxD,CAAC;AAiBF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAExF;AAED,KAAK,eAAe,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,eAAe,CAgBtD,CAAC;AA6BF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,eAAe,CAAC,CAStF;AAED,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE3C,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAMlD,CAAC;AAiBF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAElF;AAED,KAAK,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAgBlD,CAAC;AA0BF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAQlF"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE9C,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAMxD,CAAC;AAcF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAExF;AAED,KAAK,eAAe,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,eAAe,CAgBtD,CAAC;AA6BF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,eAAe,CAAC,CAStF;AAED,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE3C,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAMlD,CAAC;AAcF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAElF;AAED,KAAK,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAgBlD,CAAC;AA0BF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAQlF"}
@@ -1,8 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { saveConfig, setByDottedKey } from "@agentplaneorg/core";
3
- import { mapCoreError } from "../../error-map.js";
4
3
  import { usageError } from "../../spec/errors.js";
5
- import { CliError } from "../../../shared/errors.js";
4
+ import { wrapCommand } from "./wrap-command.js";
6
5
  export const configShowSpec = {
7
6
  id: ["config", "show"],
8
7
  group: "Config",
@@ -11,16 +10,11 @@ export const configShowSpec = {
11
10
  parse: () => ({}),
12
11
  };
13
12
  async function cmdConfigShow(opts) {
14
- try {
13
+ return wrapCommand({ command: "config show", rootOverride: opts.rootOverride }, async () => {
15
14
  const loaded = await opts.deps.getLoadedConfig("config show");
16
15
  process.stdout.write(`${JSON.stringify(loaded.raw, null, 2)}\n`);
17
16
  return 0;
18
- }
19
- catch (err) {
20
- if (err instanceof CliError)
21
- throw err;
22
- throw mapCoreError(err, { command: "config show", root: opts.rootOverride ?? null });
23
- }
17
+ });
24
18
  }
25
19
  export function makeRunConfigShowHandler(deps) {
26
20
  return (ctx) => cmdConfigShow({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, deps });
@@ -43,7 +37,11 @@ export const configSetSpec = {
43
37
  parse: (raw) => ({ key: String(raw.args.key ?? ""), value: String(raw.args.value ?? "") }),
44
38
  };
45
39
  async function cmdConfigSet(opts) {
46
- try {
40
+ return wrapCommand({
41
+ command: "config set",
42
+ rootOverride: opts.rootOverride,
43
+ context: { key: opts.key },
44
+ }, async () => {
47
45
  const resolved = await opts.deps.getResolvedProject("config set");
48
46
  const loaded = await opts.deps.getLoadedConfig("config set");
49
47
  const raw = { ...loaded.raw };
@@ -51,16 +49,7 @@ async function cmdConfigSet(opts) {
51
49
  await saveConfig(resolved.agentplaneDir, raw);
52
50
  process.stdout.write(`${path.relative(resolved.gitRoot, path.join(resolved.agentplaneDir, "config.json"))}\n`);
53
51
  return 0;
54
- }
55
- catch (err) {
56
- if (err instanceof CliError)
57
- throw err;
58
- throw mapCoreError(err, {
59
- command: "config set",
60
- key: opts.key,
61
- root: opts.rootOverride ?? null,
62
- });
63
- }
52
+ });
64
53
  }
65
54
  export function makeRunConfigSetHandler(deps) {
66
55
  return (ctx, p) => cmdConfigSet({
@@ -79,16 +68,11 @@ export const modeGetSpec = {
79
68
  parse: () => ({}),
80
69
  };
81
70
  async function cmdModeGet(opts) {
82
- try {
71
+ return wrapCommand({ command: "mode get", rootOverride: opts.rootOverride }, async () => {
83
72
  const loaded = await opts.deps.getLoadedConfig("mode get");
84
73
  process.stdout.write(`${loaded.config.workflow_mode}\n`);
85
74
  return 0;
86
- }
87
- catch (err) {
88
- if (err instanceof CliError)
89
- throw err;
90
- throw mapCoreError(err, { command: "mode get", root: opts.rootOverride ?? null });
91
- }
75
+ });
92
76
  }
93
77
  export function makeRunModeGetHandler(deps) {
94
78
  return (ctx) => cmdModeGet({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, deps });
@@ -111,7 +95,11 @@ export const modeSetSpec = {
111
95
  },
112
96
  };
113
97
  async function cmdModeSet(opts) {
114
- try {
98
+ return wrapCommand({
99
+ command: "mode set",
100
+ rootOverride: opts.rootOverride,
101
+ context: { mode: opts.mode },
102
+ }, async () => {
115
103
  const resolved = await opts.deps.getResolvedProject("mode set");
116
104
  const loaded = await opts.deps.getLoadedConfig("mode set");
117
105
  const raw = { ...loaded.raw };
@@ -119,16 +107,7 @@ async function cmdModeSet(opts) {
119
107
  await saveConfig(resolved.agentplaneDir, raw);
120
108
  process.stdout.write(`${opts.mode}\n`);
121
109
  return 0;
122
- }
123
- catch (err) {
124
- if (err instanceof CliError)
125
- throw err;
126
- throw mapCoreError(err, {
127
- command: "mode set",
128
- root: opts.rootOverride ?? null,
129
- mode: opts.mode,
130
- });
131
- }
110
+ });
132
111
  }
133
112
  export function makeRunModeSetHandler(deps) {
134
113
  return (ctx, p) => cmdModeSet({
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/core.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE9C,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAOxD,CAAC;AAYF,eAAO,MAAM,aAAa,EAAE,cAAc,CAAC,gBAAgB,CAG1D,CAAC;AAEF,KAAK,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,UAAU,CAO5C,CAAC;AAgLF,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,UAAU,CAE9C,CAAC;AAEF,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE1C,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAMhD,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,YAAY,CAAC,CA+DhF"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/core.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIrD,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE9C,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAOxD,CAAC;AASF,eAAO,MAAM,aAAa,EAAE,cAAc,CAAC,gBAAgB,CAE1D,CAAC;AAEF,KAAK,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,UAAU,CAO5C,CAAC;AAkMF,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,UAAU,CAE9C,CAAC;AAEF,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE1C,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAMhD,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,YAAY,CAAC,CA0FhF"}
@@ -1,13 +1,13 @@
1
1
  import { readdir, readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { resolveProject } from "@agentplaneorg/core";
4
- import { mapCoreError } from "../../error-map.js";
5
4
  import { fileExists } from "../../fs-utils.js";
6
5
  import { CliError } from "../../../shared/errors.js";
7
6
  import { dedupeStrings } from "../../../shared/strings.js";
8
7
  import { usageError } from "../../spec/errors.js";
9
8
  import { listRoles, renderQuickstart, renderRole } from "../../command-guide.js";
10
9
  import { toStringList } from "../../spec/parse-utils.js";
10
+ import { wrapCommand } from "./wrap-command.js";
11
11
  export const quickstartSpec = {
12
12
  id: ["quickstart"],
13
13
  group: "Core",
@@ -16,20 +16,14 @@ export const quickstartSpec = {
16
16
  examples: [{ cmd: "agentplane quickstart", why: "Show quickstart." }],
17
17
  parse: () => ({}),
18
18
  };
19
- function cmdQuickstart(opts) {
20
- try {
19
+ async function cmdQuickstart(opts) {
20
+ return wrapCommand({ command: "quickstart", rootOverride: opts.rootOverride }, () => {
21
21
  process.stdout.write(`${renderQuickstart()}\n`);
22
22
  return 0;
23
- }
24
- catch (err) {
25
- if (err instanceof CliError)
26
- throw err;
27
- throw mapCoreError(err, { command: "quickstart", root: opts.rootOverride ?? null });
28
- }
23
+ });
29
24
  }
30
25
  export const runQuickstart = (ctx) => {
31
- cmdQuickstart({ cwd: ctx.cwd, rootOverride: ctx.rootOverride });
32
- return Promise.resolve(0);
26
+ return cmdQuickstart({ cwd: ctx.cwd, rootOverride: ctx.rootOverride });
33
27
  };
34
28
  export const roleSpec = {
35
29
  id: ["role"],
@@ -39,6 +33,27 @@ export const roleSpec = {
39
33
  examples: [{ cmd: "agentplane role ORCHESTRATOR", why: "Show ORCHESTRATOR guide." }],
40
34
  parse: (raw) => ({ role: String(raw.args.role ?? "") }),
41
35
  };
36
+ function parseAgentProfileJson(filePath, text) {
37
+ let parsed;
38
+ try {
39
+ parsed = JSON.parse(text);
40
+ }
41
+ catch {
42
+ throw new CliError({
43
+ exitCode: 3,
44
+ code: "E_VALIDATION",
45
+ message: `Invalid agent profile JSON: ${filePath} (malformed JSON)`,
46
+ });
47
+ }
48
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
49
+ throw new CliError({
50
+ exitCode: 3,
51
+ code: "E_VALIDATION",
52
+ message: `Invalid agent profile JSON: ${filePath} (expected object)`,
53
+ });
54
+ }
55
+ return parsed;
56
+ }
42
57
  function normalizeRoleId(roleRaw) {
43
58
  return roleRaw.trim().toUpperCase();
44
59
  }
@@ -87,7 +102,7 @@ async function readAgentProfile(opts) {
87
102
  return null;
88
103
  const filename = `${foundId}.json`;
89
104
  const filePath = path.join(listing.agentplaneDir, "agents", filename);
90
- const raw = JSON.parse(await readFile(filePath, "utf8"));
105
+ const raw = parseAgentProfileJson(filePath, await readFile(filePath, "utf8"));
91
106
  return { agentplaneDir: listing.agentplaneDir, filename, profile: raw };
92
107
  }
93
108
  function renderAgentProfileBlock(opts) {
@@ -112,7 +127,7 @@ function renderAgentProfileBlock(opts) {
112
127
  return lines.join("\n").trimEnd();
113
128
  }
114
129
  async function cmdRole(opts) {
115
- try {
130
+ return wrapCommand({ command: "role", rootOverride: opts.rootOverride }, async () => {
116
131
  const roleRaw = opts.role.trim();
117
132
  if (!roleRaw) {
118
133
  throw usageError({
@@ -170,12 +185,7 @@ async function cmdRole(opts) {
170
185
  });
171
186
  process.stdout.write(`${block}\n`);
172
187
  return 0;
173
- }
174
- catch (err) {
175
- if (err instanceof CliError)
176
- throw err;
177
- throw mapCoreError(err, { command: "role", root: opts.rootOverride ?? null });
178
- }
188
+ });
179
189
  }
180
190
  export const runRole = (ctx, p) => {
181
191
  return cmdRole({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, role: p.role });
@@ -188,64 +198,83 @@ export const agentsSpec = {
188
198
  parse: () => ({}),
189
199
  };
190
200
  export function makeRunAgentsHandler(deps) {
191
- return async (ctx) => {
192
- try {
193
- const resolved = await deps.getResolvedProject("agents");
194
- const agentsDir = path.join(resolved.agentplaneDir, "agents");
195
- if (!(await fileExists(agentsDir))) {
196
- throw new CliError({
197
- exitCode: 2,
198
- code: "E_USAGE",
199
- message: `Agents directory not found: ${agentsDir} (run \`agentplane init\`)`,
200
- });
201
+ return async (ctx) => wrapCommand({ command: "agents", rootOverride: ctx.rootOverride }, async () => {
202
+ const resolved = await deps.getResolvedProject("agents");
203
+ const agentsDir = path.join(resolved.agentplaneDir, "agents");
204
+ if (!(await fileExists(agentsDir))) {
205
+ throw new CliError({
206
+ exitCode: 2,
207
+ code: "E_USAGE",
208
+ message: `Agents directory not found: ${agentsDir} (run \`agentplane init\`)`,
209
+ });
210
+ }
211
+ const entriesRaw = await readdir(agentsDir);
212
+ const entries = entriesRaw.filter((name) => name.endsWith(".json")).toSorted();
213
+ if (entries.length === 0) {
214
+ throw new CliError({
215
+ exitCode: 2,
216
+ code: "E_USAGE",
217
+ message: `No agent definitions found under ${agentsDir} (expected *.json)`,
218
+ });
219
+ }
220
+ const rows = [];
221
+ const seen = new Set();
222
+ const duplicates = [];
223
+ const mismatches = [];
224
+ for (const entry of entries) {
225
+ const canonicalId = entry.replace(/\.json$/i, "");
226
+ const filePath = path.join(agentsDir, entry);
227
+ const raw = parseAgentProfileJson(filePath, await readFile(filePath, "utf8"));
228
+ const rawId = typeof raw.id === "string" ? raw.id : "";
229
+ const rawRole = typeof raw.role === "string" ? raw.role : "";
230
+ const normalizedRawId = rawId.trim();
231
+ const role = rawRole.trim() || "-";
232
+ if (seen.has(canonicalId)) {
233
+ duplicates.push(canonicalId);
201
234
  }
202
- const entriesRaw = await readdir(agentsDir);
203
- const entries = entriesRaw.filter((name) => name.endsWith(".json")).toSorted();
204
- if (entries.length === 0) {
205
- throw new CliError({
206
- exitCode: 2,
207
- code: "E_USAGE",
208
- message: `No agent definitions found under ${agentsDir} (expected *.json)`,
209
- });
235
+ else {
236
+ seen.add(canonicalId);
210
237
  }
211
- const rows = [];
212
- const seen = new Set();
213
- const duplicates = [];
214
- for (const entry of entries) {
215
- const filePath = path.join(agentsDir, entry);
216
- const raw = JSON.parse(await readFile(filePath, "utf8"));
217
- const rawId = typeof raw.id === "string" ? raw.id : "";
218
- const rawRole = typeof raw.role === "string" ? raw.role : "";
219
- const agentId = rawId.trim() || "<missing-id>";
220
- const role = rawRole.trim() || "-";
221
- if (seen.has(agentId)) {
222
- duplicates.push(agentId);
223
- }
224
- else {
225
- seen.add(agentId);
226
- }
227
- rows.push([agentId, role, entry]);
238
+ if (normalizedRawId.length > 0 && normalizedRawId !== canonicalId) {
239
+ mismatches.push({ filename: entry, canonicalId, rawId: normalizedRawId });
240
+ }
241
+ rows.push({ canonicalId, role, filename: entry, rawId: normalizedRawId });
242
+ }
243
+ const showRawIdColumn = mismatches.length > 0;
244
+ const widthId = Math.max(...rows.map((row) => row.canonicalId.length), "ID".length);
245
+ const widthFile = Math.max(...rows.map((row) => row.filename.length), "FILE".length);
246
+ if (showRawIdColumn) {
247
+ const widthRawId = Math.max(...rows.map((row) => row.rawId.length), "RAW_ID".length);
248
+ process.stdout.write(`${"ID".padEnd(widthId)} ${"FILE".padEnd(widthFile)} ${"RAW_ID".padEnd(widthRawId)} ROLE\n`);
249
+ process.stdout.write(`${"-".repeat(widthId)} ${"-".repeat(widthFile)} ${"-".repeat(widthRawId)} ----\n`);
250
+ for (const row of rows) {
251
+ process.stdout.write(`${row.canonicalId.padEnd(widthId)} ${row.filename.padEnd(widthFile)} ${row.rawId.padEnd(widthRawId)} ${row.role}\n`);
228
252
  }
229
- const widthId = Math.max(...rows.map((row) => row[0].length), "ID".length);
230
- const widthFile = Math.max(...rows.map((row) => row[2].length), "FILE".length);
253
+ }
254
+ else {
231
255
  process.stdout.write(`${"ID".padEnd(widthId)} ${"FILE".padEnd(widthFile)} ROLE\n`);
232
256
  process.stdout.write(`${"-".repeat(widthId)} ${"-".repeat(widthFile)} ----\n`);
233
- for (const [agentId, role, filename] of rows) {
234
- process.stdout.write(`${agentId.padEnd(widthId)} ${filename.padEnd(widthFile)} ${role}\n`);
235
- }
236
- if (duplicates.length > 0) {
237
- throw new CliError({
238
- exitCode: 2,
239
- code: "E_USAGE",
240
- message: `Duplicate agent ids: ${dedupeStrings(duplicates).toSorted().join(", ")}`,
241
- });
257
+ for (const row of rows) {
258
+ process.stdout.write(`${row.canonicalId.padEnd(widthId)} ${row.filename.padEnd(widthFile)} ${row.role}\n`);
242
259
  }
243
- return 0;
244
260
  }
245
- catch (err) {
246
- if (err instanceof CliError)
247
- throw err;
248
- throw mapCoreError(err, { command: "agents", root: ctx.rootOverride ?? null });
261
+ if (duplicates.length > 0) {
262
+ throw new CliError({
263
+ exitCode: 2,
264
+ code: "E_USAGE",
265
+ message: `Duplicate canonical agent ids: ${dedupeStrings(duplicates).toSorted().join(", ")}`,
266
+ });
267
+ }
268
+ if (mismatches.length > 0) {
269
+ const details = mismatches
270
+ .map((m) => `${m.filename}: raw id "${m.rawId}" != canonical "${m.canonicalId}"`)
271
+ .join("; ");
272
+ throw new CliError({
273
+ exitCode: 2,
274
+ code: "E_USAGE",
275
+ message: `Agent profile id mismatch: ${details}`,
276
+ });
249
277
  }
250
- };
278
+ return 0;
279
+ });
251
280
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ide.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/ide.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,KAAK,aAAa,GAAG;IAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAA;CAAE,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAkBlD,CAAC;AAEF,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CA2ClB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAElF"}
1
+ {"version":3,"file":"ide.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/ide.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,KAAK,aAAa,GAAG;IAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAA;CAAE,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAkBlD,CAAC;AAEF,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CAwClB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAElF"}
@@ -1,8 +1,7 @@
1
1
  import { mkdir, readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { mapCoreError } from "../../error-map.js";
4
3
  import { writeTextIfChanged } from "../../../shared/write-if-changed.js";
5
- import { CliError } from "../../../shared/errors.js";
4
+ import { wrapCommand } from "./wrap-command.js";
6
5
  export const ideSyncSpec = {
7
6
  id: ["ide", "sync"],
8
7
  group: "IDE",
@@ -23,7 +22,7 @@ export const ideSyncSpec = {
23
22
  parse: (raw) => ({ ide: raw.opts.ide }),
24
23
  };
25
24
  export async function cmdIdeSync(opts) {
26
- try {
25
+ return wrapCommand({ command: "ide sync", rootOverride: opts.rootOverride }, async () => {
27
26
  const resolved = await opts.deps.getResolvedProject("ide sync");
28
27
  const agentsPath = path.join(resolved.gitRoot, "AGENTS.md");
29
28
  const agentsText = await readFile(agentsPath, "utf8");
@@ -56,12 +55,7 @@ export async function cmdIdeSync(opts) {
56
55
  process.stdout.write(`${path.relative(resolved.gitRoot, windsurfPath)}\n`);
57
56
  }
58
57
  return 0;
59
- }
60
- catch (err) {
61
- if (err instanceof CliError)
62
- throw err;
63
- throw mapCoreError(err, { command: "ide sync", root: opts.rootOverride ?? null });
64
- }
58
+ });
65
59
  }
66
60
  export function makeRunIdeSyncHandler(deps) {
67
61
  return (ctx, p) => cmdIdeSync({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, ide: p.ide, deps });
@@ -1,4 +1,5 @@
1
- export declare function ensureGitignoreAgents(opts: {
1
+ export declare function ensureInitGitignore(opts: {
2
2
  gitRoot: string;
3
+ includeAgentPromptFiles: boolean;
3
4
  }): Promise<void>;
4
5
  //# sourceMappingURL=write-gitignore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write-gitignore.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-gitignore.ts"],"names":[],"mappings":"AAeA,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBpF"}
1
+ {"version":3,"file":"write-gitignore.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-gitignore.ts"],"names":[],"mappings":"AAgCA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB"}
@@ -12,14 +12,27 @@ async function readTextIfExists(filePath) {
12
12
  throw err;
13
13
  }
14
14
  }
15
- export async function ensureGitignoreAgents(opts) {
15
+ const RUNTIME_IGNORE_LINES = [
16
+ "# agentplane: ignore runtime/transient workspace artifacts",
17
+ ".agentplane/worktrees",
18
+ ".agentplane/cache",
19
+ ".agentplane/recipes-cache",
20
+ ".agentplane/.upgrade",
21
+ ".agentplane/.release",
22
+ ".agentplane/upgrade",
23
+ ".agentplane/tasks.json",
24
+ ];
25
+ const AGENT_PROMPT_IGNORE_LINES = [
26
+ "# agentplane: ignore local agent prompts/templates",
27
+ "AGENTS.md",
28
+ ".agentplane/agents/",
29
+ ];
30
+ export async function ensureInitGitignore(opts) {
16
31
  const gitignorePath = path.join(opts.gitRoot, ".gitignore");
17
32
  const existing = (await readTextIfExists(gitignorePath)) ?? "";
18
- const ensuredLines = [
19
- "# agentplane: ignore local agent prompts/templates",
20
- "AGENTS.md",
21
- ".agentplane/agents/",
22
- ];
33
+ const ensuredLines = opts.includeAgentPromptFiles
34
+ ? [...RUNTIME_IGNORE_LINES, ...AGENT_PROMPT_IGNORE_LINES]
35
+ : [...RUNTIME_IGNORE_LINES];
23
36
  const existingLines = existing.split(/\r?\n/);
24
37
  const existingSet = new Set(existingLines.map((line) => line.trimEnd()));
25
38
  const missing = ensuredLines.filter((line) => !existingSet.has(line));
@@ -15,7 +15,7 @@ import { maybeSyncIde } from "./init/ide-sync.js";
15
15
  import { maybeInstallBundledRecipes } from "./init/recipes.js";
16
16
  import { ensureAgentplaneDirs, writeBackendStubs, writeInitConfig } from "./init/write-config.js";
17
17
  import { ensureAgentsFiles } from "./init/write-agents.js";
18
- import { ensureGitignoreAgents } from "./init/write-gitignore.js";
18
+ import { ensureInitGitignore } from "./init/write-gitignore.js";
19
19
  function parseBooleanValueForInit(flag, value) {
20
20
  const normalized = value.trim().toLowerCase();
21
21
  if (["1", "true", "yes", "y", "on"].includes(normalized))
@@ -312,8 +312,11 @@ async function cmdInit(opts) {
312
312
  configPathAbs: configPath,
313
313
  backendPathAbs: backendPath,
314
314
  });
315
+ await ensureInitGitignore({
316
+ gitRoot: resolved.gitRoot,
317
+ includeAgentPromptFiles: flags.gitignoreAgents === true,
318
+ });
315
319
  if (flags.gitignoreAgents) {
316
- await ensureGitignoreAgents({ gitRoot: resolved.gitRoot });
317
320
  await setPinnedBaseBranch({
318
321
  cwd: resolved.gitRoot,
319
322
  rootOverride: resolved.gitRoot,
@@ -0,0 +1,6 @@
1
+ export declare function wrapCommand<T>(opts: {
2
+ command: string;
3
+ rootOverride?: string;
4
+ context?: Record<string, unknown>;
5
+ }, fn: () => Promise<T> | T): Promise<T>;
6
+ //# sourceMappingURL=wrap-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-command.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/wrap-command.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,CAAC,CAAC,EACjC,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,EACD,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAYZ"}
@@ -0,0 +1,17 @@
1
+ import { mapCoreError } from "../../error-map.js";
2
+ import { CliError } from "../../../shared/errors.js";
3
+ export async function wrapCommand(opts, fn) {
4
+ try {
5
+ return await fn();
6
+ }
7
+ catch (err) {
8
+ if (err instanceof CliError)
9
+ throw err;
10
+ const context = opts.context ?? {};
11
+ throw mapCoreError(err, {
12
+ command: opts.command,
13
+ root: opts.rootOverride ?? null,
14
+ ...context,
15
+ });
16
+ }
17
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.ts"],"names":[],"mappings":"AAmWA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqK5D"}
1
+ {"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.ts"],"names":[],"mappings":"AAmWA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAuK5D"}
@@ -19,13 +19,13 @@ const GLOBAL_FLAGS = [
19
19
  { key: "version", forms: ["--version", "-v"], takesValue: false, scoped: false },
20
20
  { key: "noUpdateCheck", forms: ["--no-update-check"], takesValue: false, scoped: false },
21
21
  { key: "allowNetwork", forms: ["--allow-network"], takesValue: false, scoped: true },
22
- { key: "jsonErrors", forms: ["--json-errors", "--json"], takesValue: false, scoped: true },
22
+ { key: "jsonErrors", forms: ["--json-errors"], takesValue: false, scoped: true },
23
23
  { key: "root", forms: ["--root"], takesValue: true, scoped: false },
24
24
  ];
25
25
  const GLOBAL_FLAG_FORMS = new Map(GLOBAL_FLAGS.flatMap((def) => def.forms.map((form) => [form, def])));
26
26
  function prescanJsonErrors(argv) {
27
27
  // If parseGlobalArgs throws (e.g. missing --root value), we still want to honor
28
- // `--json` / `--json-errors` in the "scoped global" zone (before the command id).
28
+ // `--json-errors` in the "scoped global" zone (before the command id).
29
29
  let hasRest = false;
30
30
  for (let i = 0; i < argv.length; i++) {
31
31
  const arg = argv[i];
@@ -344,7 +344,9 @@ export async function runCli(argv) {
344
344
  if (resolved) {
345
345
  await loadDotEnv(resolved.gitRoot);
346
346
  }
347
- let projectPromise = null;
347
+ let projectPromise = resolved
348
+ ? Promise.resolve(resolved)
349
+ : null;
348
350
  const getResolvedProject = async (commandForErrorContext) => {
349
351
  projectPromise ??= resolveProject({ cwd, rootOverride: globals.root ?? null });
350
352
  try {
@@ -1,8 +1,3 @@
1
- import type { CommandHandler, CommandSpec } from "../cli/spec/spec.js";
2
- type DoctorParsed = {
3
- fix: boolean;
4
- };
5
- export declare const doctorSpec: CommandSpec<DoctorParsed>;
6
- export declare const runDoctor: CommandHandler<DoctorParsed>;
7
- export {};
1
+ export { doctorSpec, type DoctorParsed } from "./doctor.spec.js";
2
+ export { runDoctor } from "./doctor.run.js";
8
3
  //# sourceMappingURL=doctor.command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.command.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.command.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvE,KAAK,YAAY,GAAG;IAClB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAWhD,CAAC;AAkHF,eAAO,MAAM,SAAS,EAAE,cAAc,CAAC,YAAY,CAoBlD,CAAC"}
1
+ {"version":3,"file":"doctor.command.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}