agentplane 0.2.21 → 0.2.22

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 (47) hide show
  1. package/assets/AGENTS.md +2 -1
  2. package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
  3. package/dist/backends/task-backend/local-backend.js +27 -7
  4. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  5. package/dist/cli/run-cli/command-catalog.js +60 -12
  6. package/dist/cli/run-cli/commands/core.d.ts +2 -0
  7. package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
  8. package/dist/cli/run-cli/commands/core.js +32 -5
  9. package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -1
  10. package/dist/cli/run-cli/commands/init/write-agents.js +33 -1
  11. package/dist/cli/run-cli/commands/init/write-config.d.ts.map +1 -1
  12. package/dist/cli/run-cli/commands/init/write-config.js +3 -1
  13. package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
  14. package/dist/cli/run-cli/commands/init.js +47 -7
  15. package/dist/cli/run-cli.d.ts.map +1 -1
  16. package/dist/cli/run-cli.js +1 -3
  17. package/dist/cli/spec/docs-render.d.ts.map +1 -1
  18. package/dist/cli/spec/docs-render.js +13 -6
  19. package/dist/commands/backend/sync.command.d.ts +3 -2
  20. package/dist/commands/backend/sync.command.d.ts.map +1 -1
  21. package/dist/commands/backend/sync.command.js +13 -15
  22. package/dist/commands/pr/pr.command.d.ts +1 -1
  23. package/dist/commands/pr/pr.command.d.ts.map +1 -1
  24. package/dist/commands/pr/pr.command.js +15 -15
  25. package/dist/commands/task/block.d.ts.map +1 -1
  26. package/dist/commands/task/block.js +15 -18
  27. package/dist/commands/task/finish.d.ts.map +1 -1
  28. package/dist/commands/task/finish.js +14 -7
  29. package/dist/commands/task/plan.d.ts.map +1 -1
  30. package/dist/commands/task/plan.js +14 -2
  31. package/dist/commands/task/ready.d.ts.map +1 -1
  32. package/dist/commands/task/ready.js +6 -8
  33. package/dist/commands/task/set-status.d.ts.map +1 -1
  34. package/dist/commands/task/set-status.js +18 -23
  35. package/dist/commands/task/shared.d.ts +16 -1
  36. package/dist/commands/task/shared.d.ts.map +1 -1
  37. package/dist/commands/task/shared.js +54 -3
  38. package/dist/commands/task/start-ready.d.ts.map +1 -1
  39. package/dist/commands/task/start-ready.js +6 -15
  40. package/dist/commands/task/start.d.ts.map +1 -1
  41. package/dist/commands/task/start.js +18 -23
  42. package/dist/commands/upgrade.d.ts.map +1 -1
  43. package/dist/commands/upgrade.js +67 -19
  44. package/package.json +2 -2
  45. package/dist/cli/parse/lifecycle.d.ts +0 -64
  46. package/dist/cli/parse/lifecycle.d.ts.map +0 -1
  47. package/dist/cli/parse/lifecycle.js +0 -285
@@ -50,21 +50,19 @@ export const backendSyncSpec = {
50
50
  quiet: raw.opts.quiet === true,
51
51
  }),
52
52
  };
53
- export function makeRunBackendHandler(getCtx) {
54
- const handler = async (_ctx, p) => {
55
- // Resolve context once for consistent error mapping and approval gating.
56
- await getCtx("backend");
57
- const input = p.cmd.join(" ");
58
- const suggestion = suggestOne(input, ["sync"]);
59
- const suffix = suggestion ? ` Did you mean: ${suggestion}?` : "";
60
- const msg = p.cmd.length === 0 ? "Missing subcommand." : `Unknown subcommand: ${p.cmd[0]}.`;
61
- throw usageError({
62
- spec: backendSyncSpec,
63
- message: `${msg}${suffix}`,
64
- context: { command: "backend sync" },
65
- });
66
- };
67
- return handler;
53
+ function runBackendRootGroup(_ctx, p) {
54
+ const input = p.cmd.join(" ");
55
+ const suggestion = suggestOne(input, ["sync"]);
56
+ const suffix = suggestion ? ` Did you mean: ${suggestion}?` : "";
57
+ const msg = p.cmd.length === 0 ? "Missing subcommand." : `Unknown subcommand: ${p.cmd[0]}.`;
58
+ throw usageError({
59
+ spec: backendSyncSpec,
60
+ message: `${msg}${suffix}`,
61
+ context: { command: "backend sync" },
62
+ });
63
+ }
64
+ export function makeRunBackendHandler(_getCtx) {
65
+ return runBackendRootGroup;
68
66
  }
69
67
  export function makeRunBackendSyncHandler(getCtx) {
70
68
  return async (ctx, p) => {
@@ -24,7 +24,7 @@ export type PrNoteParsed = {
24
24
  body: string;
25
25
  };
26
26
  export declare const prNoteSpec: CommandSpec<PrNoteParsed>;
27
- export declare function makeRunPrHandler(getCtx: (cmd: string) => Promise<CommandContext>): CommandHandler<PrGroupParsed>;
27
+ export declare function makeRunPrHandler(_getCtx: (cmd: string) => Promise<CommandContext>): CommandHandler<PrGroupParsed>;
28
28
  export declare function makeRunPrOpenHandler(getCtx: (cmd: string) => Promise<CommandContext>): (ctx: CommandCtx, p: PrOpenParsed) => Promise<number>;
29
29
  export declare function makeRunPrUpdateHandler(getCtx: (cmd: string) => Promise<CommandContext>): (ctx: CommandCtx, p: PrUpdateParsed) => Promise<number>;
30
30
  export declare function makeRunPrCheckHandler(getCtx: (cmd: string) => Promise<CommandContext>): (ctx: CommandCtx, p: PrCheckParsed) => Promise<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"pr.command.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/pr.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,KAAK,aAAa,GAAG;IAAE,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvC,eAAO,MAAM,MAAM,EAAE,WAAW,CAAC,aAAa,CAgB7C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAErF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAgChD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhD,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,cAAc,CAOpD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAOlD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CA0ChD,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,GAC/C,cAAc,CAAC,aAAa,CAAC,CAe/B;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACrE,KAAK,UAAU,EAAE,GAAG,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,CAUjE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACvE,KAAK,UAAU,EAAE,GAAG,cAAc,KAAG,OAAO,CAAC,MAAM,CAAC,CAQnE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACtE,KAAK,UAAU,EAAE,GAAG,aAAa,KAAG,OAAO,CAAC,MAAM,CAAC,CAQlE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACrE,KAAK,UAAU,EAAE,GAAG,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,CAUjE"}
1
+ {"version":3,"file":"pr.command.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/pr.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,KAAK,aAAa,GAAG;IAAE,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvC,eAAO,MAAM,MAAM,EAAE,WAAW,CAAC,aAAa,CAgB7C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAErF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAgChD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhD,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,cAAc,CAOpD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAOlD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CA0ChD,CAAC;AAgBF,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,GAChD,cAAc,CAAC,aAAa,CAAC,CAE/B;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACrE,KAAK,UAAU,EAAE,GAAG,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,CAUjE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACvE,KAAK,UAAU,EAAE,GAAG,cAAc,KAAG,OAAO,CAAC,MAAM,CAAC,CAQnE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACtE,KAAK,UAAU,EAAE,GAAG,aAAa,KAAG,OAAO,CAAC,MAAM,CAAC,CAQlE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACrE,KAAK,UAAU,EAAE,GAAG,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,CAUjE"}
@@ -110,21 +110,21 @@ export const prNoteSpec = {
110
110
  body: String(raw.opts.body),
111
111
  }),
112
112
  };
113
- export function makeRunPrHandler(getCtx) {
114
- return async (_ctx, p) => {
115
- await getCtx("pr");
116
- const input = p.cmd.join(" ");
117
- const candidates = ["open", "update", "check", "note"];
118
- const suggestion = suggestOne(input, candidates);
119
- const suffix = suggestion ? ` Did you mean: ${suggestion}?` : "";
120
- const msg = p.cmd.length === 0 ? "Missing subcommand." : `Unknown subcommand: ${p.cmd[0]}.`;
121
- throw usageError({
122
- spec: prSpec,
123
- command: "pr",
124
- message: `${msg}${suffix}`,
125
- context: { command: "pr" },
126
- });
127
- };
113
+ function runPrRootGroup(_ctx, p) {
114
+ const input = p.cmd.join(" ");
115
+ const candidates = ["open", "update", "check", "note"];
116
+ const suggestion = suggestOne(input, candidates);
117
+ const suffix = suggestion ? ` Did you mean: ${suggestion}?` : "";
118
+ const msg = p.cmd.length === 0 ? "Missing subcommand." : `Unknown subcommand: ${p.cmd[0]}.`;
119
+ throw usageError({
120
+ spec: prSpec,
121
+ command: "pr",
122
+ message: `${msg}${suffix}`,
123
+ context: { command: "pr" },
124
+ });
125
+ }
126
+ export function makeRunPrHandler(_getCtx) {
127
+ return runPrRootGroup;
128
128
  }
129
129
  export function makeRunPrOpenHandler(getCtx) {
130
130
  return async (ctx, p) => {
@@ -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;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"}
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,CA+HlB"}
@@ -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, resolvePrimaryTag, toStringArray, } from "./shared.js";
10
+ import { appendTaskEvent, defaultCommitEmojiForAgentId, ensureCommentCommitAllowed, ensureStatusTransitionAllowed, nowIso, requireStructuredComment, resolvePrimaryTag, toStringArray, } from "./shared.js";
11
11
  export async function cmdBlock(opts) {
12
12
  try {
13
13
  const ctx = opts.ctx ??
@@ -28,23 +28,20 @@ export async function cmdBlock(opts) {
28
28
  ? await store.get(opts.taskId)
29
29
  : await loadTaskFromContext({ ctx, taskId: opts.taskId });
30
30
  const currentStatus = String(task.status || "TODO").toUpperCase();
31
- if (!opts.force && !isTransitionAllowed(currentStatus, "BLOCKED")) {
32
- throw new CliError({
33
- exitCode: 2,
34
- code: "E_USAGE",
35
- message: `Refusing status transition ${currentStatus} -> BLOCKED (use --force to override)`,
36
- });
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
- }
31
+ ensureStatusTransitionAllowed({
32
+ currentStatus,
33
+ nextStatus: "BLOCKED",
34
+ force: opts.force,
35
+ });
36
+ ensureCommentCommitAllowed({
37
+ enabled: opts.commitFromComment,
38
+ config: ctx.config,
39
+ action: "block",
40
+ confirmed: opts.confirmStatusCommit,
41
+ quiet: opts.quiet,
42
+ statusFrom: currentStatus,
43
+ statusTo: "BLOCKED",
44
+ });
48
45
  const formattedComment = opts.commitFromComment
49
46
  ? formatCommentBodyForCommit(opts.body, ctx.config)
50
47
  : null;
@@ -1 +1 @@
1
- {"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../../../src/commands/task/finish.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAmCnC,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,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,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6TlB"}
1
+ {"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../../../src/commands/task/finish.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAmCnC,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,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,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqUlB"}
@@ -40,7 +40,14 @@ export async function cmdFinish(opts) {
40
40
  }
41
41
  const { prefix, min_chars: minChars } = ctx.config.tasks.comments.verified;
42
42
  requireStructuredComment(opts.body, prefix, minChars);
43
- if ((opts.commitFromComment || opts.statusCommit) && opts.taskIds.length !== 1) {
43
+ const autoStatusCommit = (ctx.config.finish_auto_status_commit === true ||
44
+ ctx.config.commit_automation === "finish_only") &&
45
+ !opts.commitFromComment &&
46
+ !opts.statusCommit &&
47
+ opts.closeCommit !== true &&
48
+ opts.taskIds.length === 1;
49
+ const statusCommitRequested = opts.statusCommit || autoStatusCommit;
50
+ if ((opts.commitFromComment || statusCommitRequested) && opts.taskIds.length !== 1) {
44
51
  throw new CliError({
45
52
  exitCode: 2,
46
53
  code: "E_USAGE",
@@ -62,7 +69,7 @@ export async function cmdFinish(opts) {
62
69
  });
63
70
  }
64
71
  const primaryTaskId = opts.taskIds[0] ?? "";
65
- if ((opts.commitFromComment || opts.statusCommit) && !primaryTaskId) {
72
+ if ((opts.commitFromComment || statusCommitRequested) && !primaryTaskId) {
66
73
  throw new CliError({
67
74
  exitCode: 2,
68
75
  code: "E_USAGE",
@@ -102,7 +109,7 @@ export async function cmdFinish(opts) {
102
109
  }
103
110
  }
104
111
  if (taskId === primaryTaskId &&
105
- (opts.commitFromComment || opts.statusCommit) &&
112
+ (opts.commitFromComment || statusCommitRequested) &&
106
113
  primaryStatusFrom === null) {
107
114
  primaryStatusFrom = String(task.status || "TODO").toUpperCase();
108
115
  primaryTag = resolvePrimaryTag(toStringArray(task.tags), ctx).primary;
@@ -157,11 +164,11 @@ export async function cmdFinish(opts) {
157
164
  ? store.update(taskId, () => nextTask)
158
165
  : ctx.taskBackend.writeTask(nextTask));
159
166
  }
160
- if (opts.commitFromComment || opts.statusCommit) {
167
+ if (opts.commitFromComment || statusCommitRequested) {
161
168
  enforceStatusCommitPolicy({
162
169
  policy: ctx.config.status_commit_policy,
163
170
  action: "finish",
164
- confirmed: opts.confirmStatusCommit,
171
+ confirmed: opts.confirmStatusCommit || autoStatusCommit,
165
172
  quiet: opts.quiet,
166
173
  statusFrom: primaryStatusFrom ?? "UNKNOWN",
167
174
  statusTo: "DONE",
@@ -169,7 +176,7 @@ export async function cmdFinish(opts) {
169
176
  }
170
177
  // tasks.json is export-only; generated via `agentplane task export`.
171
178
  let executorAgent = null;
172
- if (opts.commitFromComment || opts.statusCommit) {
179
+ if (opts.commitFromComment || statusCommitRequested) {
173
180
  const mode = ctx.config.workflow_mode;
174
181
  executorAgent = opts.author;
175
182
  if (mode === "direct") {
@@ -240,7 +247,7 @@ export async function cmdFinish(opts) {
240
247
  await ctx.git.commitAmendNoEdit({ env });
241
248
  }
242
249
  }
243
- if (opts.statusCommit) {
250
+ if (statusCommitRequested) {
244
251
  if (typeof opts.statusCommitEmoji === "string" && opts.statusCommitEmoji.trim() !== "✅") {
245
252
  throw new CliError({
246
253
  exitCode: 2,
@@ -1 +1 @@
1
- {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/commands/task/plan.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AA+CnC,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmElB;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CAgFlB;AAED,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,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDlB"}
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/commands/task/plan.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAmDnC,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6ElB;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CAgFlB;AAED,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,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDlB"}
@@ -25,6 +25,9 @@ async function loadPlanTask(opts) {
25
25
  }
26
26
  return { ctx, backend: backend, task, useStore, store };
27
27
  }
28
+ function normalizeForComparison(text) {
29
+ return text.replaceAll("\r\n", "\n").trim();
30
+ }
28
31
  export async function cmdTaskPlanSet(opts) {
29
32
  try {
30
33
  const { ctx, backend, task, useStore, store } = await loadPlanTask({
@@ -69,15 +72,24 @@ export async function cmdTaskPlanSet(opts) {
69
72
  ? String(task.doc ?? "")
70
73
  : (typeof task.doc === "string" ? task.doc : "") || (await backend.getTaskDoc(task.id));
71
74
  const baseDoc = ensureDocSections(existingDoc ?? "", config.tasks.doc.required_sections);
75
+ const currentPlan = extractDocSection(baseDoc, "Plan") ?? "";
76
+ const planChanged = normalizeForComparison(currentPlan) !== normalizeForComparison(text);
72
77
  const nextDoc = ensureDocSections(setMarkdownSection(baseDoc, "Plan", text), config.tasks.doc.required_sections);
78
+ const docChanged = nextDoc !== baseDoc;
79
+ const readmePath = path.join(resolved.gitRoot, config.paths.workflow_dir, task.id, "README.md");
80
+ if (!planChanged && !docChanged && !updatedBy) {
81
+ process.stdout.write(`${readmePath}\n`);
82
+ return 0;
83
+ }
73
84
  const nextTask = {
74
85
  ...task,
75
86
  doc: nextDoc,
76
- plan_approval: { state: "pending", updated_at: null, updated_by: null, note: null },
87
+ ...(planChanged
88
+ ? { plan_approval: { state: "pending", updated_at: null, updated_by: null, note: null } }
89
+ : {}),
77
90
  ...(updatedBy ? { doc_updated_by: updatedBy } : {}),
78
91
  };
79
92
  await (useStore ? store.update(opts.taskId, () => nextTask) : backend.writeTask(nextTask));
80
- const readmePath = path.join(resolved.gitRoot, config.paths.workflow_dir, task.id, "README.md");
81
93
  process.stdout.write(`${readmePath}\n`);
82
94
  return 0;
83
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ready.d.ts","sourceRoot":"","sources":["../../../src/commands/task/ready.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIpF,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;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDlB"}
1
+ {"version":3,"file":"ready.d.ts","sourceRoot":"","sources":["../../../src/commands/task/ready.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIpF,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;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsDlB"}
@@ -1,19 +1,18 @@
1
1
  import { mapBackendError } from "../../cli/error-map.js";
2
2
  import { successMessage, unknownEntityMessage, warnMessage } from "../../cli/output.js";
3
3
  import { loadCommandContext } from "../shared/task-backend.js";
4
- import { buildDependencyState } from "./shared.js";
4
+ import { resolveTaskDependencyState } from "./shared.js";
5
5
  export async function cmdReady(opts) {
6
6
  try {
7
7
  const ctx = opts.ctx ??
8
8
  (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
9
- const tasks = await ctx.taskBackend.listTasks();
10
- const depState = buildDependencyState(tasks);
11
- const task = tasks.find((item) => item.id === opts.taskId);
9
+ const task = await ctx.taskBackend.getTask(opts.taskId);
12
10
  const warnings = [];
11
+ let dep = null;
13
12
  if (task) {
14
- const dep = depState.get(task.id);
15
- const missing = dep?.missing ?? [];
16
- const incomplete = dep?.incomplete ?? [];
13
+ dep = await resolveTaskDependencyState(task, ctx.taskBackend);
14
+ const missing = dep.missing;
15
+ const incomplete = dep.incomplete;
17
16
  if (missing.length > 0) {
18
17
  warnings.push(`${task.id}: missing deps: ${missing.join(", ")}`);
19
18
  }
@@ -31,7 +30,6 @@ export async function cmdReady(opts) {
31
30
  const status = String(task.status || "TODO").toUpperCase();
32
31
  const title = task.title?.trim() || "(untitled task)";
33
32
  const owner = task.owner?.trim() || "-";
34
- const dep = depState.get(task.id);
35
33
  const dependsOn = dep?.dependsOn ?? [];
36
34
  process.stdout.write(`Task: ${task.id} [${status}] ${title}\n`);
37
35
  process.stdout.write(`Owner: ${owner}\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"set-status.d.ts","sourceRoot":"","sources":["../../../src/commands/task/set-status.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAgBnC,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,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,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,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;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6JlB"}
1
+ {"version":3,"file":"set-status.d.ts","sourceRoot":"","sources":["../../../src/commands/task/set-status.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAgBnC,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,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,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,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;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwJlB"}
@@ -4,9 +4,9 @@ import { formatCommentBodyForCommit } from "../../shared/comment-format.js";
4
4
  import { CliError } from "../../shared/errors.js";
5
5
  import { commitFromComment } from "../guard/index.js";
6
6
  import { ensureActionApproved } from "../shared/approval-requirements.js";
7
- import { listTasksMemo, loadCommandContext, loadTaskFromContext, resolveDocUpdatedBy, } from "../shared/task-backend.js";
7
+ import { loadCommandContext, loadTaskFromContext, resolveDocUpdatedBy, } from "../shared/task-backend.js";
8
8
  import { backendIsLocalFileBackend, getTaskStore } from "../shared/task-store.js";
9
- import { appendTaskEvent, buildDependencyState, defaultCommitEmojiForStatus, enforceStatusCommitPolicy, isTransitionAllowed, normalizeTaskStatus, nowIso, readCommitInfo, resolvePrimaryTag, toStringArray, } from "./shared.js";
9
+ import { appendTaskEvent, defaultCommitEmojiForStatus, ensureCommentCommitAllowed, ensureStatusTransitionAllowed, normalizeTaskStatus, nowIso, readCommitInfo, resolveTaskDependencyState, resolvePrimaryTag, toStringArray, } from "./shared.js";
10
10
  export async function cmdTaskSetStatus(opts) {
11
11
  const nextStatus = normalizeTaskStatus(opts.status);
12
12
  if (nextStatus === "DONE" && !opts.force) {
@@ -42,18 +42,14 @@ export async function cmdTaskSetStatus(opts) {
42
42
  ? await store.get(opts.taskId)
43
43
  : await loadTaskFromContext({ ctx, taskId: opts.taskId });
44
44
  const currentStatus = String(task.status || "TODO").toUpperCase();
45
- if (!opts.force && !isTransitionAllowed(currentStatus, nextStatus)) {
46
- throw new CliError({
47
- exitCode: 2,
48
- code: "E_USAGE",
49
- message: `Refusing status transition ${currentStatus} -> ${nextStatus} (use --force to override)`,
50
- });
51
- }
45
+ ensureStatusTransitionAllowed({
46
+ currentStatus,
47
+ nextStatus,
48
+ force: opts.force,
49
+ });
52
50
  if (!opts.force && (nextStatus === "DOING" || nextStatus === "DONE")) {
53
- const allTasks = await listTasksMemo(ctx);
54
- const depState = buildDependencyState(allTasks);
55
- const dep = depState.get(task.id);
56
- if (dep && (dep.missing.length > 0 || dep.incomplete.length > 0)) {
51
+ const dep = await resolveTaskDependencyState(task, ctx.taskBackend);
52
+ if (dep.missing.length > 0 || dep.incomplete.length > 0) {
57
53
  if (!opts.quiet) {
58
54
  if (dep.missing.length > 0) {
59
55
  process.stderr.write(`${warnMessage(`missing deps: ${dep.missing.join(", ")}`)}\n`);
@@ -69,16 +65,15 @@ export async function cmdTaskSetStatus(opts) {
69
65
  });
70
66
  }
71
67
  }
72
- if (opts.commitFromComment) {
73
- enforceStatusCommitPolicy({
74
- policy: config.status_commit_policy,
75
- action: "task set-status",
76
- confirmed: opts.confirmStatusCommit,
77
- quiet: opts.quiet,
78
- statusFrom: currentStatus,
79
- statusTo: nextStatus,
80
- });
81
- }
68
+ ensureCommentCommitAllowed({
69
+ enabled: opts.commitFromComment,
70
+ config,
71
+ action: "task set-status",
72
+ confirmed: opts.confirmStatusCommit,
73
+ quiet: opts.quiet,
74
+ statusFrom: currentStatus,
75
+ statusTo: nextStatus,
76
+ });
82
77
  const existingComments = Array.isArray(task.comments)
83
78
  ? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
84
79
  : [];
@@ -1,6 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { type AgentplaneConfig } from "@agentplaneorg/core";
3
- import { type TaskData, type TaskEvent } from "../../backends/task-backend.js";
3
+ import { type TaskBackend, type TaskData, type TaskEvent } from "../../backends/task-backend.js";
4
4
  import type { CommandContext } from "../shared/task-backend.js";
5
5
  export { dedupeStrings } from "../../shared/strings.js";
6
6
  export declare const execFileAsync: typeof execFile.__promisify__;
@@ -37,9 +37,24 @@ export type DependencyState = {
37
37
  missing: string[];
38
38
  incomplete: string[];
39
39
  };
40
+ export declare function resolveTaskDependencyState(task: TaskData, backend: Pick<TaskBackend, "getTask" | "getTasks">): Promise<DependencyState>;
40
41
  export declare function buildDependencyState(tasks: TaskData[]): Map<string, DependencyState>;
41
42
  export declare function formatTaskLine(task: TaskData, depState?: DependencyState): string;
42
43
  export declare function isTransitionAllowed(current: string, next: string): boolean;
44
+ export declare function ensureStatusTransitionAllowed(opts: {
45
+ currentStatus: string;
46
+ nextStatus: string;
47
+ force: boolean;
48
+ }): void;
49
+ export declare function ensureCommentCommitAllowed(opts: {
50
+ enabled: boolean;
51
+ config: AgentplaneConfig;
52
+ action: string;
53
+ confirmed: boolean;
54
+ quiet: boolean;
55
+ statusFrom: string;
56
+ statusTo: string;
57
+ }): void;
43
58
  export declare function requireStructuredComment(body: string, prefix: string, minChars: number): void;
44
59
  export declare function readHeadCommit(cwd: string): Promise<{
45
60
  hash: string;
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/commands/task/shared.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/commands/task/shared.ts"],"names":[],"mappings":"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"}
@@ -249,6 +249,28 @@ export function ensureVerificationSatisfiedIfRequired(task, config) {
249
249
  `(verification.state=${JSON.stringify(state)}; ${hint} or set agents.approvals.require_verify=false).`,
250
250
  });
251
251
  }
252
+ export async function resolveTaskDependencyState(task, backend) {
253
+ const dependsOn = dedupeStrings(toStringArray(task.depends_on));
254
+ if (dependsOn.length === 0) {
255
+ return { dependsOn, missing: [], incomplete: [] };
256
+ }
257
+ const loaded = backend.getTasks
258
+ ? await backend.getTasks(dependsOn)
259
+ : await Promise.all(dependsOn.map(async (depId) => await backend.getTask(depId)));
260
+ const missing = [];
261
+ const incomplete = [];
262
+ for (const [idx, depId] of dependsOn.entries()) {
263
+ const dep = loaded[idx] ?? null;
264
+ if (!dep) {
265
+ missing.push(depId);
266
+ continue;
267
+ }
268
+ const status = String(dep.status || "TODO").toUpperCase();
269
+ if (status !== "DONE")
270
+ incomplete.push(depId);
271
+ }
272
+ return { dependsOn, missing, incomplete };
273
+ }
252
274
  export function buildDependencyState(tasks) {
253
275
  const byId = new Map(tasks.map((task) => [task.id, task]));
254
276
  const state = new Map();
@@ -321,6 +343,38 @@ export function isTransitionAllowed(current, next) {
321
343
  return false;
322
344
  return false;
323
345
  }
346
+ export function ensureStatusTransitionAllowed(opts) {
347
+ if (opts.force)
348
+ return;
349
+ if (isTransitionAllowed(opts.currentStatus, opts.nextStatus))
350
+ return;
351
+ throw new CliError({
352
+ exitCode: 2,
353
+ code: "E_USAGE",
354
+ message: `Refusing status transition ${opts.currentStatus} -> ${opts.nextStatus} ` +
355
+ "(use --force to override)",
356
+ });
357
+ }
358
+ export function ensureCommentCommitAllowed(opts) {
359
+ if (!opts.enabled)
360
+ return;
361
+ if (opts.config.commit_automation === "finish_only") {
362
+ throw new CliError({
363
+ exitCode: 2,
364
+ code: "E_USAGE",
365
+ message: `${opts.action}: --commit-from-comment is disabled by commit_automation='finish_only' ` +
366
+ "(allowed only in finish).",
367
+ });
368
+ }
369
+ enforceStatusCommitPolicy({
370
+ policy: opts.config.status_commit_policy,
371
+ action: opts.action,
372
+ confirmed: opts.confirmed,
373
+ quiet: opts.quiet,
374
+ statusFrom: opts.statusFrom,
375
+ statusTo: opts.statusTo,
376
+ });
377
+ }
324
378
  export function requireStructuredComment(body, prefix, minChars) {
325
379
  const normalized = body.trim();
326
380
  if (!normalized.toLowerCase().startsWith(prefix.toLowerCase())) {
@@ -375,9 +429,6 @@ const MAJOR_STATUS_COMMIT_TRANSITIONS = new Set([
375
429
  "DOING->BLOCKED",
376
430
  "BLOCKED->DOING",
377
431
  "DOING->DONE",
378
- "DONE->VERIFIED",
379
- "VERIFIED->FINISHED",
380
- "VERIFIED->EXPORTED",
381
432
  ]);
382
433
  export function isMajorStatusCommitTransition(statusFrom, statusTo) {
383
434
  const from = statusFrom.trim().toUpperCase();
@@ -1 +1 @@
1
- {"version":3,"file":"start-ready.d.ts","sourceRoot":"","sources":["../../../src/commands/task/start-ready.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAKpF,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,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuClB"}
1
+ {"version":3,"file":"start-ready.d.ts","sourceRoot":"","sources":["../../../src/commands/task/start-ready.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIpF,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,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BlB"}
@@ -1,26 +1,13 @@
1
1
  import { mapBackendError } from "../../cli/error-map.js";
2
+ import { successMessage } from "../../cli/output.js";
2
3
  import { CliError } from "../../shared/errors.js";
3
4
  import { loadCommandContext } from "../shared/task-backend.js";
4
- import { cmdReady } from "./ready.js";
5
5
  import { cmdStart } from "./start.js";
6
6
  export async function cmdTaskStartReady(opts) {
7
7
  try {
8
8
  const ctx = opts.ctx ??
9
9
  (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
10
- const readyCode = await cmdReady({
11
- ctx,
12
- cwd: opts.cwd,
13
- rootOverride: opts.rootOverride,
14
- taskId: opts.taskId,
15
- });
16
- if (readyCode !== 0 && !opts.force) {
17
- throw new CliError({
18
- exitCode: 2,
19
- code: "E_USAGE",
20
- message: `Task is not ready: ${opts.taskId} (resolve dependencies or use --force)`,
21
- });
22
- }
23
- return await cmdStart({
10
+ const result = await cmdStart({
24
11
  ctx,
25
12
  cwd: opts.cwd,
26
13
  rootOverride: opts.rootOverride,
@@ -37,6 +24,10 @@ export async function cmdTaskStartReady(opts) {
37
24
  yes: opts.yes,
38
25
  quiet: opts.quiet,
39
26
  });
27
+ if (!opts.quiet) {
28
+ process.stdout.write(`${successMessage("ready", opts.taskId)}\n`);
29
+ }
30
+ return result;
40
31
  }
41
32
  catch (err) {
42
33
  if (err instanceof CliError)
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/task/start.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAqBnC,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,CAqMlB"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/task/start.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAqBnC,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,CA+LlB"}
@@ -4,10 +4,10 @@ import { formatCommentBodyForCommit } from "../../shared/comment-format.js";
4
4
  import { CliError } from "../../shared/errors.js";
5
5
  import { commitFromComment } from "../guard/index.js";
6
6
  import { ensureActionApproved } from "../shared/approval-requirements.js";
7
- import { listTasksMemo, loadCommandContext, loadTaskFromContext, } from "../shared/task-backend.js";
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, buildDependencyState, ensurePlanApprovedIfRequired, enforceStatusCommitPolicy, defaultCommitEmojiForAgentId, extractDocSection, isVerifyStepsFilled, isTransitionAllowed, nowIso, requiresVerifyStepsByPrimary, requireStructuredComment, resolvePrimaryTag, toStringArray, } from "./shared.js";
10
+ import { appendTaskEvent, ensurePlanApprovedIfRequired, ensureCommentCommitAllowed, ensureStatusTransitionAllowed, defaultCommitEmojiForAgentId, extractDocSection, isVerifyStepsFilled, nowIso, requiresVerifyStepsByPrimary, requireStructuredComment, resolveTaskDependencyState, resolvePrimaryTag, toStringArray, } from "./shared.js";
11
11
  export async function cmdStart(opts) {
12
12
  try {
13
13
  const ctx = opts.ctx ??
@@ -61,28 +61,23 @@ export async function cmdStart(opts) {
61
61
  }
62
62
  ensurePlanApprovedIfRequired(task, ctx.config);
63
63
  const currentStatus = String(task.status || "TODO").toUpperCase();
64
- if (!opts.force && !isTransitionAllowed(currentStatus, "DOING")) {
65
- throw new CliError({
66
- exitCode: 2,
67
- code: "E_USAGE",
68
- message: `Refusing status transition ${currentStatus} -> DOING (use --force to override)`,
69
- });
70
- }
71
- if (opts.commitFromComment) {
72
- enforceStatusCommitPolicy({
73
- policy: ctx.config.status_commit_policy,
74
- action: "start",
75
- confirmed: opts.confirmStatusCommit,
76
- quiet: opts.quiet,
77
- statusFrom: currentStatus,
78
- statusTo: "DOING",
79
- });
80
- }
64
+ ensureStatusTransitionAllowed({
65
+ currentStatus,
66
+ nextStatus: "DOING",
67
+ force: opts.force,
68
+ });
69
+ ensureCommentCommitAllowed({
70
+ enabled: opts.commitFromComment,
71
+ config: ctx.config,
72
+ action: "start",
73
+ confirmed: opts.confirmStatusCommit,
74
+ quiet: opts.quiet,
75
+ statusFrom: currentStatus,
76
+ statusTo: "DOING",
77
+ });
81
78
  if (!opts.force) {
82
- const allTasks = await listTasksMemo(ctx);
83
- const depState = buildDependencyState(allTasks);
84
- const dep = depState.get(task.id);
85
- if (dep && (dep.missing.length > 0 || dep.incomplete.length > 0)) {
79
+ const dep = await resolveTaskDependencyState(task, ctx.taskBackend);
80
+ if (dep.missing.length > 0 || dep.incomplete.length > 0) {
86
81
  if (!opts.quiet) {
87
82
  if (dep.missing.length > 0) {
88
83
  process.stderr.write(`${warnMessage(`missing deps: ${dep.missing.join(", ")}`)}\n`);