agentplane 0.3.2 → 0.3.4
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 +4 -4
- package/assets/agents/CODER.json +14 -10
- package/assets/agents/CREATOR.json +8 -6
- package/assets/agents/DOCS.json +9 -6
- package/assets/agents/INTEGRATOR.json +9 -6
- package/assets/agents/ORCHESTRATOR.json +8 -6
- package/assets/agents/PLANNER.json +8 -5
- package/assets/agents/REDMINE.json +6 -3
- package/assets/agents/REVIEWER.json +8 -6
- package/assets/agents/TESTER.json +8 -4
- package/assets/agents/UPDATER.json +6 -4
- package/assets/agents/UPGRADER.json +7 -6
- package/assets/policy/dod.code.md +2 -2
- package/assets/policy/dod.core.md +16 -2
- package/assets/policy/dod.docs.md +2 -2
- package/assets/policy/incidents.md +44 -1
- package/assets/policy/workflow.direct.md +8 -4
- package/bin/agentplane.js +59 -9
- package/bin/dist-guard.js +78 -10
- package/bin/runtime-context.d.ts +3 -0
- package/bin/runtime-context.js +13 -0
- package/bin/runtime-watch.d.ts +26 -0
- package/bin/runtime-watch.js +116 -0
- package/bin/stale-dist-policy.d.ts +6 -0
- package/bin/stale-dist-policy.js +44 -0
- package/dist/.build-manifest.json +2485 -5
- package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/local-backend.js +9 -12
- package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine-backend.js +23 -18
- package/dist/backends/task-backend/shared/constants.d.ts +1 -0
- package/dist/backends/task-backend/shared/constants.d.ts.map +1 -1
- package/dist/backends/task-backend/shared/constants.js +1 -0
- package/dist/backends/task-backend/shared/doc.d.ts +1 -0
- package/dist/backends/task-backend/shared/doc.d.ts.map +1 -1
- package/dist/backends/task-backend/shared/doc.js +4 -1
- package/dist/backends/task-backend/shared/export.js +3 -3
- package/dist/cli/bootstrap-guide.d.ts +2 -3
- package/dist/cli/bootstrap-guide.d.ts.map +1 -1
- package/dist/cli/bootstrap-guide.js +16 -35
- package/dist/cli/command-guide.d.ts +14 -1
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +71 -47
- package/dist/cli/run-cli/catalog.d.ts +7 -0
- package/dist/cli/run-cli/catalog.d.ts.map +1 -0
- package/dist/cli/run-cli/catalog.js +22 -0
- package/dist/cli/run-cli/command-catalog.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog.js +11 -0
- package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/core.js +37 -29
- package/dist/cli/run-cli/commands/init/write-config.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/write-config.js +2 -0
- package/dist/cli/run-cli/commands/init/write-workflow.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/write-workflow.js +6 -55
- package/dist/cli/run-cli/commands/init.js +5 -14
- package/dist/cli/run-cli/error-guidance.d.ts +9 -0
- package/dist/cli/run-cli/error-guidance.d.ts.map +1 -0
- package/dist/cli/run-cli/error-guidance.js +180 -0
- package/dist/cli/run-cli/globals.d.ts +22 -0
- package/dist/cli/run-cli/globals.d.ts.map +1 -0
- package/dist/cli/run-cli/globals.js +197 -0
- package/dist/cli/run-cli/update-warning.d.ts +6 -0
- package/dist/cli/run-cli/update-warning.d.ts.map +1 -0
- package/dist/cli/run-cli/update-warning.js +64 -0
- package/dist/cli/run-cli.d.ts.map +1 -1
- package/dist/cli/run-cli.js +5 -476
- package/dist/cli/spec/docs-render.d.ts.map +1 -1
- package/dist/cli/spec/docs-render.js +14 -1
- package/dist/commands/doctor/archive.d.ts +4 -0
- package/dist/commands/doctor/archive.d.ts.map +1 -0
- package/dist/commands/doctor/archive.js +211 -0
- package/dist/commands/doctor/fixes.d.ts +9 -0
- package/dist/commands/doctor/fixes.d.ts.map +1 -0
- package/dist/commands/doctor/fixes.js +40 -0
- package/dist/commands/doctor/layering.d.ts +2 -0
- package/dist/commands/doctor/layering.d.ts.map +1 -0
- package/dist/commands/doctor/layering.js +87 -0
- package/dist/commands/doctor/runtime.d.ts +4 -0
- package/dist/commands/doctor/runtime.d.ts.map +1 -0
- package/dist/commands/doctor/runtime.js +56 -0
- package/dist/commands/doctor/workflow.d.ts +6 -0
- package/dist/commands/doctor/workflow.d.ts.map +1 -0
- package/dist/commands/doctor/workflow.js +62 -0
- package/dist/commands/doctor/workspace.d.ts +2 -0
- package/dist/commands/doctor/workspace.d.ts.map +1 -0
- package/dist/commands/doctor/workspace.js +165 -0
- package/dist/commands/doctor.run.d.ts.map +1 -1
- package/dist/commands/doctor.run.js +16 -342
- package/dist/commands/doctor.spec.d.ts +1 -0
- package/dist/commands/doctor.spec.d.ts.map +1 -1
- package/dist/commands/doctor.spec.js +15 -1
- package/dist/commands/guard/impl/commands.d.ts.map +1 -1
- package/dist/commands/guard/impl/commands.js +19 -0
- package/dist/commands/release/apply.command.d.ts +2 -8
- package/dist/commands/release/apply.command.d.ts.map +1 -1
- package/dist/commands/release/apply.command.js +158 -387
- package/dist/commands/release/apply.mutation.d.ts +7 -0
- package/dist/commands/release/apply.mutation.d.ts.map +1 -0
- package/dist/commands/release/apply.mutation.js +107 -0
- package/dist/commands/release/apply.preflight.d.ts +25 -0
- package/dist/commands/release/apply.preflight.d.ts.map +1 -0
- package/dist/commands/release/apply.preflight.js +338 -0
- package/dist/commands/release/apply.reporting.d.ts +4 -0
- package/dist/commands/release/apply.reporting.d.ts.map +1 -0
- package/dist/commands/release/apply.reporting.js +24 -0
- package/dist/commands/release/apply.types.d.ts +46 -0
- package/dist/commands/release/apply.types.d.ts.map +1 -0
- package/dist/commands/release/apply.types.js +1 -0
- package/dist/commands/runtime.command.d.ts +28 -0
- package/dist/commands/runtime.command.d.ts.map +1 -0
- package/dist/commands/runtime.command.js +169 -0
- package/dist/commands/shared/task-store.d.ts.map +1 -1
- package/dist/commands/shared/task-store.js +7 -3
- package/dist/commands/task/add.d.ts.map +1 -1
- package/dist/commands/task/add.js +3 -33
- package/dist/commands/task/block.d.ts.map +1 -1
- package/dist/commands/task/block.js +2 -2
- package/dist/commands/task/close-duplicate.d.ts.map +1 -1
- package/dist/commands/task/close-duplicate.js +2 -2
- package/dist/commands/task/close-noop.d.ts.map +1 -1
- package/dist/commands/task/close-noop.js +2 -2
- package/dist/commands/task/comment.js +2 -2
- package/dist/commands/task/derive.d.ts.map +1 -1
- package/dist/commands/task/derive.js +3 -3
- package/dist/commands/task/doc-template.d.ts +10 -0
- package/dist/commands/task/doc-template.d.ts.map +1 -0
- package/dist/commands/task/doc-template.js +104 -0
- package/dist/commands/task/doc.d.ts.map +1 -1
- package/dist/commands/task/doc.js +36 -1
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +7 -4
- package/dist/commands/task/migrate-doc.command.d.ts.map +1 -1
- package/dist/commands/task/migrate-doc.command.js +5 -1
- package/dist/commands/task/migrate-doc.d.ts.map +1 -1
- package/dist/commands/task/migrate-doc.js +136 -2
- package/dist/commands/task/new.d.ts.map +1 -1
- package/dist/commands/task/new.js +4 -110
- package/dist/commands/task/new.spec.js +3 -3
- package/dist/commands/task/plan.d.ts.map +1 -1
- package/dist/commands/task/plan.js +5 -4
- package/dist/commands/task/scaffold.d.ts.map +1 -1
- package/dist/commands/task/scaffold.js +7 -52
- package/dist/commands/task/set-status.d.ts.map +1 -1
- package/dist/commands/task/set-status.js +2 -2
- package/dist/commands/task/shared/dependencies.d.ts +15 -0
- package/dist/commands/task/shared/dependencies.d.ts.map +1 -0
- package/dist/commands/task/shared/dependencies.js +143 -0
- package/dist/commands/task/shared/docs.d.ts +21 -0
- package/dist/commands/task/shared/docs.d.ts.map +1 -0
- package/dist/commands/task/shared/docs.js +121 -0
- package/dist/commands/task/shared/listing.d.ts +20 -0
- package/dist/commands/task/shared/listing.d.ts.map +1 -0
- package/dist/commands/task/shared/listing.js +127 -0
- package/dist/commands/task/shared/tags.d.ts +24 -0
- package/dist/commands/task/shared/tags.d.ts.map +1 -0
- package/dist/commands/task/shared/tags.js +177 -0
- package/dist/commands/task/shared/transitions.d.ts +42 -0
- package/dist/commands/task/shared/transitions.d.ts.map +1 -0
- package/dist/commands/task/shared/transitions.js +175 -0
- package/dist/commands/task/shared.d.ts +5 -106
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +5 -681
- package/dist/commands/task/start.d.ts.map +1 -1
- package/dist/commands/task/start.js +7 -5
- package/dist/commands/task/verify-record.d.ts.map +1 -1
- package/dist/commands/task/verify-record.js +9 -25
- package/dist/commands/task/verify-show.command.d.ts.map +1 -1
- package/dist/commands/task/verify-show.command.js +5 -1
- package/dist/commands/upgrade/apply.d.ts +44 -0
- package/dist/commands/upgrade/apply.d.ts.map +1 -0
- package/dist/commands/upgrade/apply.js +180 -0
- package/dist/commands/upgrade/report.d.ts +21 -0
- package/dist/commands/upgrade/report.d.ts.map +1 -0
- package/dist/commands/upgrade/report.js +81 -0
- package/dist/commands/upgrade/source.d.ts +35 -0
- package/dist/commands/upgrade/source.d.ts.map +1 -0
- package/dist/commands/upgrade/source.js +109 -0
- package/dist/commands/upgrade/types.d.ts +31 -0
- package/dist/commands/upgrade/types.d.ts.map +1 -0
- package/dist/commands/upgrade/types.js +1 -0
- package/dist/commands/upgrade.d.ts +1 -35
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +68 -332
- package/dist/commands/workflow-build.command.d.ts.map +1 -1
- package/dist/commands/workflow-build.command.js +9 -15
- package/dist/shared/diagnostics.d.ts +23 -0
- package/dist/shared/diagnostics.d.ts.map +1 -0
- package/dist/shared/diagnostics.js +57 -0
- package/dist/shared/errors.d.ts +2 -0
- package/dist/shared/errors.d.ts.map +1 -1
- package/dist/shared/errors.js +2 -0
- package/dist/shared/repo-cli-version.d.ts +13 -0
- package/dist/shared/repo-cli-version.d.ts.map +1 -0
- package/dist/shared/repo-cli-version.js +63 -0
- package/dist/shared/runtime-source.d.ts +33 -0
- package/dist/shared/runtime-source.d.ts.map +1 -0
- package/dist/shared/runtime-source.js +156 -0
- package/dist/shared/version-compare.d.ts +7 -0
- package/dist/shared/version-compare.d.ts.map +1 -0
- package/dist/shared/version-compare.js +30 -0
- package/dist/shared/workflow-artifacts.d.ts +37 -0
- package/dist/shared/workflow-artifacts.d.ts.map +1 -0
- package/dist/shared/workflow-artifacts.js +97 -0
- package/package.json +2 -2
|
@@ -1,682 +1,6 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
|
-
import { promisify } from "node:util";
|
|
3
|
-
import { readdir } from "node:fs/promises";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { resolveCommitEmojiForAgent } from "../../shared/agent-emoji.js";
|
|
6
|
-
import { invalidValueForFlag, invalidValueMessage, missingValueMessage, warnMessage, } from "../../cli/output.js";
|
|
7
|
-
import { fileExists } from "../../cli/fs-utils.js";
|
|
8
|
-
import { exitCodeForError } from "../../cli/exit-codes.js";
|
|
9
|
-
import { CliError } from "../../shared/errors.js";
|
|
10
|
-
import { dedupeStrings } from "../../shared/strings.js";
|
|
11
|
-
import { parseGitLogHashSubject } from "../../shared/git-log.js";
|
|
12
|
-
import { isRecord } from "../../shared/guards.js";
|
|
13
1
|
export { dedupeStrings } from "../../shared/strings.js";
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return [];
|
|
20
|
-
const entries = await readdir(agentsDir);
|
|
21
|
-
return entries
|
|
22
|
-
.filter((name) => name.endsWith(".json"))
|
|
23
|
-
.map((name) => name.slice(0, -".json".length))
|
|
24
|
-
.map((id) => id.trim())
|
|
25
|
-
.filter((id) => id.length > 0);
|
|
26
|
-
})();
|
|
27
|
-
return await ctx.memo.agentIds;
|
|
28
|
-
}
|
|
29
|
-
export function nowIso() {
|
|
30
|
-
return new Date().toISOString();
|
|
31
|
-
}
|
|
32
|
-
export const VERIFY_STEPS_PLACEHOLDER = "<!-- TODO: FILL VERIFY STEPS -->";
|
|
33
|
-
export function extractDocSection(doc, sectionName) {
|
|
34
|
-
const lines = doc.replaceAll("\r\n", "\n").split("\n");
|
|
35
|
-
let capturing = false;
|
|
36
|
-
const out = [];
|
|
37
|
-
for (const line of lines) {
|
|
38
|
-
const match = /^##\s+(.*)$/.exec(line.trim());
|
|
39
|
-
if (match) {
|
|
40
|
-
if (capturing)
|
|
41
|
-
break;
|
|
42
|
-
capturing = (match[1] ?? "").trim() === sectionName;
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
if (capturing)
|
|
46
|
-
out.push(line);
|
|
47
|
-
}
|
|
48
|
-
if (!capturing)
|
|
49
|
-
return null;
|
|
50
|
-
return out.join("\n").trimEnd();
|
|
51
|
-
}
|
|
52
|
-
export function isVerifyStepsFilled(sectionText) {
|
|
53
|
-
const normalized = (sectionText ?? "").trim();
|
|
54
|
-
if (!normalized)
|
|
55
|
-
return false;
|
|
56
|
-
if (normalized.includes(VERIFY_STEPS_PLACEHOLDER))
|
|
57
|
-
return false;
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
const DOC_PLACEHOLDER_RE = /<!--\s*TODO\b/i;
|
|
61
|
-
const DOC_SECTIONS_AUTO_MANAGED = new Set(["verification"]);
|
|
62
|
-
const DOC_SECTIONS_CONDITIONAL = new Set(["verify steps", "notes"]);
|
|
63
|
-
export function isDocSectionFilled(sectionText) {
|
|
64
|
-
const normalized = (sectionText ?? "").trim();
|
|
65
|
-
if (!normalized)
|
|
66
|
-
return false;
|
|
67
|
-
if (DOC_PLACEHOLDER_RE.test(normalized))
|
|
68
|
-
return false;
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
export function ensureAgentFilledRequiredDocSections(opts) {
|
|
72
|
-
const required = dedupeStrings((opts.config.tasks.doc.required_sections ?? [])
|
|
73
|
-
.map((section) => String(section ?? "").trim())
|
|
74
|
-
.filter(Boolean));
|
|
75
|
-
const missing = [];
|
|
76
|
-
for (const section of required) {
|
|
77
|
-
const normalizedSection = section.trim().toLowerCase();
|
|
78
|
-
if (DOC_SECTIONS_AUTO_MANAGED.has(normalizedSection))
|
|
79
|
-
continue;
|
|
80
|
-
if (DOC_SECTIONS_CONDITIONAL.has(normalizedSection))
|
|
81
|
-
continue;
|
|
82
|
-
const sectionText = extractDocSection(opts.doc, section);
|
|
83
|
-
if (!isDocSectionFilled(sectionText)) {
|
|
84
|
-
missing.push(section);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (missing.length === 0)
|
|
88
|
-
return;
|
|
89
|
-
const sectionList = missing.map((section) => `## ${section}`).join(", ");
|
|
90
|
-
throw new CliError({
|
|
91
|
-
exitCode: 3,
|
|
92
|
-
code: "E_VALIDATION",
|
|
93
|
-
message: `${opts.task.id}: cannot ${opts.action}: required task doc sections are missing/empty: ${sectionList} ` +
|
|
94
|
-
`(fill via \`agentplane task doc set ${opts.task.id} --section <name> --text "..."\`)`,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
export function normalizeDependsOnInput(value) {
|
|
98
|
-
const trimmed = value.trim();
|
|
99
|
-
if (!trimmed || trimmed === "[]")
|
|
100
|
-
return [];
|
|
101
|
-
return [trimmed];
|
|
102
|
-
}
|
|
103
|
-
const ALLOWED_TASK_STATUSES = new Set(["TODO", "DOING", "DONE", "BLOCKED"]);
|
|
104
|
-
export function normalizeTaskStatus(value) {
|
|
105
|
-
const normalized = value.trim().toUpperCase();
|
|
106
|
-
if (!ALLOWED_TASK_STATUSES.has(normalized)) {
|
|
107
|
-
throw new CliError({
|
|
108
|
-
exitCode: 2,
|
|
109
|
-
code: "E_USAGE",
|
|
110
|
-
message: invalidValueMessage("status", value, `one of ${[...ALLOWED_TASK_STATUSES].join(", ")}`),
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
return normalized;
|
|
114
|
-
}
|
|
115
|
-
export function toStringArray(value) {
|
|
116
|
-
if (!Array.isArray(value))
|
|
117
|
-
return [];
|
|
118
|
-
return value
|
|
119
|
-
.filter((item) => typeof item === "string")
|
|
120
|
-
.map((item) => item.trim());
|
|
121
|
-
}
|
|
122
|
-
export function requiresVerify(tags, requiredTags) {
|
|
123
|
-
const required = new Set(requiredTags.map((tag) => tag.trim().toLowerCase()).filter(Boolean));
|
|
124
|
-
if (required.size === 0)
|
|
125
|
-
return false;
|
|
126
|
-
return tags.some((tag) => required.has(tag.trim().toLowerCase()));
|
|
127
|
-
}
|
|
128
|
-
function readStringArray(value) {
|
|
129
|
-
if (!Array.isArray(value))
|
|
130
|
-
return [];
|
|
131
|
-
return value
|
|
132
|
-
.filter((item) => typeof item === "string")
|
|
133
|
-
.map((item) => item.trim())
|
|
134
|
-
.filter((item) => item.length > 0);
|
|
135
|
-
}
|
|
136
|
-
function readBoolean(value, fallback) {
|
|
137
|
-
return typeof value === "boolean" ? value : fallback;
|
|
138
|
-
}
|
|
139
|
-
function readString(value, fallback) {
|
|
140
|
-
if (typeof value !== "string")
|
|
141
|
-
return fallback;
|
|
142
|
-
const trimmed = value.trim();
|
|
143
|
-
return trimmed.length > 0 ? trimmed : fallback;
|
|
144
|
-
}
|
|
145
|
-
function configFromInput(input) {
|
|
146
|
-
return "config" in input ? input.config : input;
|
|
147
|
-
}
|
|
148
|
-
export function readTaskTagPolicy(input) {
|
|
149
|
-
const config = configFromInput(input);
|
|
150
|
-
const tasks = isRecord(config.tasks) ? config.tasks : {};
|
|
151
|
-
const rawTagsCandidate = tasks.tags;
|
|
152
|
-
const rawTags = isRecord(rawTagsCandidate) ? rawTagsCandidate : {};
|
|
153
|
-
const fallbackAllowlist = ["code", "data", "research", "docs", "ops", "product", "meta"];
|
|
154
|
-
const normalizedAllowlist = dedupeStrings(readStringArray(rawTags.primary_allowlist)
|
|
155
|
-
.map((tag) => tag.toLowerCase())
|
|
156
|
-
.filter(Boolean));
|
|
157
|
-
return {
|
|
158
|
-
primaryAllowlist: normalizedAllowlist.length > 0 ? normalizedAllowlist : fallbackAllowlist,
|
|
159
|
-
strictPrimary: readBoolean(rawTags.strict_primary, false),
|
|
160
|
-
fallbackPrimary: readString(rawTags.fallback_primary, "meta").toLowerCase(),
|
|
161
|
-
lockPrimaryOnUpdate: readBoolean(rawTags.lock_primary_on_update, true),
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
function readVerifyPrimaryPolicy(config) {
|
|
165
|
-
const tasks = isRecord(config.tasks) ? config.tasks : {};
|
|
166
|
-
const rawVerifyCandidate = tasks.verify;
|
|
167
|
-
const rawVerify = isRecord(rawVerifyCandidate)
|
|
168
|
-
? rawVerifyCandidate
|
|
169
|
-
: {};
|
|
170
|
-
const explicitSteps = dedupeStrings(readStringArray(rawVerify.require_steps_for_primary)
|
|
171
|
-
.map((tag) => tag.toLowerCase())
|
|
172
|
-
.filter(Boolean));
|
|
173
|
-
const legacySteps = dedupeStrings(readStringArray(rawVerify.require_steps_for_tags ?? rawVerify.required_tags)
|
|
174
|
-
.map((tag) => tag.toLowerCase())
|
|
175
|
-
.filter(Boolean));
|
|
176
|
-
const requireStepsForPrimary = new Set(explicitSteps.length > 0 ? explicitSteps : legacySteps);
|
|
177
|
-
const explicitVerification = dedupeStrings(readStringArray(rawVerify.require_verification_for_primary)
|
|
178
|
-
.map((tag) => tag.toLowerCase())
|
|
179
|
-
.filter(Boolean));
|
|
180
|
-
const requireVerificationForPrimary = new Set(explicitVerification.length > 0 ? explicitVerification : [...requireStepsForPrimary.values()]);
|
|
181
|
-
return { requireStepsForPrimary, requireVerificationForPrimary };
|
|
182
|
-
}
|
|
183
|
-
export function resolvePrimaryTagFromConfig(tags, config) {
|
|
184
|
-
const policy = readTaskTagPolicy(config);
|
|
185
|
-
const allowlist = policy.primaryAllowlist;
|
|
186
|
-
if (allowlist.length === 0) {
|
|
187
|
-
throw new CliError({
|
|
188
|
-
exitCode: 3,
|
|
189
|
-
code: "E_VALIDATION",
|
|
190
|
-
message: "tasks.tags.primary_allowlist must contain at least one tag.",
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
const normalizedTags = dedupeStrings(tags.map((t) => t.trim().toLowerCase()).filter(Boolean));
|
|
194
|
-
const matched = normalizedTags.filter((tag) => allowlist.includes(tag));
|
|
195
|
-
if (matched.length > 1) {
|
|
196
|
-
throw new CliError({
|
|
197
|
-
exitCode: exitCodeForError("E_USAGE"),
|
|
198
|
-
code: "E_USAGE",
|
|
199
|
-
message: `Task must include exactly one primary tag from allowlist (${allowlist.join(", ")}); ` +
|
|
200
|
-
`found multiple: ${matched.join(", ")}`,
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
if (matched.length === 1) {
|
|
204
|
-
return { primary: matched[0], matched, usedFallback: false };
|
|
205
|
-
}
|
|
206
|
-
const strict = policy.strictPrimary;
|
|
207
|
-
if (strict) {
|
|
208
|
-
throw new CliError({
|
|
209
|
-
exitCode: exitCodeForError("E_USAGE"),
|
|
210
|
-
code: "E_USAGE",
|
|
211
|
-
message: `Task must include exactly one primary tag from allowlist (${allowlist.join(", ")}); ` +
|
|
212
|
-
"none found and strict_primary=true",
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
const fallback = policy.fallbackPrimary;
|
|
216
|
-
if (!fallback || !allowlist.includes(fallback)) {
|
|
217
|
-
throw new CliError({
|
|
218
|
-
exitCode: 3,
|
|
219
|
-
code: "E_VALIDATION",
|
|
220
|
-
message: `tasks.tags.fallback_primary=${JSON.stringify(policy.fallbackPrimary)} ` +
|
|
221
|
-
`must be present in tasks.tags.primary_allowlist (${allowlist.join(", ")}).`,
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
return { primary: fallback, matched, usedFallback: true };
|
|
225
|
-
}
|
|
226
|
-
export function requiresVerifyStepsByPrimary(tags, config) {
|
|
227
|
-
const primary = resolvePrimaryTagFromConfig(tags, config).primary;
|
|
228
|
-
return readVerifyPrimaryPolicy(config).requireStepsForPrimary.has(primary);
|
|
229
|
-
}
|
|
230
|
-
export function requiresVerificationByPrimary(tags, config) {
|
|
231
|
-
const primary = resolvePrimaryTagFromConfig(tags, config).primary;
|
|
232
|
-
return readVerifyPrimaryPolicy(config).requireVerificationForPrimary.has(primary);
|
|
233
|
-
}
|
|
234
|
-
export function resolvePrimaryTag(tags, ctx) {
|
|
235
|
-
return resolvePrimaryTagFromConfig(tags, ctx.config);
|
|
236
|
-
}
|
|
237
|
-
export async function warnIfUnknownOwner(ctx, owner) {
|
|
238
|
-
const trimmed = owner.trim();
|
|
239
|
-
if (!trimmed)
|
|
240
|
-
return;
|
|
241
|
-
const ids = await listAgentIdsMemo(ctx);
|
|
242
|
-
if (ids.length === 0)
|
|
243
|
-
return;
|
|
244
|
-
if (ids.includes(trimmed))
|
|
245
|
-
return;
|
|
246
|
-
throw new CliError({
|
|
247
|
-
exitCode: 3,
|
|
248
|
-
code: "E_VALIDATION",
|
|
249
|
-
message: `unknown task owner id: ${trimmed} (not found under ${ctx.config.paths.agents_dir}; ` +
|
|
250
|
-
`pick an existing agent id or create ${ctx.config.paths.agents_dir}/${trimmed}.json)`,
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
export function appendTaskEvent(task, event) {
|
|
254
|
-
const existing = Array.isArray(task.events)
|
|
255
|
-
? task.events.filter((entry) => !!entry &&
|
|
256
|
-
typeof entry.type === "string" &&
|
|
257
|
-
typeof entry.at === "string" &&
|
|
258
|
-
typeof entry.author === "string")
|
|
259
|
-
: [];
|
|
260
|
-
return [...existing, event];
|
|
261
|
-
}
|
|
262
|
-
export function ensurePlanApprovedIfRequired(task, config) {
|
|
263
|
-
if (config.agents?.approvals?.require_plan !== true)
|
|
264
|
-
return;
|
|
265
|
-
const state = task.plan_approval?.state ?? "missing";
|
|
266
|
-
if (state === "approved")
|
|
267
|
-
return;
|
|
268
|
-
throw new CliError({
|
|
269
|
-
exitCode: 3,
|
|
270
|
-
code: "E_VALIDATION",
|
|
271
|
-
message: `${task.id}: plan approval is required before work can proceed ` +
|
|
272
|
-
`(plan_approval.state=${JSON.stringify(state)}; use \`agentplane task plan approve ${task.id} --by <USER>\` ` +
|
|
273
|
-
"or set agents.approvals.require_plan=false).",
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
export function ensureVerificationSatisfiedIfRequired(task, config) {
|
|
277
|
-
if (config.agents?.approvals?.require_verify !== true)
|
|
278
|
-
return;
|
|
279
|
-
if (!requiresVerificationByPrimary(toStringArray(task.tags), config))
|
|
280
|
-
return;
|
|
281
|
-
const state = task.verification?.state ?? "missing";
|
|
282
|
-
if (state === "ok")
|
|
283
|
-
return;
|
|
284
|
-
const hint = `use \`agentplane verify ${task.id} --ok|--rework --by <ID> --note <TEXT>\` ` +
|
|
285
|
-
`or \`agentplane task verify ok|rework ${task.id} --by <ID> --note <TEXT>\``;
|
|
286
|
-
throw new CliError({
|
|
287
|
-
exitCode: 3,
|
|
288
|
-
code: "E_VALIDATION",
|
|
289
|
-
message: `${task.id}: verification result is required before integration/closure can proceed ` +
|
|
290
|
-
`(verification.state=${JSON.stringify(state)}; ${hint} or set agents.approvals.require_verify=false).`,
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
function hasDependsOnCycle(dependsOnMap) {
|
|
294
|
-
const visiting = new Set();
|
|
295
|
-
const visited = new Set();
|
|
296
|
-
const stack = [];
|
|
297
|
-
function dfs(taskId) {
|
|
298
|
-
if (visited.has(taskId))
|
|
299
|
-
return null;
|
|
300
|
-
if (visiting.has(taskId)) {
|
|
301
|
-
const start = stack.indexOf(taskId);
|
|
302
|
-
return start === -1 ? [taskId] : [...stack.slice(start), taskId];
|
|
303
|
-
}
|
|
304
|
-
visiting.add(taskId);
|
|
305
|
-
stack.push(taskId);
|
|
306
|
-
const deps = dependsOnMap.get(taskId) ?? [];
|
|
307
|
-
for (const depId of deps) {
|
|
308
|
-
const cycle = dfs(depId);
|
|
309
|
-
if (cycle)
|
|
310
|
-
return cycle;
|
|
311
|
-
}
|
|
312
|
-
stack.pop();
|
|
313
|
-
visiting.delete(taskId);
|
|
314
|
-
visited.add(taskId);
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
|
-
for (const taskId of dependsOnMap.keys()) {
|
|
318
|
-
const cycle = dfs(taskId);
|
|
319
|
-
if (cycle)
|
|
320
|
-
return cycle;
|
|
321
|
-
}
|
|
322
|
-
return null;
|
|
323
|
-
}
|
|
324
|
-
export async function ensureTaskDependsOnGraphIsAcyclic(opts) {
|
|
325
|
-
const nextDepends = dedupeStrings(opts.dependsOn);
|
|
326
|
-
if (nextDepends.includes(opts.taskId)) {
|
|
327
|
-
throw new CliError({
|
|
328
|
-
exitCode: 2,
|
|
329
|
-
code: "E_USAGE",
|
|
330
|
-
message: `depends_on cannot include task itself (${opts.taskId})`,
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
const allTasks = await opts.backend.listTasks();
|
|
334
|
-
const depMap = new Map();
|
|
335
|
-
for (const task of allTasks) {
|
|
336
|
-
const taskId = String(task.id || "").trim();
|
|
337
|
-
if (!taskId)
|
|
338
|
-
continue;
|
|
339
|
-
if (taskId === opts.taskId)
|
|
340
|
-
continue;
|
|
341
|
-
depMap.set(taskId, dedupeStrings(toStringArray(task.depends_on)));
|
|
342
|
-
}
|
|
343
|
-
depMap.set(opts.taskId, nextDepends);
|
|
344
|
-
const cycle = hasDependsOnCycle(depMap);
|
|
345
|
-
if (!cycle)
|
|
346
|
-
return;
|
|
347
|
-
throw new CliError({
|
|
348
|
-
exitCode: 2,
|
|
349
|
-
code: "E_USAGE",
|
|
350
|
-
message: `depends_on cycle detected: ${cycle.join(" -> ")}`,
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
export async function resolveTaskDependencyState(task, backend) {
|
|
354
|
-
const dependsOn = dedupeStrings(toStringArray(task.depends_on));
|
|
355
|
-
if (dependsOn.length === 0) {
|
|
356
|
-
return { dependsOn, missing: [], incomplete: [] };
|
|
357
|
-
}
|
|
358
|
-
const loaded = backend.getTasks
|
|
359
|
-
? await backend.getTasks(dependsOn)
|
|
360
|
-
: await Promise.all(dependsOn.map(async (depId) => await backend.getTask(depId)));
|
|
361
|
-
const missing = [];
|
|
362
|
-
const incomplete = [];
|
|
363
|
-
for (const [idx, depId] of dependsOn.entries()) {
|
|
364
|
-
const dep = loaded[idx] ?? null;
|
|
365
|
-
if (!dep) {
|
|
366
|
-
missing.push(depId);
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
const status = String(dep.status || "TODO").toUpperCase();
|
|
370
|
-
if (status !== "DONE")
|
|
371
|
-
incomplete.push(depId);
|
|
372
|
-
}
|
|
373
|
-
return { dependsOn, missing, incomplete };
|
|
374
|
-
}
|
|
375
|
-
export function buildDependencyState(tasks) {
|
|
376
|
-
const byId = new Map(tasks.map((task) => [task.id, task]));
|
|
377
|
-
const state = new Map();
|
|
378
|
-
for (const task of tasks) {
|
|
379
|
-
const dependsOn = dedupeStrings(toStringArray(task.depends_on));
|
|
380
|
-
const missing = [];
|
|
381
|
-
const incomplete = [];
|
|
382
|
-
for (const depId of dependsOn) {
|
|
383
|
-
const dep = byId.get(depId);
|
|
384
|
-
if (!dep) {
|
|
385
|
-
missing.push(depId);
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
const status = String(dep.status || "TODO").toUpperCase();
|
|
389
|
-
if (status !== "DONE") {
|
|
390
|
-
incomplete.push(depId);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
state.set(task.id, { dependsOn, missing, incomplete });
|
|
394
|
-
}
|
|
395
|
-
return state;
|
|
396
|
-
}
|
|
397
|
-
function formatDepsSummary(dep) {
|
|
398
|
-
if (!dep)
|
|
399
|
-
return null;
|
|
400
|
-
if (dep.dependsOn.length === 0)
|
|
401
|
-
return "deps=none";
|
|
402
|
-
if (dep.missing.length === 0 && dep.incomplete.length === 0)
|
|
403
|
-
return "deps=ready";
|
|
404
|
-
const parts = [];
|
|
405
|
-
if (dep.missing.length > 0) {
|
|
406
|
-
parts.push(`missing:${dep.missing.join(",")}`);
|
|
407
|
-
}
|
|
408
|
-
if (dep.incomplete.length > 0) {
|
|
409
|
-
parts.push(`wait:${dep.incomplete.join(",")}`);
|
|
410
|
-
}
|
|
411
|
-
return `deps=${parts.join(",")}`;
|
|
412
|
-
}
|
|
413
|
-
export function formatTaskLine(task, depState) {
|
|
414
|
-
const status = String(task.status || "TODO").toUpperCase();
|
|
415
|
-
const title = task.title?.trim() || "(untitled task)";
|
|
416
|
-
const extras = [];
|
|
417
|
-
if (task.owner?.trim())
|
|
418
|
-
extras.push(`owner=${task.owner.trim()}`);
|
|
419
|
-
if (task.priority !== undefined && String(task.priority).trim()) {
|
|
420
|
-
extras.push(`prio=${String(task.priority).trim()}`);
|
|
421
|
-
}
|
|
422
|
-
const depsSummary = formatDepsSummary(depState);
|
|
423
|
-
if (depsSummary)
|
|
424
|
-
extras.push(depsSummary);
|
|
425
|
-
const tags = dedupeStrings(toStringArray(task.tags));
|
|
426
|
-
if (tags.length > 0)
|
|
427
|
-
extras.push(`tags=${tags.join(",")}`);
|
|
428
|
-
const verify = dedupeStrings(toStringArray(task.verify));
|
|
429
|
-
if (verify.length > 0)
|
|
430
|
-
extras.push(`verify=${verify.length}`);
|
|
431
|
-
const suffix = extras.length > 0 ? ` (${extras.join(", ")})` : "";
|
|
432
|
-
return `${task.id} [${status}] ${title}${suffix}`;
|
|
433
|
-
}
|
|
434
|
-
export function isTransitionAllowed(current, next) {
|
|
435
|
-
if (current === next)
|
|
436
|
-
return true;
|
|
437
|
-
if (current === "TODO")
|
|
438
|
-
return next === "DOING" || next === "BLOCKED";
|
|
439
|
-
if (current === "DOING")
|
|
440
|
-
return next === "DONE" || next === "BLOCKED";
|
|
441
|
-
if (current === "BLOCKED")
|
|
442
|
-
return next === "TODO" || next === "DOING";
|
|
443
|
-
if (current === "DONE")
|
|
444
|
-
return false;
|
|
445
|
-
return false;
|
|
446
|
-
}
|
|
447
|
-
export function ensureStatusTransitionAllowed(opts) {
|
|
448
|
-
if (opts.force)
|
|
449
|
-
return;
|
|
450
|
-
if (isTransitionAllowed(opts.currentStatus, opts.nextStatus))
|
|
451
|
-
return;
|
|
452
|
-
throw new CliError({
|
|
453
|
-
exitCode: 2,
|
|
454
|
-
code: "E_USAGE",
|
|
455
|
-
message: `Refusing status transition ${opts.currentStatus} -> ${opts.nextStatus} ` +
|
|
456
|
-
"(use --force to override)",
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
export function ensureCommentCommitAllowed(opts) {
|
|
460
|
-
if (!opts.enabled)
|
|
461
|
-
return;
|
|
462
|
-
if (opts.config.commit_automation === "finish_only") {
|
|
463
|
-
throw new CliError({
|
|
464
|
-
exitCode: 2,
|
|
465
|
-
code: "E_USAGE",
|
|
466
|
-
message: `${opts.action}: --commit-from-comment is disabled by commit_automation='finish_only' ` +
|
|
467
|
-
"(allowed only in finish).",
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
enforceStatusCommitPolicy({
|
|
471
|
-
policy: opts.config.status_commit_policy,
|
|
472
|
-
action: opts.action,
|
|
473
|
-
confirmed: opts.confirmed,
|
|
474
|
-
quiet: opts.quiet,
|
|
475
|
-
statusFrom: opts.statusFrom,
|
|
476
|
-
statusTo: opts.statusTo,
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
export function requireStructuredComment(body, prefix, minChars) {
|
|
480
|
-
const normalized = body.trim();
|
|
481
|
-
if (!normalized.toLowerCase().startsWith(prefix.toLowerCase())) {
|
|
482
|
-
throw new CliError({
|
|
483
|
-
exitCode: 2,
|
|
484
|
-
code: "E_USAGE",
|
|
485
|
-
message: `Comment body must start with ${prefix}`,
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
if (normalized.length < minChars) {
|
|
489
|
-
throw new CliError({
|
|
490
|
-
exitCode: 2,
|
|
491
|
-
code: "E_USAGE",
|
|
492
|
-
message: `Comment body must be at least ${minChars} characters`,
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
export async function readHeadCommit(cwd) {
|
|
497
|
-
const { stdout } = await execFileAsync("git", ["log", "-1", "--pretty=%H%x00%s"], { cwd });
|
|
498
|
-
const { hash, subject } = parseGitLogHashSubject(stdout);
|
|
499
|
-
return { hash, message: subject };
|
|
500
|
-
}
|
|
501
|
-
export function enforceStatusCommitPolicy(opts) {
|
|
502
|
-
if (!isMajorStatusCommitTransition(opts.statusFrom, opts.statusTo)) {
|
|
503
|
-
throw new CliError({
|
|
504
|
-
exitCode: 2,
|
|
505
|
-
code: "E_USAGE",
|
|
506
|
-
message: `${opts.action}: status/comment-driven commit is allowed only for major transitions ` +
|
|
507
|
-
`(got ${opts.statusFrom.toUpperCase()} -> ${opts.statusTo.toUpperCase()})`,
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
if (opts.policy === "off")
|
|
511
|
-
return;
|
|
512
|
-
if (opts.policy === "warn") {
|
|
513
|
-
if (!opts.quiet && !opts.confirmed) {
|
|
514
|
-
process.stderr.write(`${warnMessage(`${opts.action}: status/comment-driven commit requested; policy=warn (pass --confirm-status-commit to acknowledge)`)}\n`);
|
|
515
|
-
}
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
if (opts.policy === "confirm" && !opts.confirmed) {
|
|
519
|
-
throw new CliError({
|
|
520
|
-
exitCode: 2,
|
|
521
|
-
code: "E_USAGE",
|
|
522
|
-
message: `${opts.action}: status/comment-driven commit blocked by status_commit_policy='confirm' ` +
|
|
523
|
-
"(pass --confirm-status-commit to proceed)",
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
const MAJOR_STATUS_COMMIT_TRANSITIONS = new Set([
|
|
528
|
-
"READY->DOING",
|
|
529
|
-
"TODO->DOING",
|
|
530
|
-
"DOING->BLOCKED",
|
|
531
|
-
"BLOCKED->DOING",
|
|
532
|
-
"DOING->DONE",
|
|
533
|
-
]);
|
|
534
|
-
export function isMajorStatusCommitTransition(statusFrom, statusTo) {
|
|
535
|
-
const from = statusFrom.trim().toUpperCase();
|
|
536
|
-
const to = statusTo.trim().toUpperCase();
|
|
537
|
-
if (!from || !to)
|
|
538
|
-
return false;
|
|
539
|
-
return MAJOR_STATUS_COMMIT_TRANSITIONS.has(`${from}->${to}`);
|
|
540
|
-
}
|
|
541
|
-
export async function readCommitInfo(cwd, rev) {
|
|
542
|
-
const { stdout } = await execFileAsync("git", ["log", "-1", "--pretty=%H%x00%s", rev], { cwd });
|
|
543
|
-
const { hash, subject } = parseGitLogHashSubject(stdout);
|
|
544
|
-
return { hash, message: subject };
|
|
545
|
-
}
|
|
546
|
-
export function defaultCommitEmojiForStatus(status) {
|
|
547
|
-
const normalized = status.trim().toUpperCase();
|
|
548
|
-
if (normalized === "DOING")
|
|
549
|
-
return "🚧";
|
|
550
|
-
if (normalized === "DONE")
|
|
551
|
-
return "✅";
|
|
552
|
-
if (normalized === "BLOCKED")
|
|
553
|
-
return "⛔";
|
|
554
|
-
return "🧩";
|
|
555
|
-
}
|
|
556
|
-
export async function defaultCommitEmojiForAgentId(ctx, agentId) {
|
|
557
|
-
const agentsDir = path.join(ctx.resolvedProject.gitRoot, ctx.config.paths.agents_dir);
|
|
558
|
-
return await resolveCommitEmojiForAgent({ agentsDirAbs: agentsDir, agentId });
|
|
559
|
-
}
|
|
560
|
-
export function parseTaskListFilters(args, opts) {
|
|
561
|
-
const out = { status: [], owner: [], tag: [], quiet: false, strictRead: false };
|
|
562
|
-
for (let i = 0; i < args.length; i++) {
|
|
563
|
-
const arg = args[i];
|
|
564
|
-
if (!arg)
|
|
565
|
-
continue;
|
|
566
|
-
if (arg === "--quiet") {
|
|
567
|
-
out.quiet = true;
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
if (arg === "--strict-read") {
|
|
571
|
-
out.strictRead = true;
|
|
572
|
-
continue;
|
|
573
|
-
}
|
|
574
|
-
if (arg === "--status") {
|
|
575
|
-
const next = args[i + 1];
|
|
576
|
-
if (!next) {
|
|
577
|
-
throw new CliError({
|
|
578
|
-
exitCode: exitCodeForError("E_USAGE"),
|
|
579
|
-
code: "E_USAGE",
|
|
580
|
-
message: missingValueMessage("--status"),
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
out.status.push(next);
|
|
584
|
-
i++;
|
|
585
|
-
continue;
|
|
586
|
-
}
|
|
587
|
-
if (arg === "--owner") {
|
|
588
|
-
const next = args[i + 1];
|
|
589
|
-
if (!next) {
|
|
590
|
-
throw new CliError({
|
|
591
|
-
exitCode: exitCodeForError("E_USAGE"),
|
|
592
|
-
code: "E_USAGE",
|
|
593
|
-
message: missingValueMessage("--owner"),
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
out.owner.push(next);
|
|
597
|
-
i++;
|
|
598
|
-
continue;
|
|
599
|
-
}
|
|
600
|
-
if (arg === "--tag") {
|
|
601
|
-
const next = args[i + 1];
|
|
602
|
-
if (!next) {
|
|
603
|
-
throw new CliError({
|
|
604
|
-
exitCode: exitCodeForError("E_USAGE"),
|
|
605
|
-
code: "E_USAGE",
|
|
606
|
-
message: missingValueMessage("--tag"),
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
out.tag.push(next);
|
|
610
|
-
i++;
|
|
611
|
-
continue;
|
|
612
|
-
}
|
|
613
|
-
if (opts?.allowLimit && arg === "--limit") {
|
|
614
|
-
const next = args[i + 1];
|
|
615
|
-
if (!next) {
|
|
616
|
-
throw new CliError({
|
|
617
|
-
exitCode: exitCodeForError("E_USAGE"),
|
|
618
|
-
code: "E_USAGE",
|
|
619
|
-
message: missingValueMessage("--limit"),
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
const parsed = Number.parseInt(next, 10);
|
|
623
|
-
if (!Number.isFinite(parsed)) {
|
|
624
|
-
throw new CliError({
|
|
625
|
-
exitCode: exitCodeForError("E_USAGE"),
|
|
626
|
-
code: "E_USAGE",
|
|
627
|
-
message: invalidValueForFlag("--limit", next, "integer"),
|
|
628
|
-
});
|
|
629
|
-
}
|
|
630
|
-
out.limit = parsed;
|
|
631
|
-
i++;
|
|
632
|
-
continue;
|
|
633
|
-
}
|
|
634
|
-
if (arg.startsWith("--")) {
|
|
635
|
-
throw new CliError({
|
|
636
|
-
exitCode: exitCodeForError("E_USAGE"),
|
|
637
|
-
code: "E_USAGE",
|
|
638
|
-
message: `Unknown flag: ${arg}`,
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
return out;
|
|
643
|
-
}
|
|
644
|
-
export function handleTaskListWarnings(opts) {
|
|
645
|
-
const warnings = opts.backend.getLastListWarnings?.() ?? [];
|
|
646
|
-
if (warnings.length === 0)
|
|
647
|
-
return;
|
|
648
|
-
const preview = warnings.slice(0, 3).join("; ");
|
|
649
|
-
const suffix = warnings.length > 3 ? `; +${warnings.length - 3} more` : "";
|
|
650
|
-
const message = `skipped ${warnings.length} task files during scan (${preview}${suffix})`;
|
|
651
|
-
if (opts.strictRead) {
|
|
652
|
-
throw new CliError({
|
|
653
|
-
exitCode: exitCodeForError("E_VALIDATION"),
|
|
654
|
-
code: "E_VALIDATION",
|
|
655
|
-
message: `task scan strict mode failed: ${message}`,
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
process.stderr.write(`${warnMessage(message)}\n`);
|
|
659
|
-
}
|
|
660
|
-
export function taskTextBlob(task) {
|
|
661
|
-
const parts = [];
|
|
662
|
-
for (const key of ["id", "title", "description", "status", "priority", "owner"]) {
|
|
663
|
-
const value = task[key];
|
|
664
|
-
if (typeof value === "string" && value.trim())
|
|
665
|
-
parts.push(value.trim());
|
|
666
|
-
}
|
|
667
|
-
const tags = toStringArray(task.tags);
|
|
668
|
-
parts.push(...tags.filter(Boolean));
|
|
669
|
-
const comments = Array.isArray(task.comments) ? task.comments : [];
|
|
670
|
-
for (const comment of comments) {
|
|
671
|
-
if (comment && typeof comment.author === "string")
|
|
672
|
-
parts.push(comment.author);
|
|
673
|
-
if (comment && typeof comment.body === "string")
|
|
674
|
-
parts.push(comment.body);
|
|
675
|
-
}
|
|
676
|
-
const commit = task.commit ?? null;
|
|
677
|
-
if (commit && typeof commit.hash === "string")
|
|
678
|
-
parts.push(commit.hash);
|
|
679
|
-
if (commit && typeof commit.message === "string")
|
|
680
|
-
parts.push(commit.message);
|
|
681
|
-
return parts.join("\n");
|
|
682
|
-
}
|
|
2
|
+
export { nowIso, normalizeTaskDocVersion, taskObservationSectionName, extractTaskObservationSection, VERIFY_STEPS_PLACEHOLDER, VERIFICATION_RESULTS_BEGIN, VERIFICATION_RESULTS_END, extractDocSection, isVerifyStepsFilled, isDocSectionFilled, ensureAgentFilledRequiredDocSections, normalizeVerificationSectionLayout, } from "./shared/docs.js";
|
|
3
|
+
export { normalizeDependsOnInput, normalizeTaskStatus, toStringArray, requiresVerify, readTaskTagPolicy, resolvePrimaryTagFromConfig, requiresVerifyStepsByPrimary, requiresVerificationByPrimary, resolvePrimaryTag, warnIfUnknownOwner, } from "./shared/tags.js";
|
|
4
|
+
export { ensureTaskDependsOnGraphIsAcyclic, resolveTaskDependencyState, buildDependencyState, formatTaskLine, } from "./shared/dependencies.js";
|
|
5
|
+
export { appendTaskEvent, ensurePlanApprovedIfRequired, ensureVerificationSatisfiedIfRequired, isTransitionAllowed, ensureStatusTransitionAllowed, ensureCommentCommitAllowed, requireStructuredComment, enforceStatusCommitPolicy, isMajorStatusCommitTransition, readHeadCommit, readCommitInfo, defaultCommitEmojiForStatus, defaultCommitEmojiForAgentId, } from "./shared/transitions.js";
|
|
6
|
+
export { parseTaskListFilters, handleTaskListWarnings, taskTextBlob, } from "./shared/listing.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/task/start.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/task/start.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAwBnC,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiMlB"}
|