agentplane 0.3.4 → 0.3.6
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/README.md +103 -75
- package/assets/AGENTS.md +4 -2
- package/bin/dist-guard.js +13 -3
- package/bin/runtime-watch.d.ts +1 -0
- package/bin/runtime-watch.js +22 -5
- package/bin/stale-dist-policy.js +9 -2
- package/dist/.build-manifest.json +220 -790
- package/dist/adapters/task-backend/task-backend-adapter.d.ts +1 -1
- package/dist/adapters/task-backend/task-backend-adapter.d.ts.map +1 -1
- package/dist/adapters/task-backend/task-backend-adapter.js +5 -2
- package/dist/backends/task-backend/local-backend.d.ts +13 -0
- package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/local-backend.js +17 -0
- package/dist/backends/task-backend/redmine-backend.d.ts +18 -0
- package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine-backend.js +35 -25
- package/dist/backends/task-backend/shared/types.d.ts +20 -0
- package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
- package/dist/backends/task-backend/shared.d.ts +1 -1
- package/dist/backends/task-backend/shared.d.ts.map +1 -1
- package/dist/backends/task-backend.d.ts +1 -1
- package/dist/backends/task-backend.d.ts.map +1 -1
- package/dist/backends/task-backend.test-helpers.d.ts +4 -0
- package/dist/backends/task-backend.test-helpers.d.ts.map +1 -0
- package/dist/backends/task-backend.test-helpers.js +33 -0
- package/dist/cli/bootstrap-guide.d.ts.map +1 -1
- package/dist/cli/bootstrap-guide.js +1 -0
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +3 -2
- package/dist/cli/reason-codes.d.ts.map +1 -1
- package/dist/cli/reason-codes.js +30 -0
- package/dist/cli/run-cli/command-catalog/core.d.ts +3 -0
- package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/core.js +137 -0
- package/dist/cli/run-cli/command-catalog/lifecycle.d.ts +3 -0
- package/dist/cli/run-cli/command-catalog/lifecycle.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/lifecycle.js +52 -0
- package/dist/cli/run-cli/command-catalog/project.d.ts +3 -0
- package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/project.js +78 -0
- package/dist/cli/run-cli/command-catalog/shared.d.ts +19 -0
- package/dist/cli/run-cli/command-catalog/shared.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/shared.js +9 -0
- package/dist/cli/run-cli/command-catalog/task.d.ts +3 -0
- package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/task.js +85 -0
- package/dist/cli/run-cli/command-catalog.d.ts +3 -18
- package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog.js +8 -337
- package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/ide.js +64 -2
- package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/ui.js +33 -13
- package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts +3 -0
- package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts.map +1 -0
- package/dist/cli/run-cli.core.pr-flow.test-helpers.js +41 -0
- package/dist/cli/run-cli.core.tasks.test-helpers.d.ts +2 -0
- package/dist/cli/run-cli.core.tasks.test-helpers.d.ts.map +1 -0
- package/dist/cli/run-cli.core.tasks.test-helpers.js +6 -0
- package/dist/cli/run-cli.test-helpers.d.ts +3 -0
- package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
- package/dist/cli/run-cli.test-helpers.js +138 -6
- package/dist/commands/commit.spec.d.ts.map +1 -1
- package/dist/commands/commit.spec.js +2 -2
- package/dist/commands/doctor/runtime.d.ts.map +1 -1
- package/dist/commands/doctor/runtime.js +3 -6
- package/dist/commands/doctor/workspace.d.ts +4 -1
- package/dist/commands/doctor/workspace.d.ts.map +1 -1
- package/dist/commands/doctor/workspace.js +87 -4
- package/dist/commands/doctor.run.d.ts.map +1 -1
- package/dist/commands/doctor.run.js +8 -1
- package/dist/commands/guard/commit.command.js +1 -1
- package/dist/commands/guard/impl/allow.d.ts +5 -0
- package/dist/commands/guard/impl/allow.d.ts.map +1 -1
- package/dist/commands/guard/impl/allow.js +15 -10
- package/dist/commands/guard/impl/commands.d.ts.map +1 -1
- package/dist/commands/guard/impl/commands.js +137 -18
- package/dist/commands/guard/impl/comment-commit.d.ts.map +1 -1
- package/dist/commands/guard/impl/comment-commit.js +2 -0
- package/dist/commands/hooks/index.d.ts.map +1 -1
- package/dist/commands/hooks/index.js +8 -35
- package/dist/commands/recipes/impl/apply.d.ts +4 -0
- package/dist/commands/recipes/impl/apply.d.ts.map +1 -1
- package/dist/commands/recipes/impl/apply.js +34 -0
- package/dist/commands/recipes/impl/commands/explain.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/explain.js +70 -11
- package/dist/commands/recipes/impl/commands/info.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/info.js +24 -12
- package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/install.js +32 -36
- package/dist/commands/recipes/impl/commands/list.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/list.js +7 -4
- package/dist/commands/recipes/impl/commands/remove.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/remove.js +9 -11
- package/dist/commands/recipes/impl/constants.d.ts +2 -0
- package/dist/commands/recipes/impl/constants.d.ts.map +1 -1
- package/dist/commands/recipes/impl/constants.js +2 -0
- package/dist/commands/recipes/impl/manifest.d.ts.map +1 -1
- package/dist/commands/recipes/impl/manifest.js +219 -23
- package/dist/commands/recipes/impl/normalize.d.ts +3 -0
- package/dist/commands/recipes/impl/normalize.d.ts.map +1 -1
- package/dist/commands/recipes/impl/normalize.js +28 -24
- package/dist/commands/recipes/impl/paths.d.ts +9 -0
- package/dist/commands/recipes/impl/paths.d.ts.map +1 -1
- package/dist/commands/recipes/impl/paths.js +10 -1
- package/dist/commands/recipes/impl/project-installed-recipes.d.ts +7 -0
- package/dist/commands/recipes/impl/project-installed-recipes.d.ts.map +1 -0
- package/dist/commands/recipes/impl/project-installed-recipes.js +102 -0
- package/dist/commands/recipes/impl/resolver.d.ts +20 -0
- package/dist/commands/recipes/impl/resolver.d.ts.map +1 -0
- package/dist/commands/recipes/impl/resolver.js +220 -0
- package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
- package/dist/commands/recipes/impl/scenario.js +40 -11
- package/dist/commands/recipes/impl/types.d.ts +145 -16
- package/dist/commands/recipes/impl/types.d.ts.map +1 -1
- package/dist/commands/recipes/install.spec.d.ts.map +1 -1
- package/dist/commands/recipes/install.spec.js +3 -2
- package/dist/commands/recipes.d.ts +6 -4
- package/dist/commands/recipes.d.ts.map +1 -1
- package/dist/commands/recipes.js +5 -3
- package/dist/commands/recipes.test-helpers.d.ts +185 -0
- package/dist/commands/recipes.test-helpers.d.ts.map +1 -0
- package/dist/commands/recipes.test-helpers.js +339 -0
- package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
- package/dist/commands/scenario/impl/commands.js +192 -336
- package/dist/commands/scenario/info.command.d.ts.map +1 -1
- package/dist/commands/scenario/info.command.js +7 -2
- package/dist/commands/scenario/list.command.js +2 -2
- package/dist/commands/scenario/run.command.d.ts.map +1 -1
- package/dist/commands/scenario/run.command.js +7 -2
- package/dist/commands/shared/git-context.d.ts +1 -0
- package/dist/commands/shared/git-context.d.ts.map +1 -1
- package/dist/commands/shared/git-context.js +4 -0
- package/dist/commands/shared/reconcile-check.d.ts.map +1 -1
- package/dist/commands/shared/reconcile-check.js +77 -2
- package/dist/commands/shared/task-backend.d.ts +5 -0
- package/dist/commands/shared/task-backend.d.ts.map +1 -1
- package/dist/commands/shared/task-backend.js +24 -0
- package/dist/commands/shared/task-store.d.ts +32 -1
- package/dist/commands/shared/task-store.d.ts.map +1 -1
- package/dist/commands/shared/task-store.js +166 -42
- package/dist/commands/task/block.d.ts.map +1 -1
- package/dist/commands/task/block.js +46 -29
- package/dist/commands/task/close-duplicate.d.ts.map +1 -1
- package/dist/commands/task/close-duplicate.js +12 -37
- package/dist/commands/task/close-noop.d.ts.map +1 -1
- package/dist/commands/task/close-noop.js +12 -30
- package/dist/commands/task/close-shared.d.ts +14 -0
- package/dist/commands/task/close-shared.d.ts.map +1 -0
- package/dist/commands/task/close-shared.js +76 -0
- package/dist/commands/task/comment.d.ts.map +1 -1
- package/dist/commands/task/comment.js +35 -17
- package/dist/commands/task/doc-set.command.d.ts +2 -1
- package/dist/commands/task/doc-set.command.d.ts.map +1 -1
- package/dist/commands/task/doc-set.command.js +36 -4
- package/dist/commands/task/doc-template.d.ts.map +1 -1
- package/dist/commands/task/doc-template.js +2 -7
- package/dist/commands/task/doc.command.js +1 -1
- package/dist/commands/task/doc.d.ts +2 -1
- package/dist/commands/task/doc.d.ts.map +1 -1
- package/dist/commands/task/doc.js +123 -71
- package/dist/commands/task/export.d.ts.map +1 -1
- package/dist/commands/task/export.js +4 -4
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +141 -78
- package/dist/commands/task/migrate-doc.d.ts.map +1 -1
- package/dist/commands/task/migrate-doc.js +15 -11
- package/dist/commands/task/plan-set.command.js +1 -1
- package/dist/commands/task/plan.command.d.ts +8 -0
- package/dist/commands/task/plan.command.d.ts.map +1 -0
- package/dist/commands/task/plan.command.js +37 -0
- package/dist/commands/task/plan.d.ts.map +1 -1
- package/dist/commands/task/plan.js +190 -93
- package/dist/commands/task/set-status.command.d.ts.map +1 -1
- package/dist/commands/task/set-status.command.js +1 -1
- package/dist/commands/task/set-status.d.ts.map +1 -1
- package/dist/commands/task/set-status.js +40 -3
- package/dist/commands/task/shared/docs.d.ts +1 -0
- package/dist/commands/task/shared/docs.d.ts.map +1 -1
- package/dist/commands/task/shared/docs.js +7 -0
- package/dist/commands/task/shared/transitions.d.ts +0 -2
- package/dist/commands/task/shared/transitions.d.ts.map +1 -1
- package/dist/commands/task/shared/transitions.js +0 -6
- package/dist/commands/task/shared.d.ts +2 -2
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +2 -2
- package/dist/commands/task/start.d.ts.map +1 -1
- package/dist/commands/task/start.js +88 -63
- package/dist/commands/task/task.command.d.ts +8 -0
- package/dist/commands/task/task.command.d.ts.map +1 -0
- package/dist/commands/task/task.command.js +71 -0
- package/dist/commands/task/verify-command-shared.d.ts +16 -0
- package/dist/commands/task/verify-command-shared.d.ts.map +1 -0
- package/dist/commands/task/verify-command-shared.js +53 -0
- package/dist/commands/task/verify-ok.command.d.ts +2 -6
- package/dist/commands/task/verify-ok.command.d.ts.map +1 -1
- package/dist/commands/task/verify-ok.command.js +8 -50
- package/dist/commands/task/verify-record.d.ts.map +1 -1
- package/dist/commands/task/verify-record.js +119 -140
- package/dist/commands/task/verify-rework.command.d.ts +2 -6
- package/dist/commands/task/verify-rework.command.d.ts.map +1 -1
- package/dist/commands/task/verify-rework.command.js +8 -50
- package/dist/commands/verify.spec.d.ts.map +1 -1
- package/dist/commands/verify.spec.js +3 -12
- package/dist/policy/rules/allowlist.d.ts.map +1 -1
- package/dist/policy/rules/allowlist.js +13 -4
- package/dist/policy/rules/protected-paths.d.ts.map +1 -1
- package/dist/policy/rules/protected-paths.js +6 -1
- package/dist/ports/task-backend-port.d.ts +1 -1
- package/dist/ports/task-backend-port.d.ts.map +1 -1
- package/dist/shared/agent-emoji.d.ts.map +1 -1
- package/dist/shared/protected-paths.d.ts +7 -0
- package/dist/shared/protected-paths.d.ts.map +1 -1
- package/dist/shared/protected-paths.js +26 -10
- package/dist/shared/repo-cli-version.d.ts.map +1 -1
- package/dist/shared/repo-cli-version.js +9 -3
- package/package.json +2 -2
|
@@ -2,20 +2,20 @@ import path from "node:path";
|
|
|
2
2
|
import { mapBackendError } from "../../cli/error-map.js";
|
|
3
3
|
import { backendNotSupportedMessage } from "../../cli/output.js";
|
|
4
4
|
import { CliError } from "../../shared/errors.js";
|
|
5
|
-
import { loadCommandContext } from "../shared/task-backend.js";
|
|
5
|
+
import { exportTaskProjectionSnapshot, loadCommandContext, } from "../shared/task-backend.js";
|
|
6
6
|
export async function cmdTaskExport(opts) {
|
|
7
7
|
try {
|
|
8
8
|
const ctx = opts.ctx ??
|
|
9
9
|
(await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
|
|
10
10
|
const outPath = path.join(ctx.resolvedProject.gitRoot, ctx.config.paths.tasks_path);
|
|
11
|
-
if (!ctx.taskBackend.exportTasksJson) {
|
|
11
|
+
if (!ctx.taskBackend.exportProjectionSnapshot && !ctx.taskBackend.exportTasksJson) {
|
|
12
12
|
throw new CliError({
|
|
13
13
|
exitCode: 3,
|
|
14
14
|
code: "E_VALIDATION",
|
|
15
|
-
message: backendNotSupportedMessage("
|
|
15
|
+
message: backendNotSupportedMessage("exportProjectionSnapshot()"),
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
await ctx
|
|
18
|
+
await exportTaskProjectionSnapshot({ ctx, outputPath: outPath });
|
|
19
19
|
process.stdout.write(`${path.relative(ctx.resolvedProject.gitRoot, outPath)}\n`);
|
|
20
20
|
return 0;
|
|
21
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../../../src/commands/task/finish.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../../../src/commands/task/finish.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAwFnC,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,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgZlB"}
|
|
@@ -28,6 +28,43 @@ async function clearDirectWorkLockIfMatches(opts) {
|
|
|
28
28
|
// best-effort
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
function assertTaskCanFinish(opts) {
|
|
32
|
+
if (!opts.force && String(opts.task.status || "TODO").toUpperCase() === "DONE") {
|
|
33
|
+
throw new CliError({
|
|
34
|
+
exitCode: 2,
|
|
35
|
+
code: "E_USAGE",
|
|
36
|
+
message: `Task is already DONE: ${opts.task.id} (use --force to override)`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
ensureVerificationSatisfiedIfRequired(opts.task, opts.config);
|
|
40
|
+
const normalizedDoc = ensureDocSections(typeof opts.task.doc === "string" ? opts.task.doc : "", opts.config.tasks.doc.required_sections);
|
|
41
|
+
ensureAgentFilledRequiredDocSections({
|
|
42
|
+
task: opts.task,
|
|
43
|
+
config: opts.config,
|
|
44
|
+
doc: normalizedDoc,
|
|
45
|
+
action: "finish task",
|
|
46
|
+
});
|
|
47
|
+
if (!opts.isMetaTask)
|
|
48
|
+
return;
|
|
49
|
+
const tags = Array.isArray(opts.task.tags)
|
|
50
|
+
? opts.task.tags.filter((t) => typeof t === "string")
|
|
51
|
+
: [];
|
|
52
|
+
const isSpike = tags.includes("spike");
|
|
53
|
+
if (!isSpike && opts.taskCount === 1 && !opts.resultSummary) {
|
|
54
|
+
throw new CliError({
|
|
55
|
+
exitCode: 2,
|
|
56
|
+
code: "E_USAGE",
|
|
57
|
+
message: "Missing required --result for non-spike tasks.",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (opts.resultProvided && !opts.resultSummary) {
|
|
61
|
+
throw new CliError({
|
|
62
|
+
exitCode: 2,
|
|
63
|
+
code: "E_USAGE",
|
|
64
|
+
message: "Invalid value for --result: empty.",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
31
68
|
export async function cmdFinish(opts) {
|
|
32
69
|
try {
|
|
33
70
|
const ctx = opts.ctx ??
|
|
@@ -114,14 +151,16 @@ export async function cmdFinish(opts) {
|
|
|
114
151
|
: await readHeadCommit(gitRoot);
|
|
115
152
|
const useStore = backendIsLocalFileBackend(ctx);
|
|
116
153
|
const store = useStore ? getTaskStore(ctx) : null;
|
|
154
|
+
const backendWritesTaskReadmes = ctx.taskBackend.capabilities.writes_task_readmes === true;
|
|
117
155
|
const defaultDirectCloseCommit = ctx.config.workflow_mode === "direct" &&
|
|
118
|
-
|
|
156
|
+
backendWritesTaskReadmes &&
|
|
119
157
|
opts.taskIds.length === 1 &&
|
|
120
158
|
!opts.commitFromComment &&
|
|
121
159
|
!statusCommitRequested;
|
|
122
160
|
const shouldCloseCommit = opts.closeCommit === true || (defaultDirectCloseCommit && opts.noCloseCommit !== true);
|
|
123
161
|
const metaTaskId = opts.taskIds.length === 1 ? (opts.taskIds[0] ?? "") : "";
|
|
124
162
|
const wantMeta = typeof opts.result === "string" || typeof opts.risk === "string" || opts.breaking === true;
|
|
163
|
+
const resultProvided = typeof opts.result === "string";
|
|
125
164
|
if (wantMeta && opts.taskIds.length !== 1) {
|
|
126
165
|
throw new CliError({
|
|
127
166
|
exitCode: 2,
|
|
@@ -136,78 +175,87 @@ export async function cmdFinish(opts) {
|
|
|
136
175
|
let primaryTag = null;
|
|
137
176
|
for (const taskId of opts.taskIds) {
|
|
138
177
|
const task = useStore ? await store.get(taskId) : await loadTaskFromContext({ ctx, taskId });
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
178
|
+
assertTaskCanFinish({
|
|
179
|
+
task,
|
|
180
|
+
config: ctx.config,
|
|
181
|
+
taskCount: opts.taskIds.length,
|
|
182
|
+
isMetaTask: taskId === metaTaskId,
|
|
183
|
+
resultProvided,
|
|
184
|
+
resultSummary,
|
|
185
|
+
force: opts.force,
|
|
186
|
+
});
|
|
149
187
|
if (taskId === primaryTaskId &&
|
|
150
188
|
(opts.commitFromComment || statusCommitRequested) &&
|
|
151
189
|
primaryStatusFrom === null) {
|
|
152
190
|
primaryStatusFrom = String(task.status || "TODO").toUpperCase();
|
|
153
191
|
primaryTag = resolvePrimaryTag(toStringArray(task.tags), ctx).primary;
|
|
154
192
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
: [];
|
|
167
|
-
const isSpike = tags.includes("spike");
|
|
168
|
-
if (!isSpike && opts.taskIds.length === 1 && !resultSummary) {
|
|
169
|
-
throw new CliError({
|
|
170
|
-
exitCode: 2,
|
|
171
|
-
code: "E_USAGE",
|
|
172
|
-
message: "Missing required --result for non-spike tasks.",
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
if (typeof opts.result === "string" && !resultSummary) {
|
|
176
|
-
throw new CliError({
|
|
177
|
-
exitCode: 2,
|
|
178
|
-
code: "E_USAGE",
|
|
179
|
-
message: "Invalid value for --result: empty.",
|
|
193
|
+
const at = nowIso();
|
|
194
|
+
if (useStore) {
|
|
195
|
+
await store.patch(taskId, (current) => {
|
|
196
|
+
assertTaskCanFinish({
|
|
197
|
+
task: current,
|
|
198
|
+
config: ctx.config,
|
|
199
|
+
taskCount: opts.taskIds.length,
|
|
200
|
+
isMetaTask: taskId === metaTaskId,
|
|
201
|
+
resultProvided,
|
|
202
|
+
resultSummary,
|
|
203
|
+
force: opts.force,
|
|
180
204
|
});
|
|
181
|
-
|
|
205
|
+
const currentStatus = String(current.status || "TODO").toUpperCase();
|
|
206
|
+
return {
|
|
207
|
+
task: {
|
|
208
|
+
status: "DONE",
|
|
209
|
+
commit: { hash: commitInfo.hash, message: commitInfo.message },
|
|
210
|
+
...(taskId === metaTaskId && resultSummary ? { result_summary: resultSummary } : {}),
|
|
211
|
+
...(taskId === metaTaskId && riskLevel ? { risk_level: riskLevel } : {}),
|
|
212
|
+
...(taskId === metaTaskId && breaking ? { breaking: true } : {}),
|
|
213
|
+
},
|
|
214
|
+
appendComments: [{ author: opts.author, body: opts.body }],
|
|
215
|
+
appendEvents: [
|
|
216
|
+
{
|
|
217
|
+
type: "status",
|
|
218
|
+
at,
|
|
219
|
+
author: opts.author,
|
|
220
|
+
from: currentStatus,
|
|
221
|
+
to: "DONE",
|
|
222
|
+
note: opts.body,
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
docMeta: {
|
|
226
|
+
touch: true,
|
|
227
|
+
updatedBy: opts.author,
|
|
228
|
+
version: normalizeTaskDocVersion(current.doc_version),
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
const existingComments = Array.isArray(task.comments)
|
|
235
|
+
? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
|
|
236
|
+
: [];
|
|
237
|
+
const nextTask = {
|
|
238
|
+
...task,
|
|
239
|
+
status: "DONE",
|
|
240
|
+
commit: { hash: commitInfo.hash, message: commitInfo.message },
|
|
241
|
+
comments: [...existingComments, { author: opts.author, body: opts.body }],
|
|
242
|
+
events: appendTaskEvent(task, {
|
|
243
|
+
type: "status",
|
|
244
|
+
at,
|
|
245
|
+
author: opts.author,
|
|
246
|
+
from: String(task.status || "TODO").toUpperCase(),
|
|
247
|
+
to: "DONE",
|
|
248
|
+
note: opts.body,
|
|
249
|
+
}),
|
|
250
|
+
result_summary: taskId === metaTaskId && resultSummary ? resultSummary : task.result_summary,
|
|
251
|
+
risk_level: taskId === metaTaskId && riskLevel ? riskLevel : task.risk_level,
|
|
252
|
+
breaking: taskId === metaTaskId && breaking ? true : task.breaking,
|
|
253
|
+
doc_version: normalizeTaskDocVersion(task.doc_version),
|
|
254
|
+
doc_updated_at: at,
|
|
255
|
+
doc_updated_by: opts.author,
|
|
256
|
+
};
|
|
257
|
+
await ctx.taskBackend.writeTask(nextTask);
|
|
182
258
|
}
|
|
183
|
-
const existingComments = Array.isArray(task.comments)
|
|
184
|
-
? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
|
|
185
|
-
: [];
|
|
186
|
-
const commentsValue = [...existingComments, { author: opts.author, body: opts.body }];
|
|
187
|
-
const at = nowIso();
|
|
188
|
-
const nextTask = {
|
|
189
|
-
...task,
|
|
190
|
-
status: "DONE",
|
|
191
|
-
commit: { hash: commitInfo.hash, message: commitInfo.message },
|
|
192
|
-
comments: commentsValue,
|
|
193
|
-
events: appendTaskEvent(task, {
|
|
194
|
-
type: "status",
|
|
195
|
-
at,
|
|
196
|
-
author: opts.author,
|
|
197
|
-
from: String(task.status || "TODO").toUpperCase(),
|
|
198
|
-
to: "DONE",
|
|
199
|
-
note: opts.body,
|
|
200
|
-
}),
|
|
201
|
-
result_summary: taskId === metaTaskId && resultSummary ? resultSummary : task.result_summary,
|
|
202
|
-
risk_level: taskId === metaTaskId && riskLevel ? riskLevel : task.risk_level,
|
|
203
|
-
breaking: taskId === metaTaskId && breaking ? true : task.breaking,
|
|
204
|
-
doc_version: normalizeTaskDocVersion(task.doc_version),
|
|
205
|
-
doc_updated_at: at,
|
|
206
|
-
doc_updated_by: opts.author,
|
|
207
|
-
};
|
|
208
|
-
await (useStore
|
|
209
|
-
? store.update(taskId, () => nextTask)
|
|
210
|
-
: ctx.taskBackend.writeTask(nextTask));
|
|
211
259
|
}
|
|
212
260
|
if (opts.commitFromComment || statusCommitRequested) {
|
|
213
261
|
enforceStatusCommitPolicy({
|
|
@@ -232,6 +280,9 @@ export async function cmdFinish(opts) {
|
|
|
232
280
|
}
|
|
233
281
|
}
|
|
234
282
|
if (opts.commitFromComment) {
|
|
283
|
+
if (!opts.quiet) {
|
|
284
|
+
process.stdout.write(`${infoMessage("task marked DONE; creating commit from verification comment")}\n`);
|
|
285
|
+
}
|
|
235
286
|
if (typeof opts.commitEmoji === "string" && opts.commitEmoji.trim() !== "✅") {
|
|
236
287
|
throw new CliError({
|
|
237
288
|
exitCode: 2,
|
|
@@ -262,20 +313,29 @@ export async function cmdFinish(opts) {
|
|
|
262
313
|
// commitFromComment creates the git commit and returns the actual head hash/subject.
|
|
263
314
|
// Refresh task commit metadata to this hash and amend the same commit in local mode so
|
|
264
315
|
// "task done" metadata does not require a manual follow-up close commit.
|
|
265
|
-
const taskAfterCommit = useStore
|
|
266
|
-
? await store.get(primaryTaskId)
|
|
267
|
-
: await loadTaskFromContext({ ctx, taskId: primaryTaskId });
|
|
268
|
-
const updatedAfterCommit = {
|
|
269
|
-
...taskAfterCommit,
|
|
270
|
-
commit: { hash: committed.hash, message: committed.message },
|
|
271
|
-
doc_version: normalizeTaskDocVersion(taskAfterCommit.doc_version),
|
|
272
|
-
doc_updated_at: nowIso(),
|
|
273
|
-
doc_updated_by: opts.author,
|
|
274
|
-
};
|
|
275
316
|
await (useStore
|
|
276
|
-
? store.
|
|
277
|
-
|
|
278
|
-
|
|
317
|
+
? store.patch(primaryTaskId, (current) => ({
|
|
318
|
+
task: {
|
|
319
|
+
commit: { hash: committed.hash, message: committed.message },
|
|
320
|
+
},
|
|
321
|
+
docMeta: {
|
|
322
|
+
touch: true,
|
|
323
|
+
updatedBy: opts.author,
|
|
324
|
+
version: normalizeTaskDocVersion(current.doc_version),
|
|
325
|
+
},
|
|
326
|
+
}))
|
|
327
|
+
: (async () => {
|
|
328
|
+
const taskAfterCommit = await loadTaskFromContext({ ctx, taskId: primaryTaskId });
|
|
329
|
+
const updatedAfterCommit = {
|
|
330
|
+
...taskAfterCommit,
|
|
331
|
+
commit: { hash: committed.hash, message: committed.message },
|
|
332
|
+
doc_version: normalizeTaskDocVersion(taskAfterCommit.doc_version),
|
|
333
|
+
doc_updated_at: nowIso(),
|
|
334
|
+
doc_updated_by: opts.author,
|
|
335
|
+
};
|
|
336
|
+
await ctx.taskBackend.writeTask(updatedAfterCommit);
|
|
337
|
+
})());
|
|
338
|
+
if (backendWritesTaskReadmes) {
|
|
279
339
|
const workflowReadmeRelPath = path.join(ctx.config.paths.workflow_dir, primaryTaskId, "README.md");
|
|
280
340
|
await ctx.git.stage([workflowReadmeRelPath]);
|
|
281
341
|
const env = buildGitCommitEnv({
|
|
@@ -293,6 +353,9 @@ export async function cmdFinish(opts) {
|
|
|
293
353
|
}
|
|
294
354
|
}
|
|
295
355
|
if (statusCommitRequested) {
|
|
356
|
+
if (!opts.quiet) {
|
|
357
|
+
process.stdout.write(`${infoMessage("task marked DONE; creating status commit")}\n`);
|
|
358
|
+
}
|
|
296
359
|
if (typeof opts.statusCommitEmoji === "string" && opts.statusCommitEmoji.trim() !== "✅") {
|
|
297
360
|
throw new CliError({
|
|
298
361
|
exitCode: 2,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-doc.d.ts","sourceRoot":"","sources":["../../../src/commands/task/migrate-doc.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrate-doc.d.ts","sourceRoot":"","sources":["../../../src/commands/task/migrate-doc.ts"],"names":[],"mappings":"AA2RA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqDlB"}
|
|
@@ -6,11 +6,11 @@ import { exitCodeForError } from "../../cli/exit-codes.js";
|
|
|
6
6
|
import { fileExists, getPathKind } from "../../cli/fs-utils.js";
|
|
7
7
|
import { successMessage } from "../../cli/output.js";
|
|
8
8
|
import { CliError } from "../../shared/errors.js";
|
|
9
|
-
import {
|
|
9
|
+
import { exportTaskProjectionSnapshot, loadCommandContext } from "../shared/task-backend.js";
|
|
10
|
+
import { extractDocSection, extractTaskObservationSection, decodeEscapedTaskTextNewlines, normalizeTaskDocVersion, normalizeVerificationSectionLayout, } from "./shared/docs.js";
|
|
10
11
|
import { defaultTaskDocV3 } from "./doc-template.js";
|
|
11
12
|
const V3_CANONICAL_ORDER = [
|
|
12
13
|
"Summary",
|
|
13
|
-
"Context",
|
|
14
14
|
"Scope",
|
|
15
15
|
"Plan",
|
|
16
16
|
"Verify Steps",
|
|
@@ -61,13 +61,7 @@ function renderMarkdownSections(sections) {
|
|
|
61
61
|
function normalizeLiteralNewlinesInHumanSection(title, text) {
|
|
62
62
|
if (!HUMAN_TEXT_SECTIONS.has(normalizeSectionKey(title)))
|
|
63
63
|
return text.trimEnd();
|
|
64
|
-
|
|
65
|
-
const escapedDoubleNewline = next.includes(String.raw `\n\n`) || next.includes(String.raw `\r\n\r\n`);
|
|
66
|
-
const escapedNewlineMatches = next.match(/\\n/g) ?? [];
|
|
67
|
-
if (escapedDoubleNewline || escapedNewlineMatches.length >= 2) {
|
|
68
|
-
next = next.replaceAll(String.raw `\r\n`, "\n").replaceAll(String.raw `\n`, "\n");
|
|
69
|
-
}
|
|
70
|
-
return next.trimEnd();
|
|
64
|
+
return decodeEscapedTaskTextNewlines(text).trimEnd();
|
|
71
65
|
}
|
|
72
66
|
function firstSectionText(sections, title) {
|
|
73
67
|
const target = normalizeSectionKey(title);
|
|
@@ -98,8 +92,6 @@ function migrateDocToV3(opts) {
|
|
|
98
92
|
const currentText = firstSectionText(currentSections, title);
|
|
99
93
|
const defaultText = firstSectionText(defaultSections, title) ?? "";
|
|
100
94
|
let nextText = currentText ?? defaultText;
|
|
101
|
-
if (title === "Context" && !(currentText ?? "").trim())
|
|
102
|
-
continue;
|
|
103
95
|
if (title === "Verification") {
|
|
104
96
|
nextText = normalizeVerificationSectionLayout(currentText ?? defaultText, 3);
|
|
105
97
|
}
|
|
@@ -242,6 +234,12 @@ export async function cmdTaskMigrateDoc(opts) {
|
|
|
242
234
|
rootOverride: opts.rootOverride ?? null,
|
|
243
235
|
});
|
|
244
236
|
const loaded = await loadConfig(resolved.agentplaneDir);
|
|
237
|
+
const ctx = await loadCommandContext({
|
|
238
|
+
cwd: opts.cwd,
|
|
239
|
+
rootOverride: opts.rootOverride ?? null,
|
|
240
|
+
resolvedProject: resolved,
|
|
241
|
+
config: loaded.config,
|
|
242
|
+
});
|
|
245
243
|
const tasksDir = path.join(resolved.gitRoot, loaded.config.paths.workflow_dir);
|
|
246
244
|
const readmePaths = await resolveReadmePaths({ tasksDir, params });
|
|
247
245
|
if (!params.all) {
|
|
@@ -262,6 +260,12 @@ export async function cmdTaskMigrateDoc(opts) {
|
|
|
262
260
|
if (res.changed)
|
|
263
261
|
changed += 1;
|
|
264
262
|
}
|
|
263
|
+
// Refresh the local export snapshot so doctor and other snapshot-based checks
|
|
264
|
+
// immediately observe the migrated README contract without a separate task export.
|
|
265
|
+
if (ctx.taskBackend.exportProjectionSnapshot || ctx.taskBackend.exportTasksJson) {
|
|
266
|
+
const outPath = path.join(resolved.gitRoot, loaded.config.paths.tasks_path);
|
|
267
|
+
await exportTaskProjectionSnapshot({ ctx, outputPath: outPath });
|
|
268
|
+
}
|
|
265
269
|
if (!params.quiet) {
|
|
266
270
|
process.stdout.write(`${successMessage("migrated task docs", undefined, `changed=${changed}`)}\n`);
|
|
267
271
|
}
|
|
@@ -10,7 +10,7 @@ export const taskPlanSetSpec = {
|
|
|
10
10
|
kind: "string",
|
|
11
11
|
name: "text",
|
|
12
12
|
valueHint: "<text>",
|
|
13
|
-
description:
|
|
13
|
+
description: String.raw `Plan text to write into the task README Plan section. Literal escaped newlines (\n) are normalized for inline text.`,
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
kind: "string",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CommandHandler, CommandSpec } from "../../cli/spec/spec.js";
|
|
2
|
+
type TaskPlanGroupParsed = {
|
|
3
|
+
cmd: string[];
|
|
4
|
+
};
|
|
5
|
+
export declare const taskPlanSpec: CommandSpec<TaskPlanGroupParsed>;
|
|
6
|
+
export declare const runTaskPlan: CommandHandler<TaskPlanGroupParsed>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=plan.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/plan.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAItF,KAAK,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAI7C,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,mBAAmB,CAqBzD,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,cAAc,CAAC,mBAAmB,CAW3D,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { usageError } from "../../cli/spec/errors.js";
|
|
2
|
+
import { suggestOne } from "../../cli/spec/suggest.js";
|
|
3
|
+
const TASK_PLAN_SUBCOMMANDS = ["set", "approve", "reject"];
|
|
4
|
+
export const taskPlanSpec = {
|
|
5
|
+
id: ["task", "plan"],
|
|
6
|
+
group: "Task",
|
|
7
|
+
summary: "Task plan commands (set/approve/reject).",
|
|
8
|
+
synopsis: ["agentplane task plan <set|approve|reject> [args] [options]"],
|
|
9
|
+
args: [{ name: "cmd", required: false, variadic: true, valueHint: "<subcommand>" }],
|
|
10
|
+
examples: [
|
|
11
|
+
{
|
|
12
|
+
cmd: 'agentplane task plan set <task-id> --text "..." --updated-by ORCHESTRATOR',
|
|
13
|
+
why: "Write or replace the task plan.",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
cmd: "agentplane task plan approve <task-id> --by ORCHESTRATOR",
|
|
17
|
+
why: "Approve the current task plan.",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
cmd: 'agentplane task plan reject <task-id> --by ORCHESTRATOR --note "..."',
|
|
21
|
+
why: "Reject the current task plan with a note.",
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
parse: (raw) => ({ cmd: (raw.args.cmd ?? []) }),
|
|
25
|
+
};
|
|
26
|
+
export const runTaskPlan = (_ctx, p) => {
|
|
27
|
+
const input = p.cmd.join(" ");
|
|
28
|
+
const suggestion = suggestOne(input, [...TASK_PLAN_SUBCOMMANDS]);
|
|
29
|
+
const suffix = suggestion ? ` Did you mean: ${suggestion}?` : "";
|
|
30
|
+
const message = p.cmd.length === 0 ? "Missing subcommand." : `Unknown subcommand: ${p.cmd[0]}.`;
|
|
31
|
+
throw usageError({
|
|
32
|
+
spec: taskPlanSpec,
|
|
33
|
+
command: "task plan",
|
|
34
|
+
message: `${message}${suffix}`,
|
|
35
|
+
context: { command: "task plan" },
|
|
36
|
+
});
|
|
37
|
+
};
|
|
@@ -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;
|
|
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;AAkJnC,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,CA8HlB;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,CA2DlB;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,CAkElB"}
|