agentplane 0.2.18 → 0.2.21

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 (103) hide show
  1. package/assets/AGENTS.md +4 -3
  2. package/bin/agentplane.js +24 -0
  3. package/dist/backends/task-backend/load.d.ts +2 -0
  4. package/dist/backends/task-backend/load.d.ts.map +1 -1
  5. package/dist/backends/task-backend/load.js +38 -18
  6. package/dist/cli/command-guide.d.ts.map +1 -1
  7. package/dist/cli/command-guide.js +12 -11
  8. package/dist/cli/run-cli/command-catalog.d.ts +1 -1
  9. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  10. package/dist/cli/run-cli/command-catalog.js +12 -1
  11. package/dist/cli/run-cli/commands/core.d.ts +9 -1
  12. package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
  13. package/dist/cli/run-cli/commands/core.js +268 -8
  14. package/dist/cli/run-cli/commands/init/write-config.d.ts.map +1 -1
  15. package/dist/cli/run-cli/commands/init/write-config.js +2 -0
  16. package/dist/cli/run-cli/commands/init/write-gitignore.d.ts.map +1 -1
  17. package/dist/cli/run-cli/commands/init/write-gitignore.js +3 -18
  18. package/dist/cli/run-cli/commands/init.d.ts +1 -0
  19. package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
  20. package/dist/cli/run-cli/commands/init.js +55 -30
  21. package/dist/cli/run-cli.d.ts.map +1 -1
  22. package/dist/cli/run-cli.js +85 -14
  23. package/dist/commands/commit.command.d.ts.map +1 -1
  24. package/dist/commands/commit.command.js +2 -0
  25. package/dist/commands/commit.spec.d.ts +2 -0
  26. package/dist/commands/commit.spec.d.ts.map +1 -1
  27. package/dist/commands/commit.spec.js +26 -0
  28. package/dist/commands/doctor.run.d.ts.map +1 -1
  29. package/dist/commands/doctor.run.js +15 -6
  30. package/dist/commands/finish.run.d.ts.map +1 -1
  31. package/dist/commands/finish.run.js +2 -0
  32. package/dist/commands/finish.spec.d.ts +2 -0
  33. package/dist/commands/finish.spec.d.ts.map +1 -1
  34. package/dist/commands/finish.spec.js +36 -0
  35. package/dist/commands/guard/impl/allow.d.ts.map +1 -1
  36. package/dist/commands/guard/impl/allow.js +33 -7
  37. package/dist/commands/guard/impl/commands.d.ts +2 -0
  38. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  39. package/dist/commands/guard/impl/commands.js +24 -4
  40. package/dist/commands/guard/impl/comment-commit.d.ts +1 -0
  41. package/dist/commands/guard/impl/comment-commit.d.ts.map +1 -1
  42. package/dist/commands/guard/impl/comment-commit.js +16 -24
  43. package/dist/commands/release/apply.command.d.ts.map +1 -1
  44. package/dist/commands/release/apply.command.js +79 -3
  45. package/dist/commands/release/plan.command.d.ts.map +1 -1
  46. package/dist/commands/release/plan.command.js +25 -1
  47. package/dist/commands/shared/task-backend.d.ts +3 -0
  48. package/dist/commands/shared/task-backend.d.ts.map +1 -1
  49. package/dist/commands/shared/task-backend.js +4 -1
  50. package/dist/commands/task/block.d.ts.map +1 -1
  51. package/dist/commands/task/block.js +12 -9
  52. package/dist/commands/task/close-duplicate.command.d.ts +14 -0
  53. package/dist/commands/task/close-duplicate.command.d.ts.map +1 -0
  54. package/dist/commands/task/close-duplicate.command.js +102 -0
  55. package/dist/commands/task/close-duplicate.d.ts +14 -0
  56. package/dist/commands/task/close-duplicate.d.ts.map +1 -0
  57. package/dist/commands/task/close-duplicate.js +90 -0
  58. package/dist/commands/task/close-noop.command.d.ts +14 -0
  59. package/dist/commands/task/close-noop.command.d.ts.map +1 -0
  60. package/dist/commands/task/close-noop.command.js +77 -0
  61. package/dist/commands/task/close-noop.d.ts +13 -0
  62. package/dist/commands/task/close-noop.d.ts.map +1 -0
  63. package/dist/commands/task/close-noop.js +77 -0
  64. package/dist/commands/task/finish.d.ts +2 -0
  65. package/dist/commands/task/finish.d.ts.map +1 -1
  66. package/dist/commands/task/finish.js +52 -10
  67. package/dist/commands/task/index.d.ts +3 -0
  68. package/dist/commands/task/index.d.ts.map +1 -1
  69. package/dist/commands/task/index.js +3 -0
  70. package/dist/commands/task/new.d.ts.map +1 -1
  71. package/dist/commands/task/new.js +34 -6
  72. package/dist/commands/task/new.spec.js +1 -1
  73. package/dist/commands/task/plan.d.ts.map +1 -1
  74. package/dist/commands/task/plan.js +2 -3
  75. package/dist/commands/task/set-status.d.ts.map +1 -1
  76. package/dist/commands/task/set-status.js +12 -9
  77. package/dist/commands/task/shared.d.ts +19 -0
  78. package/dist/commands/task/shared.d.ts.map +1 -1
  79. package/dist/commands/task/shared.js +137 -0
  80. package/dist/commands/task/start-ready.command.d.ts +14 -0
  81. package/dist/commands/task/start-ready.command.d.ts.map +1 -0
  82. package/dist/commands/task/start-ready.command.js +77 -0
  83. package/dist/commands/task/start-ready.d.ts +13 -0
  84. package/dist/commands/task/start-ready.d.ts.map +1 -0
  85. package/dist/commands/task/start-ready.js +46 -0
  86. package/dist/commands/task/start.d.ts.map +1 -1
  87. package/dist/commands/task/start.js +13 -11
  88. package/dist/commands/task/update.command.d.ts +1 -0
  89. package/dist/commands/task/update.command.d.ts.map +1 -1
  90. package/dist/commands/task/update.command.js +8 -0
  91. package/dist/commands/task/update.d.ts +1 -0
  92. package/dist/commands/task/update.d.ts.map +1 -1
  93. package/dist/commands/task/update.js +19 -3
  94. package/dist/shared/errors.d.ts +9 -1
  95. package/dist/shared/errors.d.ts.map +1 -1
  96. package/dist/shared/errors.js +3 -1
  97. package/dist/shared/runtime-artifacts.d.ts +3 -0
  98. package/dist/shared/runtime-artifacts.d.ts.map +1 -0
  99. package/dist/shared/runtime-artifacts.js +18 -0
  100. package/dist/usecases/context/resolve-context.d.ts +3 -0
  101. package/dist/usecases/context/resolve-context.d.ts.map +1 -1
  102. package/dist/usecases/context/resolve-context.js +6 -1
  103. package/package.json +5 -4
@@ -28,5 +28,7 @@ export declare function cmdCommit(opts: {
28
28
  allowCI: boolean;
29
29
  requireClean: boolean;
30
30
  quiet: boolean;
31
+ closeUnstageOthers: boolean;
32
+ closeCheckOnly: boolean;
31
33
  }): Promise<number>;
32
34
  //# sourceMappingURL=commands.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commands.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAMvF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAyDxE,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlB;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAS9E;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkIlB"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commands.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAOvF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAyDxE,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlB;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAS9E;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyJlB"}
@@ -3,6 +3,7 @@ import { successMessage } from "../../../cli/output.js";
3
3
  import { CliError } from "../../../shared/errors.js";
4
4
  import { loadCommandContext } from "../../shared/task-backend.js";
5
5
  import { loadTaskFromContext } from "../../shared/task-backend.js";
6
+ import { execFileAsync, gitEnv } from "../../shared/git.js";
6
7
  import { suggestAllowPrefixes } from "./allow.js";
7
8
  import { buildCloseCommitMessage, taskReadmePathForTask } from "./close-message.js";
8
9
  import { buildGitCommitEnv } from "./env.js";
@@ -126,13 +127,22 @@ export async function cmdCommit(opts) {
126
127
  if (opts.close) {
127
128
  const ctx = opts.ctx ??
128
129
  (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
129
- // Make the close commit deterministic: require empty index, then stage only the task README.
130
- const staged = await ctx.git.statusStagedPaths();
131
- if (staged.length > 0) {
130
+ // Make the close commit deterministic: start from a clean index unless --unstage-others is used.
131
+ let staged = await ctx.git.statusStagedPaths();
132
+ if (staged.length > 0 && opts.closeUnstageOthers) {
133
+ if (!opts.closeCheckOnly) {
134
+ await execFileAsync("git", ["restore", "--staged", "--", "."], {
135
+ cwd: ctx.resolvedProject.gitRoot,
136
+ env: gitEnv(),
137
+ });
138
+ }
139
+ staged = opts.closeCheckOnly ? staged : await ctx.git.statusStagedPaths();
140
+ }
141
+ if (staged.length > 0 && !opts.closeUnstageOthers) {
132
142
  throw new CliError({
133
143
  exitCode: 5,
134
144
  code: "E_GIT",
135
- message: "Staged files exist (close commit requires an empty index)",
145
+ message: "Staged files exist (close commit requires an empty index; rerun with --unstage-others to auto-unstage).",
136
146
  });
137
147
  }
138
148
  const task = await loadTaskFromContext({ ctx, taskId: opts.taskId });
@@ -145,6 +155,16 @@ export async function cmdCommit(opts) {
145
155
  const readmeRel = readmeAbs.startsWith(ctx.resolvedProject.gitRoot)
146
156
  ? readmeAbs.slice(ctx.resolvedProject.gitRoot.length + 1)
147
157
  : readmeAbs;
158
+ if (opts.closeCheckOnly) {
159
+ if (!opts.quiet) {
160
+ const stagedCount = staged.length;
161
+ const suffix = stagedCount > 0 && opts.closeUnstageOthers
162
+ ? `; would unstage ${stagedCount} path(s)`
163
+ : "";
164
+ process.stdout.write(`${successMessage("close preflight", opts.taskId, `subject=${msg.subject}${suffix}`)}\n`);
165
+ }
166
+ return 0;
167
+ }
148
168
  await ctx.git.stage([readmeRel]);
149
169
  // Close commits should not require manual --allow flags:
150
170
  // the command stages exactly one task README under workflow_dir.
@@ -5,6 +5,7 @@ export declare function commitFromComment(opts: {
5
5
  cwd: string;
6
6
  rootOverride?: string;
7
7
  taskId: string;
8
+ primaryTag: string;
8
9
  executorAgent?: string;
9
10
  author?: string;
10
11
  statusFrom?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"comment-commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/comment-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAS/E,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAsEvF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA+F/D"}
1
+ {"version":3,"file":"comment-commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/comment-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAS/E,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAiEvF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA+F/D"}
@@ -8,24 +8,6 @@ import { buildGitCommitEnv } from "./env.js";
8
8
  import { stageAllowlist, suggestAllowPrefixes } from "./allow.js";
9
9
  import { guardCommitCheck } from "./policy.js";
10
10
  function deriveCommitMessageFromComment(opts) {
11
- const raw = (opts.formattedComment ?? formatCommentBodyForCommit(opts.body, opts.config))
12
- .trim()
13
- .replaceAll(/\s+/g, " ");
14
- if (!raw) {
15
- throw new CliError({
16
- exitCode: 2,
17
- code: "E_USAGE",
18
- message: "Comment body is required to build a commit message from the task comment",
19
- });
20
- }
21
- const summary = raw.replace(/^(start|blocked|verified):\s*/i, "").trim();
22
- if (!summary) {
23
- throw new CliError({
24
- exitCode: 2,
25
- code: "E_USAGE",
26
- message: "Comment body is required to build a commit message from the task comment",
27
- });
28
- }
29
11
  const prefix = opts.emoji.trim();
30
12
  if (!prefix) {
31
13
  throw new CliError({
@@ -42,15 +24,25 @@ function deriveCommitMessageFromComment(opts) {
42
24
  message: invalidValueMessage("task id", opts.taskId, "valid task id"),
43
25
  });
44
26
  }
45
- return `${prefix} ${suffix} task: ${summary}`;
27
+ const primary = opts.primaryTag.trim().toLowerCase();
28
+ if (!primary) {
29
+ throw new CliError({
30
+ exitCode: 2,
31
+ code: "E_USAGE",
32
+ message: "Primary tag is required when deriving commit messages from task comments",
33
+ });
34
+ }
35
+ const status = (opts.statusTo?.trim().toLowerCase() ?? "status-transition").replaceAll(/\s+/g, "-");
36
+ return `${prefix} ${suffix} ${primary}: ${status}`;
46
37
  }
47
38
  function deriveCommitBodyFromComment(opts) {
48
39
  const lines = [
49
40
  `Task: ${opts.taskId}`,
41
+ `Primary: ${opts.primaryTag}`,
50
42
  ...(opts.executorAgent ? [`Agent: ${opts.executorAgent}`] : []),
51
43
  ...(opts.author ? [`Author: ${opts.author}`] : []),
52
- ...(opts.statusFrom && opts.statusTo ? [`Status: ${opts.statusFrom} -> ${opts.statusTo}`] : []),
53
- `Comment: ${normalizeCommentBodyForCommit(opts.formattedComment || opts.commentBody)}`,
44
+ ...(opts.statusTo ? [`Status: ${opts.statusTo}`] : []),
45
+ `Comment: ${normalizeCommentBodyForCommit(opts.formattedComment ?? opts.commentBody)}`,
54
46
  ];
55
47
  return lines.join("\n").trimEnd();
56
48
  }
@@ -88,14 +80,14 @@ export async function commitFromComment(opts) {
88
80
  });
89
81
  const message = deriveCommitMessageFromComment({
90
82
  taskId: opts.taskId,
91
- body: opts.commentBody,
83
+ primaryTag: opts.primaryTag,
84
+ statusTo: opts.statusTo,
92
85
  emoji: opts.emoji,
93
- formattedComment: opts.formattedComment,
94
- config: opts.config,
95
86
  });
96
87
  const formattedComment = opts.formattedComment ?? formatCommentBodyForCommit(opts.commentBody, opts.config);
97
88
  const body = deriveCommitBodyFromComment({
98
89
  taskId: opts.taskId,
90
+ primaryTag: opts.primaryTag,
99
91
  executorAgent: opts.executorAgent,
100
92
  author: opts.author,
101
93
  statusFrom: opts.statusFrom,
@@ -1 +1 @@
1
- {"version":3,"file":"apply.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.command.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAU1E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAyQnD,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAwE5D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,kBAAkB,CAyJ9D,CAAC"}
1
+ {"version":3,"file":"apply.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.command.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAU1E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAsVnD,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAwE5D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,kBAAkB,CAuK9D,CAAC"}
@@ -82,6 +82,20 @@ async function readPackageVersion(pkgJsonPath) {
82
82
  }
83
83
  return version;
84
84
  }
85
+ async function readCoreDependencyVersion(pkgJsonPath) {
86
+ const raw = JSON.parse(await readFile(pkgJsonPath, "utf8"));
87
+ const value = raw.dependencies?.["@agentplaneorg/core"];
88
+ const version = typeof value === "string" ? value.trim() : "";
89
+ if (!version) {
90
+ throw new CliError({
91
+ exitCode: exitCodeForError("E_VALIDATION"),
92
+ code: "E_VALIDATION",
93
+ message: `Missing dependency @agentplaneorg/core in ${pkgJsonPath}. ` +
94
+ "Release parity requires packages/agentplane to pin @agentplaneorg/core to the same version.",
95
+ });
96
+ }
97
+ return version;
98
+ }
85
99
  async function replacePackageVersionInFile(pkgJsonPath, nextVersion) {
86
100
  const text = await readFile(pkgJsonPath, "utf8");
87
101
  const replaced = text.replace(/"version"\s*:\s*"[^"]*"/u, `"version": "${nextVersion}"`);
@@ -94,6 +108,27 @@ async function replacePackageVersionInFile(pkgJsonPath, nextVersion) {
94
108
  }
95
109
  await writeFile(pkgJsonPath, replaced, "utf8");
96
110
  }
111
+ async function replaceAgentplanePackageMetadata(pkgJsonPath, nextVersion) {
112
+ const text = await readFile(pkgJsonPath, "utf8");
113
+ const withVersion = text.replace(/"version"\s*:\s*"[^"]*"/u, `"version": "${nextVersion}"`);
114
+ if (withVersion === text) {
115
+ throw new CliError({
116
+ exitCode: exitCodeForError("E_VALIDATION"),
117
+ code: "E_VALIDATION",
118
+ message: `Failed to update version in ${pkgJsonPath} (missing "version" field).`,
119
+ });
120
+ }
121
+ const withDependency = withVersion.replace(/("@agentplaneorg\/core"\s*:\s*")[^"]*(")/u, `$1${nextVersion}$2`);
122
+ if (withDependency === withVersion) {
123
+ throw new CliError({
124
+ exitCode: exitCodeForError("E_VALIDATION"),
125
+ code: "E_VALIDATION",
126
+ message: `Failed to update @agentplaneorg/core dependency in ${pkgJsonPath}. ` +
127
+ "Ensure packages/agentplane/package.json declares this dependency.",
128
+ });
129
+ }
130
+ await writeFile(pkgJsonPath, withDependency, "utf8");
131
+ }
97
132
  function cleanHookEnv() {
98
133
  const env = { ...gitEnv() };
99
134
  delete env.AGENTPLANE_TASK_ID;
@@ -212,6 +247,33 @@ async function ensureNpmVersionsAvailable(gitRoot, version) {
212
247
  });
213
248
  }
214
249
  }
250
+ async function runReleasePrepublishGate(gitRoot) {
251
+ try {
252
+ await execFileAsync("bun", ["run", "release:prepublish"], {
253
+ cwd: gitRoot,
254
+ env: {
255
+ ...process.env,
256
+ GIT_AUTHOR_NAME: process.env.GIT_AUTHOR_NAME ?? "agentplane-release",
257
+ GIT_AUTHOR_EMAIL: process.env.GIT_AUTHOR_EMAIL ?? "agentplane-release@example.com",
258
+ GIT_COMMITTER_NAME: process.env.GIT_COMMITTER_NAME ?? "agentplane-release",
259
+ GIT_COMMITTER_EMAIL: process.env.GIT_COMMITTER_EMAIL ?? "agentplane-release@example.com",
260
+ },
261
+ maxBuffer: 200 * 1024 * 1024,
262
+ });
263
+ }
264
+ catch (err) {
265
+ const details = String(err?.stderr ??
266
+ err?.stdout ??
267
+ err?.message ??
268
+ "").trim();
269
+ throw new CliError({
270
+ exitCode: exitCodeForError("E_VALIDATION"),
271
+ code: "E_VALIDATION",
272
+ message: "Release prepublish gate failed. `agentplane release apply --push` requires a successful local `bun run release:prepublish` run before pushing the release tag." +
273
+ (details ? `\n\n${details}` : ""),
274
+ });
275
+ }
276
+ }
215
277
  async function writeReleaseApplyReport(gitRoot, report) {
216
278
  const runId = new Date().toISOString().replaceAll(":", "-").replaceAll(".", "-");
217
279
  const dir = path.join(gitRoot, ".agentplane", ".release", "apply");
@@ -332,9 +394,10 @@ export const runReleaseApply = async (ctx, flags) => {
332
394
  await validateReleaseNotes(notesPath);
333
395
  const corePkgPath = path.join(gitRoot, "packages", "core", "package.json");
334
396
  const agentplanePkgPath = path.join(gitRoot, "packages", "agentplane", "package.json");
335
- const [coreVersion, agentplaneVersion] = await Promise.all([
397
+ const [coreVersion, agentplaneVersion, coreDependencyVersion] = await Promise.all([
336
398
  readPackageVersion(corePkgPath),
337
399
  readPackageVersion(agentplanePkgPath),
400
+ readCoreDependencyVersion(agentplanePkgPath),
338
401
  ]);
339
402
  if (coreVersion !== agentplaneVersion) {
340
403
  throw new CliError({
@@ -344,6 +407,15 @@ export const runReleaseApply = async (ctx, flags) => {
344
407
  `packages/core=${coreVersion} packages/agentplane=${agentplaneVersion}`,
345
408
  });
346
409
  }
410
+ if (coreDependencyVersion !== coreVersion) {
411
+ throw new CliError({
412
+ exitCode: exitCodeForError("E_VALIDATION"),
413
+ code: "E_VALIDATION",
414
+ message: "Release dependency parity check failed before apply. " +
415
+ `packages/agentplane dependency @agentplaneorg/core=${coreDependencyVersion} ` +
416
+ `must match packages/core version ${coreVersion}.`,
417
+ });
418
+ }
347
419
  const git = new GitContext({ gitRoot });
348
420
  await ensureCleanTrackedTree(gitRoot);
349
421
  await ensureTagDoesNotExist(gitRoot, plan.nextTag);
@@ -356,6 +428,7 @@ export const runReleaseApply = async (ctx, flags) => {
356
428
  reason: "release apply --push validates npm version availability and pushes over network",
357
429
  interactive: Boolean(process.stdin.isTTY),
358
430
  });
431
+ await runReleasePrepublishGate(gitRoot);
359
432
  await ensureNpmVersionsAvailable(gitRoot, plan.nextVersion);
360
433
  npmVersionChecked = true;
361
434
  }
@@ -363,10 +436,13 @@ export const runReleaseApply = async (ctx, flags) => {
363
436
  if (coreVersion === plan.prevVersion) {
364
437
  await Promise.all([
365
438
  replacePackageVersionInFile(corePkgPath, plan.nextVersion),
366
- replacePackageVersionInFile(agentplanePkgPath, plan.nextVersion),
439
+ replaceAgentplanePackageMetadata(agentplanePkgPath, plan.nextVersion),
367
440
  ]);
368
441
  }
369
- else if (coreVersion !== plan.nextVersion) {
442
+ else if (coreVersion === plan.nextVersion) {
443
+ await replaceAgentplanePackageMetadata(agentplanePkgPath, plan.nextVersion);
444
+ }
445
+ else {
370
446
  throw new CliError({
371
447
  exitCode: exitCodeForError("E_VALIDATION"),
372
448
  code: "E_VALIDATION",
@@ -1 +1 @@
1
- {"version":3,"file":"plan.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/plan.command.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAM1E,KAAK,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE5C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAmHjD,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,iBAAiB,CA4E1D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,iBAAiB,CAyD5D,CAAC"}
1
+ {"version":3,"file":"plan.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/plan.command.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAM1E,KAAK,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE5C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAqIjD,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,iBAAiB,CA4E1D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,iBAAiB,CAoE5D,CAAC"}
@@ -43,6 +43,20 @@ async function readPackageVersion(pkgJsonPath) {
43
43
  }
44
44
  return version;
45
45
  }
46
+ async function readCoreDependencyVersion(pkgJsonPath) {
47
+ const raw = JSON.parse(await readFile(pkgJsonPath, "utf8"));
48
+ const value = raw.dependencies?.["@agentplaneorg/core"];
49
+ const version = typeof value === "string" ? value.trim() : "";
50
+ if (!version) {
51
+ throw new CliError({
52
+ exitCode: exitCodeForError("E_VALIDATION"),
53
+ code: "E_VALIDATION",
54
+ message: `Missing dependency @agentplaneorg/core in ${pkgJsonPath}. ` +
55
+ "Release planning requires packages/agentplane to pin @agentplaneorg/core to the same version.",
56
+ });
57
+ }
58
+ return version;
59
+ }
46
60
  async function getLatestSemverTag(gitRoot) {
47
61
  try {
48
62
  const { stdout } = await execFileAsync("git", ["describe", "--tags", "--abbrev=0", "--match", "v[0-9]*.[0-9]*.[0-9]*"], { cwd: gitRoot, env: gitEnv() });
@@ -176,9 +190,10 @@ export const runReleasePlan = async (ctx, flags) => {
176
190
  const gitRoot = resolved.gitRoot;
177
191
  const corePkgPath = path.join(gitRoot, "packages", "core", "package.json");
178
192
  const agentplanePkgPath = path.join(gitRoot, "packages", "agentplane", "package.json");
179
- const [coreVersion, agentplaneVersion] = await Promise.all([
193
+ const [coreVersion, agentplaneVersion, coreDependencyVersion] = await Promise.all([
180
194
  readPackageVersion(corePkgPath),
181
195
  readPackageVersion(agentplanePkgPath),
196
+ readCoreDependencyVersion(agentplanePkgPath),
182
197
  ]);
183
198
  if (coreVersion !== agentplaneVersion) {
184
199
  throw new CliError({
@@ -188,6 +203,15 @@ export const runReleasePlan = async (ctx, flags) => {
188
203
  `packages/core=${coreVersion} packages/agentplane=${agentplaneVersion}`,
189
204
  });
190
205
  }
206
+ if (coreDependencyVersion !== coreVersion) {
207
+ throw new CliError({
208
+ exitCode: exitCodeForError("E_VALIDATION"),
209
+ code: "E_VALIDATION",
210
+ message: "Release dependency parity check failed before planning. " +
211
+ `packages/agentplane dependency @agentplaneorg/core=${coreDependencyVersion} ` +
212
+ `must match packages/core version ${coreVersion}.`,
213
+ });
214
+ }
191
215
  const prevTag = flags.since ?? (await getLatestSemverTag(gitRoot));
192
216
  const nextVersion = bumpVersion(coreVersion, flags.bump);
193
217
  const nextTag = `v${nextVersion}`;
@@ -1,3 +1,4 @@
1
+ import type { AgentplaneConfig, ResolvedProject } from "@agentplaneorg/core";
1
2
  import { loadTaskBackend, type TaskData } from "../../backends/task-backend.js";
2
3
  import { GitContext } from "./git-context.js";
3
4
  export type CommandMemo = {
@@ -22,6 +23,8 @@ export declare function taskDataToFrontmatter(task: TaskData): Record<string, un
22
23
  export declare function loadCommandContext(opts: {
23
24
  cwd: string;
24
25
  rootOverride?: string | null;
26
+ resolvedProject?: ResolvedProject;
27
+ config?: AgentplaneConfig;
25
28
  }): Promise<CommandContext>;
26
29
  export declare function loadTaskFromContext(opts: {
27
30
  ctx: CommandContext;
@@ -1 +1 @@
1
- {"version":3,"file":"task-backend.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/task-backend.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IACzE,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9D,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,UAAU,CAAC;IAEhB,IAAI,EAAE,WAAW,CAAC;IAGlB,QAAQ,EAAE,cAAc,CAAC,iBAAiB,CAAC,CAAC;IAC5C,OAAO,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC;CACxC,CAAC;AASF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ3E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA+B7E;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,OAAO,CAAC,cAAc,CAAC,CAgB1B;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAepB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,cAAc,CAAC,iBAAiB,CAAC,CAAC;IAC5C,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC,CAaD;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAG5E"}
1
+ {"version":3,"file":"task-backend.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/task-backend.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG7E,OAAO,EAAE,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IACzE,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9D,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,UAAU,CAAC;IAEhB,IAAI,EAAE,WAAW,CAAC;IAGlB,QAAQ,EAAE,cAAc,CAAC,iBAAiB,CAAC,CAAC;IAC5C,OAAO,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC;CACxC,CAAC;AASF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ3E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA+B7E;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B,GAAG,OAAO,CAAC,cAAc,CAAC,CAmB1B;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAepB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,cAAc,CAAC,iBAAiB,CAAC,CAAC;IAC5C,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC,CAaD;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAG5E"}
@@ -50,10 +50,13 @@ export function taskDataToFrontmatter(task) {
50
50
  };
51
51
  }
52
52
  export async function loadCommandContext(opts) {
53
- const { backend, backendId, backendConfigPath, resolved, config } = await loadTaskBackend({
53
+ const backendLoaded = await loadTaskBackend({
54
54
  cwd: opts.cwd,
55
55
  rootOverride: opts.rootOverride ?? null,
56
+ resolvedProject: opts.resolvedProject,
57
+ config: opts.config,
56
58
  });
59
+ const { backend, backendId, backendConfigPath, resolved, config } = backendLoaded;
57
60
  return {
58
61
  resolvedProject: resolved,
59
62
  config,
@@ -1 +1 @@
1
- {"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../src/commands/task/block.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAcnC,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgIlB"}
1
+ {"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../src/commands/task/block.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAgBnC,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmIlB"}
@@ -7,7 +7,7 @@ import { ensureActionApproved } from "../shared/approval-requirements.js";
7
7
  import { loadCommandContext, loadTaskFromContext, } from "../shared/task-backend.js";
8
8
  import { backendIsLocalFileBackend, getTaskStore } from "../shared/task-store.js";
9
9
  import { readDirectWorkLock } from "../../shared/direct-work-lock.js";
10
- import { appendTaskEvent, defaultCommitEmojiForAgentId, enforceStatusCommitPolicy, isTransitionAllowed, nowIso, requireStructuredComment, } from "./shared.js";
10
+ import { appendTaskEvent, defaultCommitEmojiForAgentId, enforceStatusCommitPolicy, isTransitionAllowed, nowIso, requireStructuredComment, resolvePrimaryTag, toStringArray, } from "./shared.js";
11
11
  export async function cmdBlock(opts) {
12
12
  try {
13
13
  const ctx = opts.ctx ??
@@ -20,14 +20,6 @@ export async function cmdBlock(opts) {
20
20
  reason: "block --force",
21
21
  });
22
22
  }
23
- if (opts.commitFromComment) {
24
- enforceStatusCommitPolicy({
25
- policy: ctx.config.status_commit_policy,
26
- action: "block",
27
- confirmed: opts.confirmStatusCommit,
28
- quiet: opts.quiet,
29
- });
30
- }
31
23
  const { prefix, min_chars: minChars } = ctx.config.tasks.comments.blocked;
32
24
  requireStructuredComment(opts.body, prefix, minChars);
33
25
  const useStore = backendIsLocalFileBackend(ctx);
@@ -43,6 +35,16 @@ export async function cmdBlock(opts) {
43
35
  message: `Refusing status transition ${currentStatus} -> BLOCKED (use --force to override)`,
44
36
  });
45
37
  }
38
+ if (opts.commitFromComment) {
39
+ enforceStatusCommitPolicy({
40
+ policy: ctx.config.status_commit_policy,
41
+ action: "block",
42
+ confirmed: opts.confirmStatusCommit,
43
+ quiet: opts.quiet,
44
+ statusFrom: currentStatus,
45
+ statusTo: "BLOCKED",
46
+ });
47
+ }
46
48
  const formattedComment = opts.commitFromComment
47
49
  ? formatCommentBodyForCommit(opts.body, ctx.config)
48
50
  : null;
@@ -94,6 +96,7 @@ export async function cmdBlock(opts) {
94
96
  cwd: opts.cwd,
95
97
  rootOverride: opts.rootOverride,
96
98
  taskId: opts.taskId,
99
+ primaryTag: resolvePrimaryTag(toStringArray(task.tags), ctx).primary,
97
100
  executorAgent,
98
101
  author: opts.author,
99
102
  statusFrom: currentStatus,
@@ -0,0 +1,14 @@
1
+ import type { CommandCtx, CommandSpec } from "../../cli/spec/spec.js";
2
+ import type { CommandContext } from "../shared/task-backend.js";
3
+ export type TaskCloseDuplicateParsed = {
4
+ taskId: string;
5
+ duplicateOf: string;
6
+ author: string;
7
+ note?: string;
8
+ force: boolean;
9
+ yes: boolean;
10
+ quiet: boolean;
11
+ };
12
+ export declare const taskCloseDuplicateSpec: CommandSpec<TaskCloseDuplicateParsed>;
13
+ export declare function makeRunTaskCloseDuplicateHandler(getCtx: (cmd: string) => Promise<CommandContext>): (ctx: CommandCtx, p: TaskCloseDuplicateParsed) => Promise<number>;
14
+ //# sourceMappingURL=close-duplicate.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"close-duplicate.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/close-duplicate.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,wBAAwB,CAmFxE,CAAC;AAEF,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACjF,KAAK,UAAU,EAAE,GAAG,wBAAwB,KAAG,OAAO,CAAC,MAAM,CAAC,CAc7E"}
@@ -0,0 +1,102 @@
1
+ import { usageError } from "../../cli/spec/errors.js";
2
+ import { cmdTaskCloseDuplicate } from "./close-duplicate.js";
3
+ export const taskCloseDuplicateSpec = {
4
+ id: ["task", "close-duplicate"],
5
+ group: "Task",
6
+ summary: "Close a task as a duplicate of another task with no-op bookkeeping metadata.",
7
+ args: [{ name: "task-id", required: true, valueHint: "<task-id>" }],
8
+ options: [
9
+ {
10
+ kind: "string",
11
+ name: "of",
12
+ valueHint: "<task-id>",
13
+ required: true,
14
+ description: "Canonical task id that this task duplicates.",
15
+ },
16
+ {
17
+ kind: "string",
18
+ name: "author",
19
+ valueHint: "<id>",
20
+ required: true,
21
+ description: "Comment author id (e.g. ORCHESTRATOR).",
22
+ },
23
+ {
24
+ kind: "string",
25
+ name: "note",
26
+ valueHint: "<text>",
27
+ description: "Optional short reason appended to the closure comment.",
28
+ },
29
+ { kind: "boolean", name: "force", default: false, description: "Force closure despite gates." },
30
+ {
31
+ kind: "boolean",
32
+ name: "yes",
33
+ default: false,
34
+ description: "Auto-approve force-action approval checks when required.",
35
+ },
36
+ { kind: "boolean", name: "quiet", default: false, description: "Suppress output." },
37
+ ],
38
+ examples: [
39
+ {
40
+ cmd: "agentplane task close-duplicate 202602120845-VKGC27 --of 202602120845-RWJ8K3 --author ORCHESTRATOR",
41
+ why: "Close accidental duplicate task in one command.",
42
+ },
43
+ ],
44
+ validateRaw: (raw) => {
45
+ const taskId = typeof raw.args["task-id"] === "string" ? raw.args["task-id"].trim() : "";
46
+ const of = typeof raw.opts.of === "string" ? raw.opts.of.trim() : "";
47
+ const author = typeof raw.opts.author === "string" ? raw.opts.author.trim() : "";
48
+ const note = raw.opts.note;
49
+ if (!taskId) {
50
+ throw usageError({
51
+ spec: taskCloseDuplicateSpec,
52
+ message: "Invalid value for task-id: empty.",
53
+ });
54
+ }
55
+ if (!of) {
56
+ throw usageError({ spec: taskCloseDuplicateSpec, message: "Invalid value for --of: empty." });
57
+ }
58
+ if (!author) {
59
+ throw usageError({
60
+ spec: taskCloseDuplicateSpec,
61
+ message: "Invalid value for --author: empty.",
62
+ });
63
+ }
64
+ if (typeof note === "string" && note.trim().length === 0) {
65
+ throw usageError({
66
+ spec: taskCloseDuplicateSpec,
67
+ message: "Invalid value for --note: empty.",
68
+ });
69
+ }
70
+ if (taskId === of) {
71
+ throw usageError({
72
+ spec: taskCloseDuplicateSpec,
73
+ message: "Duplicate target must differ from task-id.",
74
+ });
75
+ }
76
+ },
77
+ parse: (raw) => ({
78
+ taskId: String(raw.args["task-id"]),
79
+ duplicateOf: String(raw.opts.of),
80
+ author: String(raw.opts.author),
81
+ note: typeof raw.opts.note === "string" ? raw.opts.note : undefined,
82
+ force: raw.opts.force === true,
83
+ yes: raw.opts.yes === true,
84
+ quiet: raw.opts.quiet === true,
85
+ }),
86
+ };
87
+ export function makeRunTaskCloseDuplicateHandler(getCtx) {
88
+ return async (ctx, p) => {
89
+ return await cmdTaskCloseDuplicate({
90
+ ctx: await getCtx("task close-duplicate"),
91
+ cwd: ctx.cwd,
92
+ rootOverride: ctx.rootOverride,
93
+ taskId: p.taskId,
94
+ duplicateOf: p.duplicateOf,
95
+ author: p.author,
96
+ note: p.note,
97
+ force: p.force,
98
+ yes: p.yes,
99
+ quiet: p.quiet,
100
+ });
101
+ };
102
+ }
@@ -0,0 +1,14 @@
1
+ import { type CommandContext } from "../shared/task-backend.js";
2
+ export declare function cmdTaskCloseDuplicate(opts: {
3
+ ctx: CommandContext;
4
+ cwd: string;
5
+ rootOverride?: string;
6
+ taskId: string;
7
+ duplicateOf: string;
8
+ author: string;
9
+ note?: string;
10
+ force: boolean;
11
+ yes: boolean;
12
+ quiet: boolean;
13
+ }): Promise<number>;
14
+ //# sourceMappingURL=close-duplicate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"close-duplicate.d.ts","sourceRoot":"","sources":["../../../src/commands/task/close-duplicate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIrF,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuFlB"}