agentplane 0.1.5 → 0.1.7
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.
- package/assets/AGENTS.md +1 -1
- package/assets/agents/ORCHESTRATOR.json +1 -1
- package/assets/agents/UPGRADER.json +1 -1
- package/dist/cli/run-cli.d.ts.map +1 -1
- package/dist/cli/run-cli.js +22 -7
- package/dist/commands/branch/index.d.ts +60 -0
- package/dist/commands/branch/index.d.ts.map +1 -0
- package/dist/commands/branch/index.js +511 -0
- package/dist/commands/guard/index.d.ts +67 -0
- package/dist/commands/guard/index.d.ts.map +1 -0
- package/dist/commands/guard/index.js +367 -0
- package/dist/commands/hooks/index.d.ts +18 -0
- package/dist/commands/hooks/index.d.ts.map +1 -0
- package/dist/commands/hooks/index.js +290 -0
- package/dist/commands/pr/index.d.ts +46 -0
- package/dist/commands/pr/index.d.ts.map +1 -0
- package/dist/commands/pr/index.js +854 -0
- package/dist/commands/shared/git-diff.d.ts +9 -0
- package/dist/commands/shared/git-diff.d.ts.map +1 -0
- package/dist/commands/shared/git-diff.js +41 -0
- package/dist/commands/shared/git-ops.d.ts +24 -0
- package/dist/commands/shared/git-ops.d.ts.map +1 -0
- package/dist/commands/shared/git-ops.js +181 -0
- package/dist/commands/shared/git-worktree.d.ts +8 -0
- package/dist/commands/shared/git-worktree.d.ts.map +1 -0
- package/dist/commands/shared/git-worktree.js +48 -0
- package/dist/commands/shared/git.d.ts +4 -0
- package/dist/commands/shared/git.d.ts.map +1 -0
- package/dist/commands/shared/git.js +14 -0
- package/dist/commands/shared/path.d.ts +3 -0
- package/dist/commands/shared/path.d.ts.map +1 -0
- package/dist/commands/shared/path.js +14 -0
- package/dist/commands/shared/pr-meta.d.ts +21 -0
- package/dist/commands/shared/pr-meta.d.ts.map +1 -0
- package/dist/commands/shared/pr-meta.js +72 -0
- package/dist/commands/shared/task-backend.d.ts +15 -0
- package/dist/commands/shared/task-backend.d.ts.map +1 -0
- package/dist/commands/shared/task-backend.js +55 -0
- package/dist/commands/task/add.d.ts +8 -0
- package/dist/commands/task/add.d.ts.map +1 -0
- package/dist/commands/task/add.js +164 -0
- package/dist/commands/task/block.d.ts +19 -0
- package/dist/commands/task/block.d.ts.map +1 -0
- package/dist/commands/task/block.js +86 -0
- package/dist/commands/task/comment.d.ts +8 -0
- package/dist/commands/task/comment.d.ts.map +1 -0
- package/dist/commands/task/comment.js +29 -0
- package/dist/commands/task/doc.d.ts +17 -0
- package/dist/commands/task/doc.d.ts.map +1 -0
- package/dist/commands/task/doc.js +220 -0
- package/dist/commands/task/export.d.ts +5 -0
- package/dist/commands/task/export.d.ts.map +1 -0
- package/dist/commands/task/export.js +27 -0
- package/dist/commands/task/finish.d.ts +27 -0
- package/dist/commands/task/finish.d.ts.map +1 -0
- package/dist/commands/task/finish.js +131 -0
- package/dist/commands/task/index.d.ts +23 -0
- package/dist/commands/task/index.d.ts.map +1 -0
- package/dist/commands/task/index.js +22 -0
- package/dist/commands/task/lint.d.ts +5 -0
- package/dist/commands/task/lint.d.ts.map +1 -0
- package/dist/commands/task/lint.js +22 -0
- package/dist/commands/task/list.d.ts +11 -0
- package/dist/commands/task/list.d.ts.map +1 -0
- package/dist/commands/task/list.js +54 -0
- package/dist/commands/task/migrate.d.ts +6 -0
- package/dist/commands/task/migrate.d.ts.map +1 -0
- package/dist/commands/task/migrate.js +70 -0
- package/dist/commands/task/new.d.ts +8 -0
- package/dist/commands/task/new.d.ts.map +1 -0
- package/dist/commands/task/new.js +117 -0
- package/dist/commands/task/next.d.ts +6 -0
- package/dist/commands/task/next.d.ts.map +1 -0
- package/dist/commands/task/next.js +45 -0
- package/dist/commands/task/normalize.d.ts +6 -0
- package/dist/commands/task/normalize.d.ts.map +1 -0
- package/dist/commands/task/normalize.js +46 -0
- package/dist/commands/task/ready.d.ts +6 -0
- package/dist/commands/task/ready.d.ts.map +1 -0
- package/dist/commands/task/ready.js +57 -0
- package/dist/commands/task/scaffold.d.ts +8 -0
- package/dist/commands/task/scaffold.d.ts.map +1 -0
- package/dist/commands/task/scaffold.js +131 -0
- package/dist/commands/task/scrub.d.ts +8 -0
- package/dist/commands/task/scrub.d.ts.map +1 -0
- package/dist/commands/task/scrub.js +121 -0
- package/dist/commands/task/search.d.ts +7 -0
- package/dist/commands/task/search.d.ts.map +1 -0
- package/dist/commands/task/search.js +79 -0
- package/dist/commands/task/set-status.d.ts +19 -0
- package/dist/commands/task/set-status.d.ts.map +1 -0
- package/dist/commands/task/set-status.js +123 -0
- package/dist/commands/task/shared.d.ts +46 -0
- package/dist/commands/task/shared.d.ts.map +1 -0
- package/dist/commands/task/shared.js +283 -0
- package/dist/commands/task/show.d.ts +6 -0
- package/dist/commands/task/show.d.ts.map +1 -0
- package/dist/commands/task/show.js +35 -0
- package/dist/commands/task/start.d.ts +19 -0
- package/dist/commands/task/start.d.ts.map +1 -0
- package/dist/commands/task/start.js +109 -0
- package/dist/commands/task/update.d.ts +8 -0
- package/dist/commands/task/update.d.ts.map +1 -0
- package/dist/commands/task/update.js +144 -0
- package/dist/commands/task/verify.d.ts +14 -0
- package/dist/commands/task/verify.d.ts.map +1 -0
- package/dist/commands/task/verify.js +362 -0
- package/dist/commands/workflow.d.ts +5 -364
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +6 -4617
- package/package.json +2 -2
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { loadTaskBackend } from "../../backends/task-backend.js";
|
|
2
|
+
import { mapBackendError } from "../../cli/error-map.js";
|
|
3
|
+
import { missingValueMessage, usageMessage } from "../../cli/output.js";
|
|
4
|
+
import { CliError } from "../../shared/errors.js";
|
|
5
|
+
import { dedupeStrings, normalizeDependsOnInput, normalizeTaskStatus, nowIso, requiresVerify, } from "./shared.js";
|
|
6
|
+
export const TASK_ADD_USAGE = "Usage: agentplane task add <task-id> [<task-id> ...] --title <text> --description <text> --priority <low|normal|med|high> --owner <id> --tag <tag> [--tag <tag>...]";
|
|
7
|
+
export const TASK_ADD_USAGE_EXAMPLE = 'agentplane task add 202602030608-F1Q8AB --title "..." --description "..." --priority med --owner CODER --tag cli';
|
|
8
|
+
function parseTaskAddFlags(args) {
|
|
9
|
+
const out = {
|
|
10
|
+
taskIds: [],
|
|
11
|
+
title: "",
|
|
12
|
+
description: "",
|
|
13
|
+
status: "TODO",
|
|
14
|
+
priority: "",
|
|
15
|
+
owner: "",
|
|
16
|
+
tags: [],
|
|
17
|
+
dependsOn: [],
|
|
18
|
+
verify: [],
|
|
19
|
+
};
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
const arg = args[i];
|
|
22
|
+
if (!arg)
|
|
23
|
+
continue;
|
|
24
|
+
if (!arg.startsWith("--")) {
|
|
25
|
+
out.taskIds.push(arg);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const next = args[i + 1];
|
|
29
|
+
if (arg === "--replace-tags" || arg === "--replace-depends-on" || arg === "--replace-verify") {
|
|
30
|
+
throw new CliError({
|
|
31
|
+
exitCode: 2,
|
|
32
|
+
code: "E_USAGE",
|
|
33
|
+
message: usageMessage(TASK_ADD_USAGE, TASK_ADD_USAGE_EXAMPLE),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (!next) {
|
|
37
|
+
throw new CliError({ exitCode: 2, code: "E_USAGE", message: missingValueMessage(arg) });
|
|
38
|
+
}
|
|
39
|
+
switch (arg) {
|
|
40
|
+
case "--title": {
|
|
41
|
+
out.title = next;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case "--description": {
|
|
45
|
+
out.description = next;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
case "--status": {
|
|
49
|
+
out.status = next;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case "--priority": {
|
|
53
|
+
out.priority = next;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
case "--owner": {
|
|
57
|
+
out.owner = next;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case "--tag": {
|
|
61
|
+
out.tags.push(next);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case "--depends-on": {
|
|
65
|
+
out.dependsOn.push(...normalizeDependsOnInput(next));
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "--verify": {
|
|
69
|
+
out.verify.push(next);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case "--comment-author": {
|
|
73
|
+
out.commentAuthor = next;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
case "--comment-body": {
|
|
77
|
+
out.commentBody = next;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
default: {
|
|
81
|
+
throw new CliError({ exitCode: 2, code: "E_USAGE", message: `Unknown flag: ${arg}` });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
export async function cmdTaskAdd(opts) {
|
|
89
|
+
const flags = parseTaskAddFlags(opts.args);
|
|
90
|
+
if (flags.taskIds.length === 0 ||
|
|
91
|
+
!flags.title ||
|
|
92
|
+
!flags.description ||
|
|
93
|
+
!flags.priority ||
|
|
94
|
+
!flags.owner ||
|
|
95
|
+
flags.tags.length === 0) {
|
|
96
|
+
throw new CliError({
|
|
97
|
+
exitCode: 2,
|
|
98
|
+
code: "E_USAGE",
|
|
99
|
+
message: usageMessage(TASK_ADD_USAGE, TASK_ADD_USAGE_EXAMPLE),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const { backend, config } = await loadTaskBackend({
|
|
104
|
+
cwd: opts.cwd,
|
|
105
|
+
rootOverride: opts.rootOverride ?? null,
|
|
106
|
+
});
|
|
107
|
+
const status = normalizeTaskStatus(flags.status);
|
|
108
|
+
const existing = await backend.listTasks();
|
|
109
|
+
const existingIds = new Set(existing.map((task) => task.id));
|
|
110
|
+
for (const taskId of flags.taskIds) {
|
|
111
|
+
if (existingIds.has(taskId)) {
|
|
112
|
+
throw new CliError({
|
|
113
|
+
exitCode: 2,
|
|
114
|
+
code: "E_USAGE",
|
|
115
|
+
message: `Task already exists: ${taskId}`,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const tags = dedupeStrings(flags.tags);
|
|
120
|
+
const dependsOn = dedupeStrings(flags.dependsOn);
|
|
121
|
+
const verify = dedupeStrings(flags.verify);
|
|
122
|
+
const docUpdatedBy = (flags.commentAuthor ?? "").trim() || flags.owner;
|
|
123
|
+
if (requiresVerify(tags, config.tasks.verify.required_tags) && verify.length === 0) {
|
|
124
|
+
throw new CliError({
|
|
125
|
+
exitCode: 2,
|
|
126
|
+
code: "E_USAGE",
|
|
127
|
+
message: "verify commands are required for tasks with code/backend/frontend tags",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const tasks = flags.taskIds.map((taskId) => ({
|
|
131
|
+
id: taskId,
|
|
132
|
+
title: flags.title,
|
|
133
|
+
description: flags.description,
|
|
134
|
+
status,
|
|
135
|
+
priority: flags.priority,
|
|
136
|
+
owner: flags.owner,
|
|
137
|
+
tags,
|
|
138
|
+
depends_on: dependsOn,
|
|
139
|
+
verify,
|
|
140
|
+
comments: flags.commentAuthor && flags.commentBody
|
|
141
|
+
? [{ author: flags.commentAuthor, body: flags.commentBody }]
|
|
142
|
+
: [],
|
|
143
|
+
doc_version: 2,
|
|
144
|
+
doc_updated_at: nowIso(),
|
|
145
|
+
doc_updated_by: docUpdatedBy,
|
|
146
|
+
id_source: "explicit",
|
|
147
|
+
}));
|
|
148
|
+
if (backend.writeTasks) {
|
|
149
|
+
await backend.writeTasks(tasks);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
for (const task of tasks) {
|
|
153
|
+
await backend.writeTask(task);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const task of tasks) {
|
|
157
|
+
process.stdout.write(`${task.id}\n`);
|
|
158
|
+
}
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
throw mapBackendError(err, { command: "task add", root: opts.rootOverride ?? null });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const BLOCK_USAGE = "Usage: agentplane block <task-id> --author <id> --body <text> [flags]";
|
|
2
|
+
export declare const BLOCK_USAGE_EXAMPLE = "agentplane block 202602030608-F1Q8AB --author CODER --body \"Blocked: ...\"";
|
|
3
|
+
export declare function cmdBlock(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=block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../src/commands/task/block.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,WAAW,0EAA0E,CAAC;AACnG,eAAO,MAAM,mBAAmB,gFAC6C,CAAC;AAE9E,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,CAqFlB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { loadConfig, resolveProject } from "@agentplaneorg/core";
|
|
2
|
+
import { mapBackendError } from "../../cli/error-map.js";
|
|
3
|
+
import { successMessage } from "../../cli/output.js";
|
|
4
|
+
import { formatCommentBodyForCommit } from "../../shared/comment-format.js";
|
|
5
|
+
import { CliError } from "../../shared/errors.js";
|
|
6
|
+
import { commitFromComment } from "../guard/index.js";
|
|
7
|
+
import { loadBackendTask } from "../shared/task-backend.js";
|
|
8
|
+
import { defaultCommitEmojiForStatus, enforceStatusCommitPolicy, isTransitionAllowed, nowIso, requireStructuredComment, } from "./shared.js";
|
|
9
|
+
export const BLOCK_USAGE = "Usage: agentplane block <task-id> --author <id> --body <text> [flags]";
|
|
10
|
+
export const BLOCK_USAGE_EXAMPLE = 'agentplane block 202602030608-F1Q8AB --author CODER --body "Blocked: ..."';
|
|
11
|
+
export async function cmdBlock(opts) {
|
|
12
|
+
try {
|
|
13
|
+
const resolved = await resolveProject({
|
|
14
|
+
cwd: opts.cwd,
|
|
15
|
+
rootOverride: opts.rootOverride ?? null,
|
|
16
|
+
});
|
|
17
|
+
const loaded = await loadConfig(resolved.agentplaneDir);
|
|
18
|
+
if (opts.commitFromComment) {
|
|
19
|
+
enforceStatusCommitPolicy({
|
|
20
|
+
policy: loaded.config.status_commit_policy,
|
|
21
|
+
action: "block",
|
|
22
|
+
confirmed: opts.confirmStatusCommit,
|
|
23
|
+
quiet: opts.quiet,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const { prefix, min_chars: minChars } = loaded.config.tasks.comments.blocked;
|
|
27
|
+
requireStructuredComment(opts.body, prefix, minChars);
|
|
28
|
+
const { backend, task } = await loadBackendTask({
|
|
29
|
+
cwd: opts.cwd,
|
|
30
|
+
rootOverride: opts.rootOverride,
|
|
31
|
+
taskId: opts.taskId,
|
|
32
|
+
});
|
|
33
|
+
const currentStatus = String(task.status || "TODO").toUpperCase();
|
|
34
|
+
if (!opts.force && !isTransitionAllowed(currentStatus, "BLOCKED")) {
|
|
35
|
+
throw new CliError({
|
|
36
|
+
exitCode: 2,
|
|
37
|
+
code: "E_USAGE",
|
|
38
|
+
message: `Refusing status transition ${currentStatus} -> BLOCKED (use --force to override)`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const formattedComment = opts.commitFromComment
|
|
42
|
+
? formatCommentBodyForCommit(opts.body, loaded.config)
|
|
43
|
+
: null;
|
|
44
|
+
const commentBody = formattedComment ?? opts.body;
|
|
45
|
+
const existingComments = Array.isArray(task.comments)
|
|
46
|
+
? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
|
|
47
|
+
: [];
|
|
48
|
+
const commentsValue = [...existingComments, { author: opts.author, body: commentBody }];
|
|
49
|
+
const nextTask = {
|
|
50
|
+
...task,
|
|
51
|
+
status: "BLOCKED",
|
|
52
|
+
comments: commentsValue,
|
|
53
|
+
doc_version: 2,
|
|
54
|
+
doc_updated_at: nowIso(),
|
|
55
|
+
doc_updated_by: opts.author,
|
|
56
|
+
};
|
|
57
|
+
await backend.writeTask(nextTask);
|
|
58
|
+
let commitInfo = null;
|
|
59
|
+
if (opts.commitFromComment) {
|
|
60
|
+
commitInfo = await commitFromComment({
|
|
61
|
+
cwd: opts.cwd,
|
|
62
|
+
rootOverride: opts.rootOverride,
|
|
63
|
+
taskId: opts.taskId,
|
|
64
|
+
commentBody: opts.body,
|
|
65
|
+
formattedComment,
|
|
66
|
+
emoji: opts.commitEmoji ?? defaultCommitEmojiForStatus("BLOCKED"),
|
|
67
|
+
allow: opts.commitAllow,
|
|
68
|
+
autoAllow: opts.commitAutoAllow || opts.commitAllow.length === 0,
|
|
69
|
+
allowTasks: opts.commitAllowTasks,
|
|
70
|
+
requireClean: opts.commitRequireClean,
|
|
71
|
+
quiet: opts.quiet,
|
|
72
|
+
config: loaded.config,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (!opts.quiet) {
|
|
76
|
+
const suffix = commitInfo ? ` (commit=${commitInfo.hash.slice(0, 12)})` : "";
|
|
77
|
+
process.stdout.write(`${successMessage("blocked", `${opts.taskId}${suffix}`)}\n`);
|
|
78
|
+
}
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
if (err instanceof CliError)
|
|
83
|
+
throw err;
|
|
84
|
+
throw mapBackendError(err, { command: "block", root: opts.rootOverride ?? null });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../../../src/commands/task/comment.ts"],"names":[],"mappings":"AAOA,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,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;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BlB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mapBackendError } from "../../cli/error-map.js";
|
|
2
|
+
import { successMessage } from "../../cli/output.js";
|
|
3
|
+
import { loadBackendTask } from "../shared/task-backend.js";
|
|
4
|
+
import { nowIso } from "./shared.js";
|
|
5
|
+
export async function cmdTaskComment(opts) {
|
|
6
|
+
try {
|
|
7
|
+
const { backend, task } = await loadBackendTask({
|
|
8
|
+
cwd: opts.cwd,
|
|
9
|
+
rootOverride: opts.rootOverride ?? null,
|
|
10
|
+
taskId: opts.taskId,
|
|
11
|
+
});
|
|
12
|
+
const existing = Array.isArray(task.comments)
|
|
13
|
+
? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
|
|
14
|
+
: [];
|
|
15
|
+
const next = {
|
|
16
|
+
...task,
|
|
17
|
+
comments: [...existing, { author: opts.author, body: opts.body }],
|
|
18
|
+
doc_version: 2,
|
|
19
|
+
doc_updated_at: nowIso(),
|
|
20
|
+
doc_updated_by: opts.author,
|
|
21
|
+
};
|
|
22
|
+
await backend.writeTask(next);
|
|
23
|
+
process.stdout.write(`${successMessage("commented", opts.taskId)}\n`);
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
throw mapBackendError(err, { command: "task comment", root: opts.rootOverride ?? null });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const TASK_DOC_SET_USAGE = "Usage: agentplane task doc set <task-id> --section <name> (--text <text> | --file <path>)";
|
|
2
|
+
export declare const TASK_DOC_SET_USAGE_EXAMPLE = "agentplane task doc set 202602030608-F1Q8AB --section Summary --text \"...\"";
|
|
3
|
+
export declare const TASK_DOC_SHOW_USAGE = "Usage: agentplane task doc show <task-id> [--section <name>] [--quiet]";
|
|
4
|
+
export declare const TASK_DOC_SHOW_USAGE_EXAMPLE = "agentplane task doc show 202602030608-F1Q8AB --section Summary";
|
|
5
|
+
export declare function cmdTaskDocSet(opts: {
|
|
6
|
+
cwd: string;
|
|
7
|
+
rootOverride?: string;
|
|
8
|
+
taskId: string;
|
|
9
|
+
args: string[];
|
|
10
|
+
}): Promise<number>;
|
|
11
|
+
export declare function cmdTaskDocShow(opts: {
|
|
12
|
+
cwd: string;
|
|
13
|
+
rootOverride?: string;
|
|
14
|
+
taskId: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
}): Promise<number>;
|
|
17
|
+
//# sourceMappingURL=doc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,kBAAkB,8FAC8D,CAAC;AAC9F,eAAO,MAAM,0BAA0B,iFACuC,CAAC;AAC/E,eAAO,MAAM,mBAAmB,2EAC0C,CAAC;AAC3E,eAAO,MAAM,2BAA2B,mEAC0B,CAAC;AAgFnE,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoGlB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyClB"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ensureDocSections, normalizeDocSectionName, parseDocSections, setMarkdownSection, } from "@agentplaneorg/core";
|
|
4
|
+
import { loadTaskBackend } from "../../backends/task-backend.js";
|
|
5
|
+
import { mapBackendError, mapCoreError } from "../../cli/error-map.js";
|
|
6
|
+
import { infoMessage, missingValueMessage, unknownEntityMessage, usageMessage, backendNotSupportedMessage, } from "../../cli/output.js";
|
|
7
|
+
import { CliError } from "../../shared/errors.js";
|
|
8
|
+
export const TASK_DOC_SET_USAGE = "Usage: agentplane task doc set <task-id> --section <name> (--text <text> | --file <path>)";
|
|
9
|
+
export const TASK_DOC_SET_USAGE_EXAMPLE = 'agentplane task doc set 202602030608-F1Q8AB --section Summary --text "..."';
|
|
10
|
+
export const TASK_DOC_SHOW_USAGE = "Usage: agentplane task doc show <task-id> [--section <name>] [--quiet]";
|
|
11
|
+
export const TASK_DOC_SHOW_USAGE_EXAMPLE = "agentplane task doc show 202602030608-F1Q8AB --section Summary";
|
|
12
|
+
function parseTaskDocShowFlags(args) {
|
|
13
|
+
const out = { quiet: false };
|
|
14
|
+
for (let i = 0; i < args.length; i++) {
|
|
15
|
+
const arg = args[i];
|
|
16
|
+
if (!arg)
|
|
17
|
+
continue;
|
|
18
|
+
if (arg === "--quiet") {
|
|
19
|
+
out.quiet = true;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (arg === "--section") {
|
|
23
|
+
const next = args[i + 1];
|
|
24
|
+
if (!next) {
|
|
25
|
+
throw new CliError({ exitCode: 2, code: "E_USAGE", message: missingValueMessage(arg) });
|
|
26
|
+
}
|
|
27
|
+
out.section = next;
|
|
28
|
+
i++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
throw new CliError({ exitCode: 2, code: "E_USAGE", message: `Unknown flag: ${arg}` });
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function parseTaskDocSetFlags(args) {
|
|
36
|
+
const out = {};
|
|
37
|
+
for (let i = 0; i < args.length; i++) {
|
|
38
|
+
const arg = args[i];
|
|
39
|
+
if (!arg)
|
|
40
|
+
continue;
|
|
41
|
+
if (!arg.startsWith("--")) {
|
|
42
|
+
throw new CliError({ exitCode: 2, code: "E_USAGE", message: `Unexpected argument: ${arg}` });
|
|
43
|
+
}
|
|
44
|
+
const next = args[i + 1];
|
|
45
|
+
if (!next) {
|
|
46
|
+
throw new CliError({ exitCode: 2, code: "E_USAGE", message: missingValueMessage(arg) });
|
|
47
|
+
}
|
|
48
|
+
switch (arg) {
|
|
49
|
+
case "--section": {
|
|
50
|
+
out.section = next;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case "--text": {
|
|
54
|
+
out.text = next;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
case "--file": {
|
|
58
|
+
out.file = next;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case "--updated-by": {
|
|
62
|
+
out.updatedBy = next;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
default: {
|
|
66
|
+
throw new CliError({ exitCode: 2, code: "E_USAGE", message: `Unknown flag: ${arg}` });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
i++;
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
export async function cmdTaskDocSet(opts) {
|
|
74
|
+
const flags = parseTaskDocSetFlags(opts.args);
|
|
75
|
+
if (!flags.section) {
|
|
76
|
+
throw new CliError({
|
|
77
|
+
exitCode: 2,
|
|
78
|
+
code: "E_USAGE",
|
|
79
|
+
message: usageMessage(TASK_DOC_SET_USAGE, TASK_DOC_SET_USAGE_EXAMPLE),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const hasText = flags.text !== undefined;
|
|
83
|
+
const hasFile = flags.file !== undefined;
|
|
84
|
+
if (hasText === hasFile) {
|
|
85
|
+
throw new CliError({
|
|
86
|
+
exitCode: 2,
|
|
87
|
+
code: "E_USAGE",
|
|
88
|
+
message: usageMessage(TASK_DOC_SET_USAGE, TASK_DOC_SET_USAGE_EXAMPLE),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
let updatedBy;
|
|
92
|
+
if (flags.updatedBy !== undefined) {
|
|
93
|
+
const trimmed = flags.updatedBy.trim();
|
|
94
|
+
if (trimmed.length === 0) {
|
|
95
|
+
throw new CliError({
|
|
96
|
+
exitCode: 2,
|
|
97
|
+
code: "E_USAGE",
|
|
98
|
+
message: "--updated-by must be non-empty",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
updatedBy = trimmed;
|
|
102
|
+
}
|
|
103
|
+
let text = flags.text ?? "";
|
|
104
|
+
if (hasFile) {
|
|
105
|
+
try {
|
|
106
|
+
text = await readFile(path.resolve(opts.cwd, flags.file ?? ""), "utf8");
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
throw mapCoreError(err, { command: "task doc set", filePath: flags.file ?? "" });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const { backend, resolved, config } = await loadTaskBackend({
|
|
114
|
+
cwd: opts.cwd,
|
|
115
|
+
rootOverride: opts.rootOverride ?? null,
|
|
116
|
+
});
|
|
117
|
+
if (!backend.getTaskDoc || !backend.setTaskDoc) {
|
|
118
|
+
throw new CliError({
|
|
119
|
+
exitCode: 2,
|
|
120
|
+
code: "E_USAGE",
|
|
121
|
+
message: backendNotSupportedMessage("task docs"),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
const allowed = config.tasks.doc.sections;
|
|
125
|
+
if (!allowed.includes(flags.section)) {
|
|
126
|
+
throw new CliError({
|
|
127
|
+
exitCode: 2,
|
|
128
|
+
code: "E_USAGE",
|
|
129
|
+
message: unknownEntityMessage("doc section", flags.section),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const normalizedAllowed = new Set(allowed.map((section) => normalizeDocSectionName(section)));
|
|
133
|
+
const targetKey = normalizeDocSectionName(flags.section);
|
|
134
|
+
const headingKeys = new Set();
|
|
135
|
+
for (const line of text.replaceAll("\r\n", "\n").split("\n")) {
|
|
136
|
+
const match = /^##\s+(.*)$/.exec(line.trim());
|
|
137
|
+
if (!match)
|
|
138
|
+
continue;
|
|
139
|
+
const key = normalizeDocSectionName(match[1] ?? "");
|
|
140
|
+
if (key && normalizedAllowed.has(key))
|
|
141
|
+
headingKeys.add(key);
|
|
142
|
+
}
|
|
143
|
+
const existing = await backend.getTaskDoc(opts.taskId);
|
|
144
|
+
const baseDoc = ensureDocSections(existing ?? "", config.tasks.doc.required_sections);
|
|
145
|
+
if (headingKeys.size > 0 && (headingKeys.size > 1 || !headingKeys.has(targetKey))) {
|
|
146
|
+
const fullDoc = ensureDocSections(text, config.tasks.doc.required_sections);
|
|
147
|
+
await backend.setTaskDoc(opts.taskId, fullDoc, updatedBy);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
let nextText = text;
|
|
151
|
+
if (headingKeys.size > 0 && headingKeys.has(targetKey)) {
|
|
152
|
+
const lines = nextText.replaceAll("\r\n", "\n").split("\n");
|
|
153
|
+
let firstContent = 0;
|
|
154
|
+
while (firstContent < lines.length && lines[firstContent]?.trim() === "")
|
|
155
|
+
firstContent++;
|
|
156
|
+
if ((lines[firstContent]?.trim() ?? "") === `## ${flags.section}`) {
|
|
157
|
+
lines.splice(firstContent, 1);
|
|
158
|
+
if (lines[firstContent]?.trim() === "")
|
|
159
|
+
lines.splice(firstContent, 1);
|
|
160
|
+
nextText = lines.join("\n");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const nextDoc = setMarkdownSection(baseDoc, flags.section, nextText);
|
|
164
|
+
const normalized = ensureDocSections(nextDoc, config.tasks.doc.required_sections);
|
|
165
|
+
await backend.setTaskDoc(opts.taskId, normalized, updatedBy);
|
|
166
|
+
}
|
|
167
|
+
const tasksDir = path.join(resolved.gitRoot, config.paths.workflow_dir);
|
|
168
|
+
process.stdout.write(`${path.join(tasksDir, opts.taskId, "README.md")}\n`);
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
if (err instanceof CliError)
|
|
173
|
+
throw err;
|
|
174
|
+
throw mapBackendError(err, { command: "task doc set", root: opts.rootOverride ?? null });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
export async function cmdTaskDocShow(opts) {
|
|
178
|
+
const flags = parseTaskDocShowFlags(opts.args);
|
|
179
|
+
try {
|
|
180
|
+
const { backend } = await loadTaskBackend({
|
|
181
|
+
cwd: opts.cwd,
|
|
182
|
+
rootOverride: opts.rootOverride ?? null,
|
|
183
|
+
});
|
|
184
|
+
if (!backend.getTaskDoc) {
|
|
185
|
+
throw new CliError({
|
|
186
|
+
exitCode: 2,
|
|
187
|
+
code: "E_USAGE",
|
|
188
|
+
message: backendNotSupportedMessage("task docs"),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const doc = (await backend.getTaskDoc(opts.taskId)) ?? "";
|
|
192
|
+
if (flags.section) {
|
|
193
|
+
const sectionKey = normalizeDocSectionName(flags.section);
|
|
194
|
+
const { sections } = parseDocSections(doc);
|
|
195
|
+
const entry = sections.get(sectionKey);
|
|
196
|
+
const content = entry?.lines ?? [];
|
|
197
|
+
if (content.length > 0) {
|
|
198
|
+
process.stdout.write(`${content.join("\n").trimEnd()}\n`);
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
if (!flags.quiet) {
|
|
202
|
+
process.stdout.write(`${infoMessage(`section has no content: ${flags.section}`)}\n`);
|
|
203
|
+
}
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
if (doc.trim()) {
|
|
207
|
+
process.stdout.write(`${doc.trimEnd()}\n`);
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
if (!flags.quiet) {
|
|
211
|
+
process.stdout.write(`${infoMessage("task doc metadata missing")}\n`);
|
|
212
|
+
}
|
|
213
|
+
return 0;
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
if (err instanceof CliError)
|
|
217
|
+
throw err;
|
|
218
|
+
throw mapBackendError(err, { command: "task doc show", root: opts.rootOverride ?? null });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/commands/task/export.ts"],"names":[],"mappings":"AAOA,wBAAsB,aAAa,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBjG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { loadTaskBackend } from "../../backends/task-backend.js";
|
|
3
|
+
import { mapBackendError } from "../../cli/error-map.js";
|
|
4
|
+
import { backendNotSupportedMessage } from "../../cli/output.js";
|
|
5
|
+
import { CliError } from "../../shared/errors.js";
|
|
6
|
+
export async function cmdTaskExport(opts) {
|
|
7
|
+
try {
|
|
8
|
+
const { backend, resolved, config } = await loadTaskBackend({
|
|
9
|
+
cwd: opts.cwd,
|
|
10
|
+
rootOverride: opts.rootOverride ?? null,
|
|
11
|
+
});
|
|
12
|
+
const outPath = path.join(resolved.gitRoot, config.paths.tasks_path);
|
|
13
|
+
if (!backend.exportTasksJson) {
|
|
14
|
+
throw new CliError({
|
|
15
|
+
exitCode: 3,
|
|
16
|
+
code: "E_VALIDATION",
|
|
17
|
+
message: backendNotSupportedMessage("exportTasksJson()"),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
await backend.exportTasksJson(outPath);
|
|
21
|
+
process.stdout.write(`${path.relative(resolved.gitRoot, outPath)}\n`);
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
throw mapBackendError(err, { command: "task export", root: opts.rootOverride ?? null });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const FINISH_USAGE = "Usage: agentplane finish <task-id> [<task-id>...] --author <id> --body <text> [flags]";
|
|
2
|
+
export declare const FINISH_USAGE_EXAMPLE = "agentplane finish 202602030608-F1Q8AB --author INTEGRATOR --body \"Verified: ...\"";
|
|
3
|
+
export declare function cmdFinish(opts: {
|
|
4
|
+
cwd: string;
|
|
5
|
+
rootOverride?: string;
|
|
6
|
+
taskIds: string[];
|
|
7
|
+
author: string;
|
|
8
|
+
body: string;
|
|
9
|
+
commit?: string;
|
|
10
|
+
skipVerify: boolean;
|
|
11
|
+
force: boolean;
|
|
12
|
+
noRequireTaskIdInCommit: boolean;
|
|
13
|
+
commitFromComment: boolean;
|
|
14
|
+
commitEmoji?: string;
|
|
15
|
+
commitAllow: string[];
|
|
16
|
+
commitAutoAllow: boolean;
|
|
17
|
+
commitAllowTasks: boolean;
|
|
18
|
+
commitRequireClean: boolean;
|
|
19
|
+
statusCommit: boolean;
|
|
20
|
+
statusCommitEmoji?: string;
|
|
21
|
+
statusCommitAllow: string[];
|
|
22
|
+
statusCommitAutoAllow: boolean;
|
|
23
|
+
statusCommitRequireClean: boolean;
|
|
24
|
+
confirmStatusCommit: boolean;
|
|
25
|
+
quiet: boolean;
|
|
26
|
+
}): Promise<number>;
|
|
27
|
+
//# sourceMappingURL=finish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../../../src/commands/task/finish.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,YAAY,0FACgE,CAAC;AAC1F,eAAO,MAAM,oBAAoB,uFACmD,CAAC;AAErF,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,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,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,uBAAuB,EAAE,OAAO,CAAC;IACjC,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,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkIlB"}
|