agentplane 0.1.6 → 0.1.8

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 (138) hide show
  1. package/assets/AGENTS.md +1 -1
  2. package/assets/agents/ORCHESTRATOR.json +1 -1
  3. package/assets/agents/UPGRADER.json +1 -1
  4. package/dist/backends/task-backend.d.ts +16 -0
  5. package/dist/backends/task-backend.d.ts.map +1 -1
  6. package/dist/backends/task-backend.js +44 -0
  7. package/dist/backends/task-index.d.ts.map +1 -1
  8. package/dist/backends/task-index.js +3 -6
  9. package/dist/cli/command-guide.d.ts.map +1 -1
  10. package/dist/cli/command-guide.js +4 -4
  11. package/dist/cli/help.d.ts.map +1 -1
  12. package/dist/cli/help.js +7 -5
  13. package/dist/cli/run-cli.d.ts.map +1 -1
  14. package/dist/cli/run-cli.js +39 -78
  15. package/dist/commands/backend.d.ts.map +1 -1
  16. package/dist/commands/backend.js +17 -2
  17. package/dist/commands/branch/index.d.ts +60 -0
  18. package/dist/commands/branch/index.d.ts.map +1 -0
  19. package/dist/commands/branch/index.js +513 -0
  20. package/dist/commands/guard/index.d.ts +67 -0
  21. package/dist/commands/guard/index.d.ts.map +1 -0
  22. package/dist/commands/guard/index.js +367 -0
  23. package/dist/commands/hooks/index.d.ts +18 -0
  24. package/dist/commands/hooks/index.d.ts.map +1 -0
  25. package/dist/commands/hooks/index.js +290 -0
  26. package/dist/commands/pr/index.d.ts +46 -0
  27. package/dist/commands/pr/index.d.ts.map +1 -0
  28. package/dist/commands/pr/index.js +857 -0
  29. package/dist/commands/recipes.d.ts.map +1 -1
  30. package/dist/commands/recipes.js +67 -23
  31. package/dist/commands/shared/git-diff.d.ts +9 -0
  32. package/dist/commands/shared/git-diff.d.ts.map +1 -0
  33. package/dist/commands/shared/git-diff.js +41 -0
  34. package/dist/commands/shared/git-ops.d.ts +24 -0
  35. package/dist/commands/shared/git-ops.d.ts.map +1 -0
  36. package/dist/commands/shared/git-ops.js +181 -0
  37. package/dist/commands/shared/git-worktree.d.ts +8 -0
  38. package/dist/commands/shared/git-worktree.d.ts.map +1 -0
  39. package/dist/commands/shared/git-worktree.js +48 -0
  40. package/dist/commands/shared/git.d.ts +4 -0
  41. package/dist/commands/shared/git.d.ts.map +1 -0
  42. package/dist/commands/shared/git.js +14 -0
  43. package/dist/commands/shared/network-approval.d.ts +8 -0
  44. package/dist/commands/shared/network-approval.d.ts.map +1 -0
  45. package/dist/commands/shared/network-approval.js +25 -0
  46. package/dist/commands/shared/path.d.ts +3 -0
  47. package/dist/commands/shared/path.d.ts.map +1 -0
  48. package/dist/commands/shared/path.js +14 -0
  49. package/dist/commands/shared/pr-meta.d.ts +21 -0
  50. package/dist/commands/shared/pr-meta.d.ts.map +1 -0
  51. package/dist/commands/shared/pr-meta.js +72 -0
  52. package/dist/commands/shared/task-backend.d.ts +15 -0
  53. package/dist/commands/shared/task-backend.d.ts.map +1 -0
  54. package/dist/commands/shared/task-backend.js +61 -0
  55. package/dist/commands/task/add.d.ts +8 -0
  56. package/dist/commands/task/add.d.ts.map +1 -0
  57. package/dist/commands/task/add.js +164 -0
  58. package/dist/commands/task/block.d.ts +19 -0
  59. package/dist/commands/task/block.d.ts.map +1 -0
  60. package/dist/commands/task/block.js +86 -0
  61. package/dist/commands/task/comment.d.ts +8 -0
  62. package/dist/commands/task/comment.d.ts.map +1 -0
  63. package/dist/commands/task/comment.js +29 -0
  64. package/dist/commands/task/doc.d.ts +17 -0
  65. package/dist/commands/task/doc.d.ts.map +1 -0
  66. package/dist/commands/task/doc.js +220 -0
  67. package/dist/commands/task/export.d.ts +5 -0
  68. package/dist/commands/task/export.d.ts.map +1 -0
  69. package/dist/commands/task/export.js +27 -0
  70. package/dist/commands/task/finish.d.ts +27 -0
  71. package/dist/commands/task/finish.d.ts.map +1 -0
  72. package/dist/commands/task/finish.js +132 -0
  73. package/dist/commands/task/index.d.ts +26 -0
  74. package/dist/commands/task/index.d.ts.map +1 -0
  75. package/dist/commands/task/index.js +25 -0
  76. package/dist/commands/task/lint.d.ts +5 -0
  77. package/dist/commands/task/lint.d.ts.map +1 -0
  78. package/dist/commands/task/lint.js +22 -0
  79. package/dist/commands/task/list.d.ts +11 -0
  80. package/dist/commands/task/list.d.ts.map +1 -0
  81. package/dist/commands/task/list.js +54 -0
  82. package/dist/commands/task/migrate-doc.d.ts +8 -0
  83. package/dist/commands/task/migrate-doc.d.ts.map +1 -0
  84. package/dist/commands/task/migrate-doc.js +147 -0
  85. package/dist/commands/task/migrate.d.ts +6 -0
  86. package/dist/commands/task/migrate.d.ts.map +1 -0
  87. package/dist/commands/task/migrate.js +70 -0
  88. package/dist/commands/task/new.d.ts +8 -0
  89. package/dist/commands/task/new.d.ts.map +1 -0
  90. package/dist/commands/task/new.js +117 -0
  91. package/dist/commands/task/next.d.ts +6 -0
  92. package/dist/commands/task/next.d.ts.map +1 -0
  93. package/dist/commands/task/next.js +45 -0
  94. package/dist/commands/task/normalize.d.ts +6 -0
  95. package/dist/commands/task/normalize.d.ts.map +1 -0
  96. package/dist/commands/task/normalize.js +46 -0
  97. package/dist/commands/task/plan.d.ts +14 -0
  98. package/dist/commands/task/plan.d.ts.map +1 -0
  99. package/dist/commands/task/plan.js +217 -0
  100. package/dist/commands/task/ready.d.ts +6 -0
  101. package/dist/commands/task/ready.d.ts.map +1 -0
  102. package/dist/commands/task/ready.js +57 -0
  103. package/dist/commands/task/scaffold.d.ts +8 -0
  104. package/dist/commands/task/scaffold.d.ts.map +1 -0
  105. package/dist/commands/task/scaffold.js +142 -0
  106. package/dist/commands/task/scrub.d.ts +8 -0
  107. package/dist/commands/task/scrub.d.ts.map +1 -0
  108. package/dist/commands/task/scrub.js +121 -0
  109. package/dist/commands/task/search.d.ts +7 -0
  110. package/dist/commands/task/search.d.ts.map +1 -0
  111. package/dist/commands/task/search.js +79 -0
  112. package/dist/commands/task/set-status.d.ts +19 -0
  113. package/dist/commands/task/set-status.d.ts.map +1 -0
  114. package/dist/commands/task/set-status.js +123 -0
  115. package/dist/commands/task/shared.d.ts +48 -0
  116. package/dist/commands/task/shared.d.ts.map +1 -0
  117. package/dist/commands/task/shared.js +312 -0
  118. package/dist/commands/task/show.d.ts +6 -0
  119. package/dist/commands/task/show.d.ts.map +1 -0
  120. package/dist/commands/task/show.js +35 -0
  121. package/dist/commands/task/start.d.ts +19 -0
  122. package/dist/commands/task/start.d.ts.map +1 -0
  123. package/dist/commands/task/start.js +110 -0
  124. package/dist/commands/task/update.d.ts +8 -0
  125. package/dist/commands/task/update.d.ts.map +1 -0
  126. package/dist/commands/task/update.js +144 -0
  127. package/dist/commands/task/verify-record.d.ts +16 -0
  128. package/dist/commands/task/verify-record.d.ts.map +1 -0
  129. package/dist/commands/task/verify-record.js +277 -0
  130. package/dist/commands/task/verify.d.ts +2 -0
  131. package/dist/commands/task/verify.d.ts.map +1 -0
  132. package/dist/commands/task/verify.js +1 -0
  133. package/dist/commands/upgrade.d.ts.map +1 -1
  134. package/dist/commands/upgrade.js +17 -2
  135. package/dist/commands/workflow.d.ts +5 -364
  136. package/dist/commands/workflow.d.ts.map +1 -1
  137. package/dist/commands/workflow.js +6 -4617
  138. package/package.json +2 -2
@@ -0,0 +1,19 @@
1
+ export declare function cmdTaskSetStatus(opts: {
2
+ cwd: string;
3
+ rootOverride?: string;
4
+ taskId: string;
5
+ status: string;
6
+ author?: string;
7
+ body?: string;
8
+ commit?: string;
9
+ force: boolean;
10
+ commitFromComment: boolean;
11
+ commitEmoji?: string;
12
+ commitAllow: string[];
13
+ commitAutoAllow: boolean;
14
+ commitAllowTasks: boolean;
15
+ commitRequireClean: boolean;
16
+ confirmStatusCommit: boolean;
17
+ quiet: boolean;
18
+ }): Promise<number>;
19
+ //# sourceMappingURL=set-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set-status.d.ts","sourceRoot":"","sources":["../../../src/commands/task/set-status.ts"],"names":[],"mappings":"AAmBA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,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,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,CA8HlB"}
@@ -0,0 +1,123 @@
1
+ import { mapBackendError } from "../../cli/error-map.js";
2
+ import { successMessage, warnMessage } from "../../cli/output.js";
3
+ import { formatCommentBodyForCommit } from "../../shared/comment-format.js";
4
+ import { CliError } from "../../shared/errors.js";
5
+ import { commitFromComment } from "../guard/index.js";
6
+ import { loadBackendTask, resolveDocUpdatedBy } from "../shared/task-backend.js";
7
+ import { buildDependencyState, defaultCommitEmojiForStatus, enforceStatusCommitPolicy, isTransitionAllowed, normalizeTaskStatus, nowIso, readCommitInfo, } from "./shared.js";
8
+ export async function cmdTaskSetStatus(opts) {
9
+ const nextStatus = normalizeTaskStatus(opts.status);
10
+ if (nextStatus === "DONE" && !opts.force) {
11
+ throw new CliError({
12
+ exitCode: 2,
13
+ code: "E_USAGE",
14
+ message: "Use `agentplane finish` to mark DONE (use --force to override)",
15
+ });
16
+ }
17
+ if ((opts.author && !opts.body) || (opts.body && !opts.author)) {
18
+ throw new CliError({
19
+ exitCode: 2,
20
+ code: "E_USAGE",
21
+ message: "--author and --body must be provided together",
22
+ });
23
+ }
24
+ try {
25
+ const { backend, task, config, resolved } = await loadBackendTask({
26
+ cwd: opts.cwd,
27
+ rootOverride: opts.rootOverride ?? null,
28
+ taskId: opts.taskId,
29
+ });
30
+ if (opts.commitFromComment) {
31
+ enforceStatusCommitPolicy({
32
+ policy: config.status_commit_policy,
33
+ action: "task set-status",
34
+ confirmed: opts.confirmStatusCommit,
35
+ quiet: opts.quiet,
36
+ });
37
+ }
38
+ const currentStatus = String(task.status || "TODO").toUpperCase();
39
+ if (!opts.force && !isTransitionAllowed(currentStatus, nextStatus)) {
40
+ throw new CliError({
41
+ exitCode: 2,
42
+ code: "E_USAGE",
43
+ message: `Refusing status transition ${currentStatus} -> ${nextStatus} (use --force to override)`,
44
+ });
45
+ }
46
+ if (!opts.force && (nextStatus === "DOING" || nextStatus === "DONE")) {
47
+ const allTasks = await backend.listTasks();
48
+ const depState = buildDependencyState(allTasks);
49
+ const dep = depState.get(task.id);
50
+ if (dep && (dep.missing.length > 0 || dep.incomplete.length > 0)) {
51
+ if (!opts.quiet) {
52
+ if (dep.missing.length > 0) {
53
+ process.stderr.write(`${warnMessage(`missing deps: ${dep.missing.join(", ")}`)}\n`);
54
+ }
55
+ if (dep.incomplete.length > 0) {
56
+ process.stderr.write(`${warnMessage(`incomplete deps: ${dep.incomplete.join(", ")}`)}\n`);
57
+ }
58
+ }
59
+ throw new CliError({
60
+ exitCode: 2,
61
+ code: "E_USAGE",
62
+ message: `Task is not ready: ${task.id} (use --force to override)`,
63
+ });
64
+ }
65
+ }
66
+ const existingComments = Array.isArray(task.comments)
67
+ ? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
68
+ : [];
69
+ let comments = existingComments;
70
+ if (opts.author && opts.body) {
71
+ const commentBody = opts.commitFromComment
72
+ ? formatCommentBodyForCommit(opts.body, config)
73
+ : opts.body;
74
+ comments = [...existingComments, { author: opts.author, body: commentBody }];
75
+ }
76
+ const next = {
77
+ ...task,
78
+ status: nextStatus,
79
+ comments,
80
+ doc_version: 2,
81
+ doc_updated_at: nowIso(),
82
+ doc_updated_by: resolveDocUpdatedBy(task, opts.author),
83
+ };
84
+ if (opts.commit) {
85
+ const commitInfo = await readCommitInfo(resolved.gitRoot, opts.commit);
86
+ next.commit = { hash: commitInfo.hash, message: commitInfo.message };
87
+ }
88
+ await backend.writeTask(next);
89
+ // tasks.json is export-only; generated via `agentplane task export`.
90
+ if (opts.commitFromComment) {
91
+ if (!opts.body) {
92
+ throw new CliError({
93
+ exitCode: 2,
94
+ code: "E_USAGE",
95
+ message: "--body is required when using --commit-from-comment",
96
+ });
97
+ }
98
+ await commitFromComment({
99
+ cwd: opts.cwd,
100
+ rootOverride: opts.rootOverride,
101
+ taskId: opts.taskId,
102
+ commentBody: opts.body,
103
+ formattedComment: formatCommentBodyForCommit(opts.body, config),
104
+ emoji: opts.commitEmoji ?? defaultCommitEmojiForStatus(nextStatus),
105
+ allow: opts.commitAllow,
106
+ autoAllow: opts.commitAutoAllow || opts.commitAllow.length === 0,
107
+ allowTasks: opts.commitAllowTasks,
108
+ requireClean: opts.commitRequireClean,
109
+ quiet: opts.quiet,
110
+ config,
111
+ });
112
+ }
113
+ if (!opts.quiet) {
114
+ process.stdout.write(`${successMessage("status", opts.taskId, `next=${nextStatus}`)}\n`);
115
+ }
116
+ return 0;
117
+ }
118
+ catch (err) {
119
+ if (err instanceof CliError)
120
+ throw err;
121
+ throw mapBackendError(err, { command: "task set-status", root: opts.rootOverride ?? null });
122
+ }
123
+ }
@@ -0,0 +1,48 @@
1
+ import { execFile } from "node:child_process";
2
+ import { type AgentplaneConfig } from "@agentplaneorg/core";
3
+ import { type TaskData } from "../../backends/task-backend.js";
4
+ export declare const execFileAsync: typeof execFile.__promisify__;
5
+ export declare function nowIso(): string;
6
+ export declare function normalizeDependsOnInput(value: string): string[];
7
+ export declare function normalizeTaskStatus(value: string): string;
8
+ export declare function dedupeStrings(items: string[]): string[];
9
+ export declare function toStringArray(value: unknown): string[];
10
+ export declare function requiresVerify(tags: string[], requiredTags: string[]): boolean;
11
+ export declare function ensurePlanApprovedIfRequired(task: TaskData, config: AgentplaneConfig): void;
12
+ export declare function ensureVerificationSatisfiedIfRequired(task: TaskData, config: AgentplaneConfig): void;
13
+ export type DependencyState = {
14
+ dependsOn: string[];
15
+ missing: string[];
16
+ incomplete: string[];
17
+ };
18
+ export declare function buildDependencyState(tasks: TaskData[]): Map<string, DependencyState>;
19
+ export declare function formatTaskLine(task: TaskData, depState?: DependencyState): string;
20
+ export declare function isTransitionAllowed(current: string, next: string): boolean;
21
+ export declare function requireStructuredComment(body: string, prefix: string, minChars: number): void;
22
+ export declare function readHeadCommit(cwd: string): Promise<{
23
+ hash: string;
24
+ message: string;
25
+ }>;
26
+ export declare function enforceStatusCommitPolicy(opts: {
27
+ policy: AgentplaneConfig["status_commit_policy"];
28
+ action: string;
29
+ confirmed: boolean;
30
+ quiet: boolean;
31
+ }): void;
32
+ export declare function readCommitInfo(cwd: string, rev: string): Promise<{
33
+ hash: string;
34
+ message: string;
35
+ }>;
36
+ export declare function defaultCommitEmojiForStatus(status: string): string;
37
+ export type TaskListFilters = {
38
+ status: string[];
39
+ owner: string[];
40
+ tag: string[];
41
+ limit?: number;
42
+ quiet: boolean;
43
+ };
44
+ export declare function parseTaskListFilters(args: string[], opts?: {
45
+ allowLimit?: boolean;
46
+ }): TaskListFilters;
47
+ export declare function taskTextBlob(task: TaskData): string;
48
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/commands/task/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAQ5D,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAG/D,eAAO,MAAM,aAAa,+BAAsB,CAAC;AAEjD,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAI/D;AAID,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAczD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAWvD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAKtD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAI9E;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAc3F;AAED,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,gBAAgB,GACvB,IAAI,CAiBN;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAqBpF;AAgBD,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,MAAM,CAgBjF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO1E;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAgB7F;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ5F;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,MAAM,EAAE,gBAAgB,CAAC,sBAAsB,CAAC,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,IAAI,CAqBP;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ5C;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9B,eAAe,CAsEjB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAiBnD"}
@@ -0,0 +1,312 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { invalidValueForFlag, invalidValueMessage, missingValueMessage, warnMessage, } from "../../cli/output.js";
4
+ import { CliError } from "../../shared/errors.js";
5
+ export const execFileAsync = promisify(execFile);
6
+ export function nowIso() {
7
+ return new Date().toISOString();
8
+ }
9
+ export function normalizeDependsOnInput(value) {
10
+ const trimmed = value.trim();
11
+ if (!trimmed || trimmed === "[]")
12
+ return [];
13
+ return [trimmed];
14
+ }
15
+ const ALLOWED_TASK_STATUSES = new Set(["TODO", "DOING", "DONE", "BLOCKED"]);
16
+ export function normalizeTaskStatus(value) {
17
+ const normalized = value.trim().toUpperCase();
18
+ if (!ALLOWED_TASK_STATUSES.has(normalized)) {
19
+ throw new CliError({
20
+ exitCode: 2,
21
+ code: "E_USAGE",
22
+ message: invalidValueMessage("status", value, `one of ${[...ALLOWED_TASK_STATUSES].join(", ")}`),
23
+ });
24
+ }
25
+ return normalized;
26
+ }
27
+ export function dedupeStrings(items) {
28
+ const seen = new Set();
29
+ const out = [];
30
+ for (const item of items) {
31
+ const trimmed = item.trim();
32
+ if (!trimmed)
33
+ continue;
34
+ if (seen.has(trimmed))
35
+ continue;
36
+ seen.add(trimmed);
37
+ out.push(trimmed);
38
+ }
39
+ return out;
40
+ }
41
+ export function toStringArray(value) {
42
+ if (!Array.isArray(value))
43
+ return [];
44
+ return value
45
+ .filter((item) => typeof item === "string")
46
+ .map((item) => item.trim());
47
+ }
48
+ export function requiresVerify(tags, requiredTags) {
49
+ const required = new Set(requiredTags.map((tag) => tag.trim().toLowerCase()).filter(Boolean));
50
+ if (required.size === 0)
51
+ return false;
52
+ return tags.some((tag) => required.has(tag.trim().toLowerCase()));
53
+ }
54
+ export function ensurePlanApprovedIfRequired(task, config) {
55
+ if (config.agents?.approvals?.require_plan !== true)
56
+ return;
57
+ const state = task.plan_approval?.state ?? "missing";
58
+ if (state === "approved")
59
+ return;
60
+ throw new CliError({
61
+ exitCode: 3,
62
+ code: "E_VALIDATION",
63
+ message: `${task.id}: plan approval is required before work can proceed ` +
64
+ `(plan_approval.state=${JSON.stringify(state)}; use \`agentplane task plan approve ${task.id} --by <USER>\` ` +
65
+ "or set agents.approvals.require_plan=false).",
66
+ });
67
+ }
68
+ export function ensureVerificationSatisfiedIfRequired(task, config) {
69
+ if (config.agents?.approvals?.require_verify !== true)
70
+ return;
71
+ const state = task.verification?.state ?? "missing";
72
+ if (state === "ok")
73
+ return;
74
+ const hint = `use \`agentplane verify ${task.id} --ok|--rework --by <ID> --note <TEXT>\` ` +
75
+ `or \`agentplane task verify ok|rework ${task.id} --by <ID> --note <TEXT>\``;
76
+ throw new CliError({
77
+ exitCode: 3,
78
+ code: "E_VALIDATION",
79
+ message: `${task.id}: verification result is required before integration/closure can proceed ` +
80
+ `(verification.state=${JSON.stringify(state)}; ${hint} or set agents.approvals.require_verify=false).`,
81
+ });
82
+ }
83
+ export function buildDependencyState(tasks) {
84
+ const byId = new Map(tasks.map((task) => [task.id, task]));
85
+ const state = new Map();
86
+ for (const task of tasks) {
87
+ const dependsOn = dedupeStrings(toStringArray(task.depends_on));
88
+ const missing = [];
89
+ const incomplete = [];
90
+ for (const depId of dependsOn) {
91
+ const dep = byId.get(depId);
92
+ if (!dep) {
93
+ missing.push(depId);
94
+ continue;
95
+ }
96
+ const status = String(dep.status || "TODO").toUpperCase();
97
+ if (status !== "DONE") {
98
+ incomplete.push(depId);
99
+ }
100
+ }
101
+ state.set(task.id, { dependsOn, missing, incomplete });
102
+ }
103
+ return state;
104
+ }
105
+ function formatDepsSummary(dep) {
106
+ if (!dep)
107
+ return null;
108
+ if (dep.dependsOn.length === 0)
109
+ return "deps=none";
110
+ if (dep.missing.length === 0 && dep.incomplete.length === 0)
111
+ return "deps=ready";
112
+ const parts = [];
113
+ if (dep.missing.length > 0) {
114
+ parts.push(`missing:${dep.missing.join(",")}`);
115
+ }
116
+ if (dep.incomplete.length > 0) {
117
+ parts.push(`wait:${dep.incomplete.join(",")}`);
118
+ }
119
+ return `deps=${parts.join(",")}`;
120
+ }
121
+ export function formatTaskLine(task, depState) {
122
+ const status = String(task.status || "TODO").toUpperCase();
123
+ const title = task.title?.trim() || "(untitled task)";
124
+ const extras = [];
125
+ if (task.owner?.trim())
126
+ extras.push(`owner=${task.owner.trim()}`);
127
+ if (task.priority !== undefined && String(task.priority).trim()) {
128
+ extras.push(`prio=${String(task.priority).trim()}`);
129
+ }
130
+ const depsSummary = formatDepsSummary(depState);
131
+ if (depsSummary)
132
+ extras.push(depsSummary);
133
+ const tags = dedupeStrings(toStringArray(task.tags));
134
+ if (tags.length > 0)
135
+ extras.push(`tags=${tags.join(",")}`);
136
+ const verify = dedupeStrings(toStringArray(task.verify));
137
+ if (verify.length > 0)
138
+ extras.push(`verify=${verify.length}`);
139
+ const suffix = extras.length > 0 ? ` (${extras.join(", ")})` : "";
140
+ return `${task.id} [${status}] ${title}${suffix}`;
141
+ }
142
+ export function isTransitionAllowed(current, next) {
143
+ if (current === next)
144
+ return true;
145
+ if (current === "TODO")
146
+ return next === "DOING" || next === "BLOCKED";
147
+ if (current === "DOING")
148
+ return next === "DONE" || next === "BLOCKED";
149
+ if (current === "BLOCKED")
150
+ return next === "TODO" || next === "DOING";
151
+ if (current === "DONE")
152
+ return false;
153
+ return false;
154
+ }
155
+ export function requireStructuredComment(body, prefix, minChars) {
156
+ const normalized = body.trim();
157
+ if (!normalized.toLowerCase().startsWith(prefix.toLowerCase())) {
158
+ throw new CliError({
159
+ exitCode: 2,
160
+ code: "E_USAGE",
161
+ message: `Comment body must start with ${prefix}`,
162
+ });
163
+ }
164
+ if (normalized.length < minChars) {
165
+ throw new CliError({
166
+ exitCode: 2,
167
+ code: "E_USAGE",
168
+ message: `Comment body must be at least ${minChars} characters`,
169
+ });
170
+ }
171
+ }
172
+ export async function readHeadCommit(cwd) {
173
+ const { stdout } = await execFileAsync("git", ["log", "-1", "--pretty=%H:%s"], { cwd });
174
+ const trimmed = stdout.trim();
175
+ const [hash, message] = trimmed.split(":", 2);
176
+ if (!hash || !message) {
177
+ throw new Error("Unable to read git HEAD commit");
178
+ }
179
+ return { hash, message };
180
+ }
181
+ export function enforceStatusCommitPolicy(opts) {
182
+ if (opts.policy === "off")
183
+ return;
184
+ if (opts.policy === "warn") {
185
+ if (!opts.quiet && !opts.confirmed) {
186
+ process.stderr.write(`${warnMessage(`${opts.action}: status/comment-driven commit requested; policy=warn (pass --confirm-status-commit to acknowledge)`)}\n`);
187
+ }
188
+ return;
189
+ }
190
+ if (opts.policy === "confirm" && !opts.confirmed) {
191
+ throw new CliError({
192
+ exitCode: 2,
193
+ code: "E_USAGE",
194
+ message: `${opts.action}: status/comment-driven commit blocked by status_commit_policy='confirm' ` +
195
+ "(pass --confirm-status-commit to proceed)",
196
+ });
197
+ }
198
+ }
199
+ export async function readCommitInfo(cwd, rev) {
200
+ const { stdout } = await execFileAsync("git", ["log", "-1", "--pretty=%H:%s", rev], { cwd });
201
+ const trimmed = stdout.trim();
202
+ const [hash, message] = trimmed.split(":", 2);
203
+ if (!hash || !message) {
204
+ throw new Error("Unable to read git commit");
205
+ }
206
+ return { hash, message };
207
+ }
208
+ export function defaultCommitEmojiForStatus(status) {
209
+ const normalized = status.trim().toUpperCase();
210
+ if (normalized === "DOING")
211
+ return "🚧";
212
+ if (normalized === "DONE")
213
+ return "✅";
214
+ if (normalized === "BLOCKED")
215
+ return "⛔";
216
+ return "🧩";
217
+ }
218
+ export function parseTaskListFilters(args, opts) {
219
+ const out = { status: [], owner: [], tag: [], quiet: false };
220
+ for (let i = 0; i < args.length; i++) {
221
+ const arg = args[i];
222
+ if (!arg)
223
+ continue;
224
+ if (arg === "--quiet") {
225
+ out.quiet = true;
226
+ continue;
227
+ }
228
+ if (arg === "--status") {
229
+ const next = args[i + 1];
230
+ if (!next) {
231
+ throw new CliError({
232
+ exitCode: 2,
233
+ code: "E_USAGE",
234
+ message: missingValueMessage("--status"),
235
+ });
236
+ }
237
+ out.status.push(next);
238
+ i++;
239
+ continue;
240
+ }
241
+ if (arg === "--owner") {
242
+ const next = args[i + 1];
243
+ if (!next) {
244
+ throw new CliError({
245
+ exitCode: 2,
246
+ code: "E_USAGE",
247
+ message: missingValueMessage("--owner"),
248
+ });
249
+ }
250
+ out.owner.push(next);
251
+ i++;
252
+ continue;
253
+ }
254
+ if (arg === "--tag") {
255
+ const next = args[i + 1];
256
+ if (!next) {
257
+ throw new CliError({ exitCode: 2, code: "E_USAGE", message: missingValueMessage("--tag") });
258
+ }
259
+ out.tag.push(next);
260
+ i++;
261
+ continue;
262
+ }
263
+ if (opts?.allowLimit && arg === "--limit") {
264
+ const next = args[i + 1];
265
+ if (!next) {
266
+ throw new CliError({
267
+ exitCode: 2,
268
+ code: "E_USAGE",
269
+ message: missingValueMessage("--limit"),
270
+ });
271
+ }
272
+ const parsed = Number.parseInt(next, 10);
273
+ if (!Number.isFinite(parsed)) {
274
+ throw new CliError({
275
+ exitCode: 2,
276
+ code: "E_USAGE",
277
+ message: invalidValueForFlag("--limit", next, "integer"),
278
+ });
279
+ }
280
+ out.limit = parsed;
281
+ i++;
282
+ continue;
283
+ }
284
+ if (arg.startsWith("--")) {
285
+ throw new CliError({ exitCode: 2, code: "E_USAGE", message: `Unknown flag: ${arg}` });
286
+ }
287
+ }
288
+ return out;
289
+ }
290
+ export function taskTextBlob(task) {
291
+ const parts = [];
292
+ for (const key of ["id", "title", "description", "status", "priority", "owner"]) {
293
+ const value = task[key];
294
+ if (typeof value === "string" && value.trim())
295
+ parts.push(value.trim());
296
+ }
297
+ const tags = toStringArray(task.tags);
298
+ parts.push(...tags.filter(Boolean));
299
+ const comments = Array.isArray(task.comments) ? task.comments : [];
300
+ for (const comment of comments) {
301
+ if (comment && typeof comment.author === "string")
302
+ parts.push(comment.author);
303
+ if (comment && typeof comment.body === "string")
304
+ parts.push(comment.body);
305
+ }
306
+ const commit = task.commit ?? null;
307
+ if (commit && typeof commit.hash === "string")
308
+ parts.push(commit.hash);
309
+ if (commit && typeof commit.message === "string")
310
+ parts.push(commit.message);
311
+ return parts.join("\n");
312
+ }
@@ -0,0 +1,6 @@
1
+ export declare function cmdTaskShow(opts: {
2
+ cwd: string;
3
+ rootOverride?: string;
4
+ taskId: string;
5
+ }): Promise<number>;
6
+ //# sourceMappingURL=show.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/commands/task/show.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BlB"}
@@ -0,0 +1,35 @@
1
+ import { validateTaskDocMetadata } from "@agentplaneorg/core";
2
+ import { mapBackendError } from "../../cli/error-map.js";
3
+ import { CliError } from "../../shared/errors.js";
4
+ import { loadBackendTask, taskDataToFrontmatter } from "../shared/task-backend.js";
5
+ export async function cmdTaskShow(opts) {
6
+ try {
7
+ const { task, backendId } = await loadBackendTask({
8
+ cwd: opts.cwd,
9
+ rootOverride: opts.rootOverride,
10
+ taskId: opts.taskId,
11
+ });
12
+ const frontmatter = taskDataToFrontmatter(task);
13
+ if (backendId === "local") {
14
+ const metadataErrors = validateTaskDocMetadata(frontmatter);
15
+ if (metadataErrors.length > 0) {
16
+ throw new CliError({
17
+ exitCode: 3,
18
+ code: "E_VALIDATION",
19
+ message: `Invalid task README metadata: ${metadataErrors.join("; ")}`,
20
+ });
21
+ }
22
+ }
23
+ process.stdout.write(`${JSON.stringify(frontmatter, null, 2)}\n`);
24
+ return 0;
25
+ }
26
+ catch (err) {
27
+ if (err instanceof CliError)
28
+ throw err;
29
+ throw mapBackendError(err, {
30
+ command: "task show",
31
+ root: opts.rootOverride ?? null,
32
+ taskId: opts.taskId,
33
+ });
34
+ }
35
+ }
@@ -0,0 +1,19 @@
1
+ export declare const START_USAGE = "Usage: agentplane start <task-id> --author <id> --body <text> [flags]";
2
+ export declare const START_USAGE_EXAMPLE = "agentplane start 202602030608-F1Q8AB --author CODER --body \"Start: ...\"";
3
+ export declare function cmdStart(opts: {
4
+ cwd: string;
5
+ rootOverride?: string;
6
+ taskId: string;
7
+ author: string;
8
+ body: string;
9
+ commitFromComment: boolean;
10
+ commitEmoji?: string;
11
+ commitAllow: string[];
12
+ commitAutoAllow: boolean;
13
+ commitAllowTasks: boolean;
14
+ commitRequireClean: boolean;
15
+ confirmStatusCommit: boolean;
16
+ force: boolean;
17
+ quiet: boolean;
18
+ }): Promise<number>;
19
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/task/start.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,WAAW,0EAA0E,CAAC;AACnG,eAAO,MAAM,mBAAmB,8EAC2C,CAAC;AAE5E,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,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,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkHlB"}