agentplane 0.1.4 → 0.1.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/dist/agents/agents-template.d.ts.map +1 -0
- package/dist/{agents-template.js → agents/agents-template.js} +2 -2
- package/dist/{task-backend.d.ts → backends/task-backend.d.ts} +5 -3
- package/dist/backends/task-backend.d.ts.map +1 -0
- package/dist/{task-backend.js → backends/task-backend.js} +102 -268
- package/dist/backends/task-index.d.ts +16 -0
- package/dist/backends/task-index.d.ts.map +1 -0
- package/dist/backends/task-index.js +84 -0
- package/dist/cli/archive.d.ts +16 -0
- package/dist/cli/archive.d.ts.map +1 -0
- package/dist/cli/archive.js +149 -0
- package/dist/cli/checksum.d.ts +3 -0
- package/dist/cli/checksum.d.ts.map +1 -0
- package/dist/cli/checksum.js +12 -0
- package/dist/cli/command-guide.d.ts.map +1 -0
- package/dist/cli/error-map.d.ts +4 -0
- package/dist/cli/error-map.d.ts.map +1 -0
- package/dist/cli/error-map.js +42 -0
- package/dist/cli/exit-codes.d.ts +3 -0
- package/dist/cli/exit-codes.d.ts.map +1 -0
- package/dist/cli/exit-codes.js +12 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/{help.js → cli/help.js} +1 -1
- package/dist/cli/http.d.ts +4 -0
- package/dist/cli/http.d.ts.map +1 -0
- package/dist/cli/http.js +95 -0
- package/dist/cli/output.d.ts +16 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +47 -0
- package/dist/cli/recipes-bundled.js +2 -2
- package/dist/cli/run-cli.d.ts.map +1 -0
- package/dist/cli/run-cli.js +2681 -0
- package/dist/{run-cli.test-helpers.d.ts → cli/run-cli.test-helpers.d.ts} +6 -0
- package/dist/cli/run-cli.test-helpers.d.ts.map +1 -0
- package/dist/{run-cli.test-helpers.js → cli/run-cli.test-helpers.js} +67 -0
- package/dist/cli/update-check.d.ts +31 -0
- package/dist/cli/update-check.d.ts.map +1 -0
- package/dist/cli/update-check.js +86 -0
- package/dist/cli.js +1 -1
- package/dist/commands/backend.d.ts +15 -0
- package/dist/commands/backend.d.ts.map +1 -0
- package/dist/commands/backend.js +211 -0
- package/dist/commands/recipes.d.ts +13 -0
- package/dist/commands/recipes.d.ts.map +1 -0
- package/dist/commands/recipes.js +1919 -0
- package/dist/commands/upgrade.d.ts +6 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +291 -0
- package/dist/commands/workflow.d.ts +367 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +4619 -0
- package/dist/meta/version.d.ts.map +1 -0
- package/dist/meta/version.js +20 -0
- package/dist/recipes/bundled-recipes.d.ts.map +1 -0
- package/dist/shared/comment-format.d.ts.map +1 -0
- package/dist/shared/env.d.ts.map +1 -0
- package/dist/{errors.d.ts → shared/errors.d.ts} +1 -3
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/{errors.js → shared/errors.js} +1 -3
- package/package.json +6 -2
- package/dist/agents-template.d.ts.map +0 -1
- package/dist/bundled-recipes.d.ts.map +0 -1
- package/dist/command-guide.d.ts.map +0 -1
- package/dist/comment-format.d.ts.map +0 -1
- package/dist/env.d.ts.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/help.d.ts.map +0 -1
- package/dist/run-cli.d.ts.map +0 -1
- package/dist/run-cli.js +0 -9454
- package/dist/run-cli.test-helpers.d.ts.map +0 -1
- package/dist/task-backend.d.ts.map +0 -1
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js +0 -3
- /package/dist/{agents-template.d.ts → agents/agents-template.d.ts} +0 -0
- /package/dist/{command-guide.d.ts → cli/command-guide.d.ts} +0 -0
- /package/dist/{command-guide.js → cli/command-guide.js} +0 -0
- /package/dist/{help.d.ts → cli/help.d.ts} +0 -0
- /package/dist/{run-cli.d.ts → cli/run-cli.d.ts} +0 -0
- /package/dist/{version.d.ts → meta/version.d.ts} +0 -0
- /package/dist/{bundled-recipes.d.ts → recipes/bundled-recipes.d.ts} +0 -0
- /package/dist/{bundled-recipes.js → recipes/bundled-recipes.js} +0 -0
- /package/dist/{comment-format.d.ts → shared/comment-format.d.ts} +0 -0
- /package/dist/{comment-format.js → shared/comment-format.js} +0 -0
- /package/dist/{env.d.ts → shared/env.d.ts} +0 -0
- /package/dist/{env.js → shared/env.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents-template.d.ts","sourceRoot":"","sources":["../../src/agents/agents-template.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,CAAC;AAElD,KAAK,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAwC5D,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAG1D;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAanE;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CASvF"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
const AGENTS_TEMPLATE_URL = new URL("
|
|
5
|
-
const AGENTS_DIR_URL = new URL("
|
|
4
|
+
const AGENTS_TEMPLATE_URL = new URL("../../assets/AGENTS.md", import.meta.url);
|
|
5
|
+
const AGENTS_DIR_URL = new URL("../../assets/agents/", import.meta.url);
|
|
6
6
|
const HEADING_RE = /^(#+)\s+(.*)$/;
|
|
7
7
|
function ensureTrailingNewline(text) {
|
|
8
8
|
return text.endsWith("\n") ? text : `${text}\n`;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type AgentplaneConfig, type ResolvedProject, type TaskRecord } from "@agentplaneorg/core";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
type ExtractTaskDoc = (body: string) => string;
|
|
3
|
+
type MergeTaskDoc = (body: string, doc: string) => string;
|
|
4
|
+
declare const extractTaskDoc: ExtractTaskDoc;
|
|
5
|
+
declare const mergeTaskDoc: MergeTaskDoc;
|
|
6
|
+
export { extractTaskDoc, mergeTaskDoc };
|
|
4
7
|
export type TaskData = {
|
|
5
8
|
id: string;
|
|
6
9
|
title: string;
|
|
@@ -171,5 +174,4 @@ export declare function loadTaskBackend(opts: {
|
|
|
171
174
|
config: AgentplaneConfig;
|
|
172
175
|
backendConfigPath: string;
|
|
173
176
|
}>;
|
|
174
|
-
export {};
|
|
175
177
|
//# sourceMappingURL=task-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-backend.d.ts","sourceRoot":"","sources":["../../src/backends/task-backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { createHash
|
|
2
|
-
import { mkdir, readdir, readFile,
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readdir, readFile, stat } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { canonicalizeJson, loadConfig, parseTaskReadme, renderTaskReadme, resolveProject, taskReadmePath, } from "@agentplaneorg/core";
|
|
5
|
-
import { loadDotEnv } from "
|
|
6
|
-
|
|
7
|
-
const TASK_ID_RE = new RegExp(String.raw `^\d{12}-[${
|
|
8
|
-
const DOC_SECTION_HEADER = "## Summary";
|
|
9
|
-
const DOC_SECTION_HEADER_RE = /^##\s+Summary(?:\s|$|#)/;
|
|
10
|
-
const AUTO_SUMMARY_HEADER = "## Changes Summary (auto)";
|
|
4
|
+
import { atomicWriteFile as atomicWriteFileCore, canonicalizeJson, docChanged, extractTaskDoc as extractTaskDocCore, generateTaskId as generateTaskIdCore, loadConfig, mergeTaskDoc as mergeTaskDocCore, parseTaskReadme, renderTaskReadme, resolveProject, TASK_ID_ALPHABET, taskReadmePath, } from "@agentplaneorg/core";
|
|
5
|
+
import { loadDotEnv } from "../shared/env.js";
|
|
6
|
+
import { buildTaskIndexEntry, loadTaskIndex, resolveTaskIndexPath, saveTaskIndex, } from "./task-index.js";
|
|
7
|
+
const TASK_ID_RE = new RegExp(String.raw `^\d{12}-[${TASK_ID_ALPHABET}]{4,}$`);
|
|
11
8
|
const DEFAULT_DOC_UPDATED_BY = "agentplane";
|
|
12
9
|
const DOC_VERSION = 2;
|
|
10
|
+
const atomicWriteFile = atomicWriteFileCore;
|
|
11
|
+
const extractTaskDoc = extractTaskDocCore;
|
|
12
|
+
const mergeTaskDoc = mergeTaskDocCore;
|
|
13
|
+
const generateTaskId = generateTaskIdCore;
|
|
13
14
|
function nowIso() {
|
|
14
15
|
return new Date().toISOString();
|
|
15
16
|
}
|
|
@@ -35,145 +36,6 @@ function firstNonEmptyString(...values) {
|
|
|
35
36
|
function sleep(ms) {
|
|
36
37
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
37
38
|
}
|
|
38
|
-
function normalizeDoc(text) {
|
|
39
|
-
return (text ?? "")
|
|
40
|
-
.split("\n")
|
|
41
|
-
.map((line) => line.replaceAll(/\s+$/gu, ""))
|
|
42
|
-
.join("\n")
|
|
43
|
-
.trim();
|
|
44
|
-
}
|
|
45
|
-
function normalizeDocSectionName(section) {
|
|
46
|
-
return section.trim().replaceAll(/\s+/g, " ").toLowerCase();
|
|
47
|
-
}
|
|
48
|
-
function normalizeSectionLines(lines) {
|
|
49
|
-
const trimmedLines = [...lines];
|
|
50
|
-
while (trimmedLines.length > 0 && trimmedLines[0]?.trim() === "")
|
|
51
|
-
trimmedLines.shift();
|
|
52
|
-
while (trimmedLines.length > 0 && trimmedLines.at(-1)?.trim() === "")
|
|
53
|
-
trimmedLines.pop();
|
|
54
|
-
const out = [];
|
|
55
|
-
let inFence = false;
|
|
56
|
-
let pendingBlank = false;
|
|
57
|
-
for (const line of trimmedLines) {
|
|
58
|
-
const fenceCheck = line.trimStart();
|
|
59
|
-
if (fenceCheck.startsWith("```")) {
|
|
60
|
-
if (pendingBlank) {
|
|
61
|
-
out.push("");
|
|
62
|
-
pendingBlank = false;
|
|
63
|
-
}
|
|
64
|
-
out.push(line);
|
|
65
|
-
inFence = !inFence;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (inFence) {
|
|
69
|
-
out.push(line);
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
if (line.trim() === "") {
|
|
73
|
-
pendingBlank = true;
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (pendingBlank) {
|
|
77
|
-
out.push("");
|
|
78
|
-
pendingBlank = false;
|
|
79
|
-
}
|
|
80
|
-
out.push(line);
|
|
81
|
-
}
|
|
82
|
-
return out;
|
|
83
|
-
}
|
|
84
|
-
function splitCombinedHeadingLines(doc) {
|
|
85
|
-
const lines = doc.replaceAll("\r\n", "\n").split("\n");
|
|
86
|
-
const out = [];
|
|
87
|
-
let inFence = false;
|
|
88
|
-
for (const line of lines) {
|
|
89
|
-
const trimmed = line.trimStart();
|
|
90
|
-
if (trimmed.startsWith("```")) {
|
|
91
|
-
inFence = !inFence;
|
|
92
|
-
out.push(line);
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
if (!inFence && line.includes("## ")) {
|
|
96
|
-
const matches = [...line.matchAll(/##\s+/g)];
|
|
97
|
-
if (matches.length > 1 && matches[0]?.index === 0) {
|
|
98
|
-
let start = 0;
|
|
99
|
-
for (let i = 1; i < matches.length; i += 1) {
|
|
100
|
-
const idx = matches[i]?.index ?? 0;
|
|
101
|
-
const chunk = line.slice(start, idx).trimEnd();
|
|
102
|
-
if (chunk)
|
|
103
|
-
out.push(chunk);
|
|
104
|
-
start = idx;
|
|
105
|
-
}
|
|
106
|
-
const last = line.slice(start).trimEnd();
|
|
107
|
-
if (last)
|
|
108
|
-
out.push(last);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
out.push(line);
|
|
113
|
-
}
|
|
114
|
-
return out;
|
|
115
|
-
}
|
|
116
|
-
function normalizeTaskDoc(doc) {
|
|
117
|
-
const normalized = doc.replaceAll("\r\n", "\n");
|
|
118
|
-
const trimmed = normalized.replaceAll(/^\n+|\n+$/g, "");
|
|
119
|
-
if (!trimmed)
|
|
120
|
-
return "";
|
|
121
|
-
const lines = splitCombinedHeadingLines(trimmed);
|
|
122
|
-
const sections = new Map();
|
|
123
|
-
const order = [];
|
|
124
|
-
const pendingSeparator = new Set();
|
|
125
|
-
let currentKey = null;
|
|
126
|
-
for (const line of lines) {
|
|
127
|
-
const match = /^##\s+(.*)$/.exec(line.trim());
|
|
128
|
-
if (match) {
|
|
129
|
-
const title = match[1]?.trim() ?? "";
|
|
130
|
-
const key = normalizeDocSectionName(title);
|
|
131
|
-
if (key) {
|
|
132
|
-
const existing = sections.get(key);
|
|
133
|
-
if (existing) {
|
|
134
|
-
if (existing.lines.some((entry) => entry.trim() !== "")) {
|
|
135
|
-
pendingSeparator.add(key);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
sections.set(key, { title, lines: [] });
|
|
140
|
-
order.push(key);
|
|
141
|
-
}
|
|
142
|
-
currentKey = key;
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (currentKey) {
|
|
147
|
-
const entry = sections.get(currentKey);
|
|
148
|
-
if (!entry)
|
|
149
|
-
continue;
|
|
150
|
-
if (pendingSeparator.has(currentKey) && line.trim() !== "") {
|
|
151
|
-
entry.lines.push("");
|
|
152
|
-
pendingSeparator.delete(currentKey);
|
|
153
|
-
}
|
|
154
|
-
entry.lines.push(line);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (order.length === 0)
|
|
158
|
-
return trimmed;
|
|
159
|
-
const out = [];
|
|
160
|
-
for (const key of order) {
|
|
161
|
-
const section = sections.get(key);
|
|
162
|
-
if (!section)
|
|
163
|
-
continue;
|
|
164
|
-
const normalizedLines = normalizeSectionLines(section.lines);
|
|
165
|
-
if (normalizedLines.length > 0) {
|
|
166
|
-
out.push(`## ${section.title}`, "", ...normalizedLines, "");
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
out.push(`## ${section.title}`, "", "");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return out.join("\n").trimEnd();
|
|
173
|
-
}
|
|
174
|
-
function docChanged(existing, updated) {
|
|
175
|
-
return normalizeDoc(existing) !== normalizeDoc(updated);
|
|
176
|
-
}
|
|
177
39
|
function normalizeUpdatedBy(value) {
|
|
178
40
|
if (typeof value !== "string")
|
|
179
41
|
return "";
|
|
@@ -243,67 +105,7 @@ function resolveDocUpdatedByFromTask(task, fallback) {
|
|
|
243
105
|
const fallbackValue = normalizeUpdatedBy(fallback);
|
|
244
106
|
return fallbackValue || fallback;
|
|
245
107
|
}
|
|
246
|
-
|
|
247
|
-
return DOC_SECTION_HEADER_RE.test(line.trim());
|
|
248
|
-
}
|
|
249
|
-
export function extractTaskDoc(body) {
|
|
250
|
-
if (!body)
|
|
251
|
-
return "";
|
|
252
|
-
const lines = body.split("\n");
|
|
253
|
-
let startIdx = null;
|
|
254
|
-
for (const [idx, line] of lines.entries()) {
|
|
255
|
-
if (isDocSectionHeader(line)) {
|
|
256
|
-
startIdx = idx;
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
if (startIdx === null)
|
|
261
|
-
return "";
|
|
262
|
-
if (lines[startIdx]?.trim() !== DOC_SECTION_HEADER) {
|
|
263
|
-
lines[startIdx] = DOC_SECTION_HEADER;
|
|
264
|
-
}
|
|
265
|
-
let endIdx = lines.length;
|
|
266
|
-
for (let idx = startIdx + 1; idx < lines.length; idx++) {
|
|
267
|
-
if (lines[idx]?.trim() === AUTO_SUMMARY_HEADER) {
|
|
268
|
-
endIdx = idx;
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
const doc = lines.slice(startIdx, endIdx).join("\n").trimEnd();
|
|
273
|
-
return normalizeTaskDoc(doc);
|
|
274
|
-
}
|
|
275
|
-
export function mergeTaskDoc(body, doc) {
|
|
276
|
-
const docText = normalizeTaskDoc(String(doc ?? ""));
|
|
277
|
-
if (docText) {
|
|
278
|
-
const lines = body ? body.split("\n") : [];
|
|
279
|
-
let prefixIdx = null;
|
|
280
|
-
for (const [idx, line] of lines.entries()) {
|
|
281
|
-
if (isDocSectionHeader(line)) {
|
|
282
|
-
prefixIdx = idx;
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
const prefixText = prefixIdx === null ? "" : lines.slice(0, prefixIdx).join("\n").trimEnd();
|
|
287
|
-
let autoIdx = null;
|
|
288
|
-
for (const [idx, line] of lines.entries()) {
|
|
289
|
-
if (line.trim() === AUTO_SUMMARY_HEADER) {
|
|
290
|
-
autoIdx = idx;
|
|
291
|
-
break;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
const autoBlock = autoIdx === null ? "" : lines.slice(autoIdx).join("\n").trimEnd();
|
|
295
|
-
const parts = [];
|
|
296
|
-
if (prefixText) {
|
|
297
|
-
parts.push(prefixText, "");
|
|
298
|
-
}
|
|
299
|
-
parts.push(docText.trimEnd());
|
|
300
|
-
if (autoBlock) {
|
|
301
|
-
parts.push("", autoBlock);
|
|
302
|
-
}
|
|
303
|
-
return `${parts.join("\n").trimEnd()}\n`;
|
|
304
|
-
}
|
|
305
|
-
return body;
|
|
306
|
-
}
|
|
108
|
+
export { extractTaskDoc, mergeTaskDoc };
|
|
307
109
|
function validateTaskId(taskId) {
|
|
308
110
|
if (TASK_ID_RE.test(taskId))
|
|
309
111
|
return;
|
|
@@ -341,6 +143,14 @@ function toStringArray(value) {
|
|
|
341
143
|
return [];
|
|
342
144
|
return value.filter((v) => typeof v === "string");
|
|
343
145
|
}
|
|
146
|
+
function normalizeDependsOn(value) {
|
|
147
|
+
if (Array.isArray(value)) {
|
|
148
|
+
return value.filter((v) => typeof v === "string" && v.trim() !== "[]");
|
|
149
|
+
}
|
|
150
|
+
if (typeof value === "string" && value.trim() === "[]")
|
|
151
|
+
return [];
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
344
154
|
function normalizePriority(value) {
|
|
345
155
|
const raw = toStringSafe(value).trim().toLowerCase();
|
|
346
156
|
if (!raw)
|
|
@@ -378,7 +188,7 @@ export function taskRecordToData(record) {
|
|
|
378
188
|
status: typeof fm.status === "string" ? fm.status : "TODO",
|
|
379
189
|
priority: typeof fm.priority === "string" || typeof fm.priority === "number" ? fm.priority : "",
|
|
380
190
|
owner: typeof fm.owner === "string" ? fm.owner : "",
|
|
381
|
-
depends_on:
|
|
191
|
+
depends_on: normalizeDependsOn(fm.depends_on),
|
|
382
192
|
tags: toStringArray(fm.tags),
|
|
383
193
|
verify: toStringArray(fm.verify),
|
|
384
194
|
commit,
|
|
@@ -435,7 +245,7 @@ export function buildTasksExportSnapshotFromTasks(tasks) {
|
|
|
435
245
|
export async function writeTasksExportFromTasks(opts) {
|
|
436
246
|
const snapshot = buildTasksExportSnapshotFromTasks(opts.tasks);
|
|
437
247
|
await mkdir(path.dirname(opts.outputPath), { recursive: true });
|
|
438
|
-
await
|
|
248
|
+
await atomicWriteFile(opts.outputPath, `${JSON.stringify(snapshot, null, 2)}\n`);
|
|
439
249
|
}
|
|
440
250
|
export class LocalBackend {
|
|
441
251
|
id = "local";
|
|
@@ -450,40 +260,64 @@ export class LocalBackend {
|
|
|
450
260
|
if (length < 4)
|
|
451
261
|
throw new Error(invalidLengthMessage(length, 4));
|
|
452
262
|
const attempts = Math.max(1, opts.attempts);
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
catch (err) {
|
|
471
|
-
const code = err?.code;
|
|
472
|
-
if (code === "ENOENT")
|
|
473
|
-
return taskId;
|
|
474
|
-
throw err;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
throw new Error("Failed to generate a unique task id (exhausted attempts)");
|
|
263
|
+
return await generateTaskId({
|
|
264
|
+
length,
|
|
265
|
+
attempts,
|
|
266
|
+
isAvailable: async (taskId) => {
|
|
267
|
+
const readmePath = taskReadmePath(this.root, taskId);
|
|
268
|
+
try {
|
|
269
|
+
await readFile(readmePath, "utf8");
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
const code = err?.code;
|
|
274
|
+
if (code === "ENOENT")
|
|
275
|
+
return true;
|
|
276
|
+
throw err;
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
});
|
|
478
280
|
}
|
|
479
281
|
async listTasks() {
|
|
480
282
|
const tasks = [];
|
|
481
283
|
const entries = await readdir(this.root, { withFileTypes: true }).catch(() => []);
|
|
284
|
+
const indexPath = resolveTaskIndexPath(this.root);
|
|
285
|
+
const cachedIndex = await loadTaskIndex(indexPath);
|
|
286
|
+
const cachedByPath = new Map();
|
|
287
|
+
if (cachedIndex) {
|
|
288
|
+
for (const entry of cachedIndex.tasks) {
|
|
289
|
+
cachedByPath.set(entry.readmePath, entry);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const nextIndex = [];
|
|
482
293
|
const seen = new Set();
|
|
483
294
|
for (const entry of entries) {
|
|
484
295
|
if (!entry.isDirectory())
|
|
485
296
|
continue;
|
|
486
297
|
const readme = path.join(this.root, entry.name, "README.md");
|
|
298
|
+
let stats;
|
|
299
|
+
try {
|
|
300
|
+
stats = await stat(readme);
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (!stats.isFile())
|
|
306
|
+
continue;
|
|
307
|
+
const cached = cachedByPath.get(readme);
|
|
308
|
+
if (cached?.mtimeMs === stats.mtimeMs) {
|
|
309
|
+
const taskId = cached.task.id.trim();
|
|
310
|
+
if (taskId) {
|
|
311
|
+
validateTaskId(taskId);
|
|
312
|
+
if (seen.has(taskId)) {
|
|
313
|
+
throw new Error(`Duplicate task id in local backend: ${taskId}`);
|
|
314
|
+
}
|
|
315
|
+
seen.add(taskId);
|
|
316
|
+
}
|
|
317
|
+
tasks.push(cached.task);
|
|
318
|
+
nextIndex.push(cached);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
487
321
|
let text = "";
|
|
488
322
|
try {
|
|
489
323
|
text = await readFile(readme, "utf8");
|
|
@@ -516,6 +350,13 @@ export class LocalBackend {
|
|
|
516
350
|
readmePath: readme,
|
|
517
351
|
});
|
|
518
352
|
tasks.push(task);
|
|
353
|
+
nextIndex.push(buildTaskIndexEntry(task, readme, stats.mtimeMs));
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
await saveTaskIndex(indexPath, { schema_version: 1, tasks: nextIndex });
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
// Best-effort cache; ignore failures.
|
|
519
360
|
}
|
|
520
361
|
return tasks;
|
|
521
362
|
}
|
|
@@ -598,7 +439,7 @@ export class LocalBackend {
|
|
|
598
439
|
}
|
|
599
440
|
await mkdir(path.dirname(readme), { recursive: true });
|
|
600
441
|
const text = renderTaskReadme(payload, body || "");
|
|
601
|
-
await
|
|
442
|
+
await atomicWriteFile(readme, text.endsWith("\n") ? text : `${text}\n`);
|
|
602
443
|
}
|
|
603
444
|
async setTaskDoc(taskId, doc, updatedBy) {
|
|
604
445
|
const readme = taskReadmePath(this.root, taskId);
|
|
@@ -616,7 +457,7 @@ export class LocalBackend {
|
|
|
616
457
|
frontmatter.doc_version = DOC_VERSION;
|
|
617
458
|
}
|
|
618
459
|
const next = renderTaskReadme(frontmatter, body);
|
|
619
|
-
await
|
|
460
|
+
await atomicWriteFile(readme, next.endsWith("\n") ? next : `${next}\n`);
|
|
620
461
|
}
|
|
621
462
|
async touchTaskDocMetadata(taskId, updatedBy) {
|
|
622
463
|
const readme = taskReadmePath(this.root, taskId);
|
|
@@ -627,7 +468,7 @@ export class LocalBackend {
|
|
|
627
468
|
frontmatter.doc_updated_at = nowIso();
|
|
628
469
|
frontmatter.doc_updated_by = resolveDocUpdatedByFromFrontmatter(frontmatter, updatedBy, this.updatedBy);
|
|
629
470
|
const next = renderTaskReadme(frontmatter, parsed.body || "");
|
|
630
|
-
await
|
|
471
|
+
await atomicWriteFile(readme, next.endsWith("\n") ? next : `${next}\n`);
|
|
631
472
|
}
|
|
632
473
|
async writeTasks(tasks) {
|
|
633
474
|
for (const task of tasks) {
|
|
@@ -654,11 +495,11 @@ export class RedmineBackend {
|
|
|
654
495
|
issueCache = new Map();
|
|
655
496
|
reverseStatus = new Map();
|
|
656
497
|
constructor(settings, opts) {
|
|
657
|
-
const envUrl = firstNonEmptyString(process.env.
|
|
658
|
-
const envApiKey = firstNonEmptyString(process.env.
|
|
659
|
-
const envProjectId = firstNonEmptyString(process.env.
|
|
660
|
-
const envAssignee = (process.env.
|
|
661
|
-
const envOwner = firstNonEmptyString(process.env.
|
|
498
|
+
const envUrl = firstNonEmptyString(process.env.AGENTPLANE_REDMINE_URL);
|
|
499
|
+
const envApiKey = firstNonEmptyString(process.env.AGENTPLANE_REDMINE_API_KEY);
|
|
500
|
+
const envProjectId = firstNonEmptyString(process.env.AGENTPLANE_REDMINE_PROJECT_ID);
|
|
501
|
+
const envAssignee = (process.env.AGENTPLANE_REDMINE_ASSIGNEE_ID ?? "").trim();
|
|
502
|
+
const envOwner = firstNonEmptyString(process.env.AGENTPLANE_REDMINE_OWNER, process.env.AGENTPLANE_REDMINE_OWNER_AGENT);
|
|
662
503
|
this.baseUrl = firstNonEmptyString(envUrl, settings.url).replaceAll(/\/+$/gu, "");
|
|
663
504
|
this.apiKey = firstNonEmptyString(envApiKey, settings.api_key);
|
|
664
505
|
this.projectId = firstNonEmptyString(envProjectId, settings.project_id);
|
|
@@ -696,7 +537,11 @@ export class RedmineBackend {
|
|
|
696
537
|
const cached = await this.cache.listTasks();
|
|
697
538
|
existingIds = new Set(cached.map((task) => toStringSafe(task.id)).filter(Boolean));
|
|
698
539
|
}
|
|
699
|
-
return generateTaskId(
|
|
540
|
+
return await generateTaskId({
|
|
541
|
+
length,
|
|
542
|
+
attempts,
|
|
543
|
+
isAvailable: (taskId) => !existingIds.has(taskId),
|
|
544
|
+
});
|
|
700
545
|
}
|
|
701
546
|
async listTasks() {
|
|
702
547
|
try {
|
|
@@ -1388,26 +1233,6 @@ export class RedmineBackend {
|
|
|
1388
1233
|
throw lastError instanceof Error ? lastError : new RedmineUnavailable("Redmine unavailable");
|
|
1389
1234
|
}
|
|
1390
1235
|
}
|
|
1391
|
-
function generateTaskId(existingIds, length, attempts) {
|
|
1392
|
-
if (length < 4)
|
|
1393
|
-
throw new Error(invalidLengthMessage(length, 4));
|
|
1394
|
-
for (let i = 0; i < attempts; i++) {
|
|
1395
|
-
const now = new Date();
|
|
1396
|
-
const yyyy = String(now.getUTCFullYear()).padStart(4, "0");
|
|
1397
|
-
const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
1398
|
-
const dd = String(now.getUTCDate()).padStart(2, "0");
|
|
1399
|
-
const hh = String(now.getUTCHours()).padStart(2, "0");
|
|
1400
|
-
const min = String(now.getUTCMinutes()).padStart(2, "0");
|
|
1401
|
-
let suffix = "";
|
|
1402
|
-
for (let j = 0; j < length; j++) {
|
|
1403
|
-
suffix += ID_ALPHABET[randomInt(0, ID_ALPHABET.length)];
|
|
1404
|
-
}
|
|
1405
|
-
const candidate = `${yyyy}${mm}${dd}${hh}${min}-${suffix}`;
|
|
1406
|
-
if (!existingIds.has(candidate))
|
|
1407
|
-
return candidate;
|
|
1408
|
-
}
|
|
1409
|
-
throw new Error("Failed to generate a unique task id (exhausted attempts)");
|
|
1410
|
-
}
|
|
1411
1236
|
async function loadBackendConfig(configPath) {
|
|
1412
1237
|
try {
|
|
1413
1238
|
const raw = JSON.parse(await readFile(configPath, "utf8"));
|
|
@@ -1428,14 +1253,23 @@ function resolveMaybeRelative(root, input) {
|
|
|
1428
1253
|
return null;
|
|
1429
1254
|
return path.isAbsolute(raw) ? raw : path.join(root, raw);
|
|
1430
1255
|
}
|
|
1256
|
+
function normalizeBackendConfig(raw) {
|
|
1257
|
+
if (!isRecord(raw)) {
|
|
1258
|
+
return { id: "local", version: 1, settings: {} };
|
|
1259
|
+
}
|
|
1260
|
+
const id = toStringSafe(raw.id).trim() || "local";
|
|
1261
|
+
const version = typeof raw.version === "number" ? raw.version : 1;
|
|
1262
|
+
const settings = isRecord(raw.settings) ? raw.settings : {};
|
|
1263
|
+
return { id, version, settings };
|
|
1264
|
+
}
|
|
1431
1265
|
export async function loadTaskBackend(opts) {
|
|
1432
1266
|
const resolved = await resolveProject({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null });
|
|
1433
1267
|
const loaded = await loadConfig(resolved.agentplaneDir);
|
|
1434
1268
|
const backendConfigPath = path.join(resolved.gitRoot, loaded.config.tasks_backend.config_path);
|
|
1435
1269
|
const backendConfig = await loadBackendConfig(backendConfigPath);
|
|
1436
|
-
const
|
|
1437
|
-
const backendId =
|
|
1438
|
-
const settings =
|
|
1270
|
+
const normalized = normalizeBackendConfig(backendConfig);
|
|
1271
|
+
const backendId = normalized.id;
|
|
1272
|
+
const settings = normalized.settings;
|
|
1439
1273
|
if (backendId === "redmine") {
|
|
1440
1274
|
await loadDotEnv(resolved.gitRoot);
|
|
1441
1275
|
const cacheDirRaw = resolveMaybeRelative(resolved.gitRoot, settings.cache_dir);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TaskData } from "./task-backend.js";
|
|
2
|
+
export declare const TASK_INDEX_SCHEMA_VERSION = 1;
|
|
3
|
+
export type TaskIndexEntry = {
|
|
4
|
+
task: TaskData;
|
|
5
|
+
readmePath: string;
|
|
6
|
+
mtimeMs: number;
|
|
7
|
+
};
|
|
8
|
+
export type TaskIndexFile = {
|
|
9
|
+
schema_version: 1;
|
|
10
|
+
tasks: TaskIndexEntry[];
|
|
11
|
+
};
|
|
12
|
+
export declare function resolveTaskIndexPath(tasksDir: string): string;
|
|
13
|
+
export declare function loadTaskIndex(indexPath: string): Promise<TaskIndexFile | null>;
|
|
14
|
+
export declare function saveTaskIndex(indexPath: string, index: TaskIndexFile): Promise<void>;
|
|
15
|
+
export declare function buildTaskIndexEntry(task: TaskData, readmePath: string, mtimeMs: number): TaskIndexEntry;
|
|
16
|
+
//# sourceMappingURL=task-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-index.d.ts","sourceRoot":"","sources":["../../src/backends/task-index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAG3C,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,cAAc,EAAE,CAAC,CAAC;IAClB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAU7D;AAuBD,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAkBpF;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1F;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,cAAc,CAMhB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export const TASK_INDEX_SCHEMA_VERSION = 1;
|
|
4
|
+
const TASK_INDEX_FILENAME = "tasks-index.v1.json";
|
|
5
|
+
export function resolveTaskIndexPath(tasksDir) {
|
|
6
|
+
const normalized = path.normalize(tasksDir);
|
|
7
|
+
const parts = normalized.split(path.sep);
|
|
8
|
+
const tail = parts.slice(-2).join(path.sep);
|
|
9
|
+
if (tail === path.join(".agentplane", "tasks")) {
|
|
10
|
+
const cacheDir = path.join(path.dirname(tasksDir), "cache");
|
|
11
|
+
return path.join(cacheDir, TASK_INDEX_FILENAME);
|
|
12
|
+
}
|
|
13
|
+
const cacheDir = path.join(tasksDir, ".cache");
|
|
14
|
+
return path.join(cacheDir, TASK_INDEX_FILENAME);
|
|
15
|
+
}
|
|
16
|
+
function isRecord(value) {
|
|
17
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
18
|
+
}
|
|
19
|
+
function isTaskIndexEntry(value) {
|
|
20
|
+
if (!isRecord(value))
|
|
21
|
+
return false;
|
|
22
|
+
if (!isRecord(value.task))
|
|
23
|
+
return false;
|
|
24
|
+
if (typeof value.readmePath !== "string")
|
|
25
|
+
return false;
|
|
26
|
+
if (typeof value.mtimeMs !== "number")
|
|
27
|
+
return false;
|
|
28
|
+
const task = value.task;
|
|
29
|
+
if (typeof task.id !== "string")
|
|
30
|
+
return false;
|
|
31
|
+
if (typeof task.title !== "string")
|
|
32
|
+
return false;
|
|
33
|
+
if (typeof task.description !== "string")
|
|
34
|
+
return false;
|
|
35
|
+
if (typeof task.status !== "string")
|
|
36
|
+
return false;
|
|
37
|
+
if (typeof task.owner !== "string")
|
|
38
|
+
return false;
|
|
39
|
+
if (!Array.isArray(task.depends_on))
|
|
40
|
+
return false;
|
|
41
|
+
if (!Array.isArray(task.tags))
|
|
42
|
+
return false;
|
|
43
|
+
if (!Array.isArray(task.verify))
|
|
44
|
+
return false;
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
export async function loadTaskIndex(indexPath) {
|
|
48
|
+
let raw = "";
|
|
49
|
+
try {
|
|
50
|
+
raw = await readFile(indexPath, "utf8");
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
let parsed;
|
|
56
|
+
try {
|
|
57
|
+
parsed = JSON.parse(raw);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (!isRecord(parsed))
|
|
63
|
+
return null;
|
|
64
|
+
if (parsed.schema_version !== TASK_INDEX_SCHEMA_VERSION)
|
|
65
|
+
return null;
|
|
66
|
+
if (!Array.isArray(parsed.tasks))
|
|
67
|
+
return null;
|
|
68
|
+
const tasks = parsed.tasks.filter((entry) => isTaskIndexEntry(entry));
|
|
69
|
+
return { schema_version: TASK_INDEX_SCHEMA_VERSION, tasks };
|
|
70
|
+
}
|
|
71
|
+
export async function saveTaskIndex(indexPath, index) {
|
|
72
|
+
const dir = path.dirname(indexPath);
|
|
73
|
+
await mkdir(dir, { recursive: true });
|
|
74
|
+
const tmpPath = `${indexPath}.tmp-${process.pid}`;
|
|
75
|
+
await writeFile(tmpPath, `${JSON.stringify(index, null, 2)}\n`, "utf8");
|
|
76
|
+
await rename(tmpPath, indexPath);
|
|
77
|
+
}
|
|
78
|
+
export function buildTaskIndexEntry(task, readmePath, mtimeMs) {
|
|
79
|
+
return {
|
|
80
|
+
task,
|
|
81
|
+
readmePath,
|
|
82
|
+
mtimeMs,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type ArchiveType = "tar" | "zip";
|
|
2
|
+
export type ArchiveEntryIssue = {
|
|
3
|
+
entry: string;
|
|
4
|
+
reason: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function validateArchive(archivePath: string, type: ArchiveType): Promise<ArchiveEntryIssue[]>;
|
|
7
|
+
export declare function detectArchiveType(filePath: string): ArchiveType | null;
|
|
8
|
+
export declare function extractArchive(opts: {
|
|
9
|
+
archivePath: string;
|
|
10
|
+
destDir: string;
|
|
11
|
+
usage: string;
|
|
12
|
+
example?: string;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
export declare function validateArchiveEntries(entries: string[], symlinks: string[]): ArchiveEntryIssue[];
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=archive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/cli/archive.ts"],"names":[],"mappings":"AAYA,KAAK,WAAW,GAAG,KAAK,GAAG,KAAK,CAAC;AAOjC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAU9B;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAKtE;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhB;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE,CA2BjG"}
|