agentplane 0.1.3 → 0.1.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/README.md +51 -30
- package/dist/run-cli.d.ts.map +1 -1
- package/dist/run-cli.js +32 -9
- package/dist/task-backend.d.ts.map +1 -1
- package/dist/task-backend.js +170 -21
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,53 +5,83 @@
|
|
|
5
5
|
[](https://github.com/basilisk-labs/agentplane/blob/main/LICENSE)
|
|
6
6
|
[](https://github.com/basilisk-labs/agentplane/blob/main/docs/user/prerequisites.mdx)
|
|
7
7
|
|
|
8
|
-
Agent Plane is
|
|
9
|
-
It turns "AI magic" into a predictable process with approvals, role boundaries, and audit-friendly artifacts.
|
|
8
|
+
Agent Plane is a policy-driven framework for running LLM agents inside real repositories. It turns "AI magic" into an engineering process: explicit approvals, role boundaries, and a reproducible execution pipeline. The goal is simple: make agents boring, safe, and auditable.
|
|
10
9
|
|
|
11
|
-
##
|
|
10
|
+
## Why Agent Plane
|
|
12
11
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- Recipes for repeatable setup and automation.
|
|
12
|
+
- You want agents that behave predictably inside real repos.
|
|
13
|
+
- You need human approvals, clear roles, and traceable artifacts.
|
|
14
|
+
- You want guardrails by default, not optional add-ons.
|
|
15
|
+
- You want an offline-first CLI that keeps state local and inspectable.
|
|
18
16
|
|
|
19
|
-
##
|
|
17
|
+
## 5-minute start
|
|
18
|
+
|
|
19
|
+
Install and initialize the CLI:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
npm install -g agentplane
|
|
23
|
+
agentplane init
|
|
24
|
+
agentplane quickstart
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
Create your first task and run the workflow:
|
|
26
28
|
|
|
27
29
|
```bash
|
|
28
|
-
|
|
30
|
+
agentplane task new --title "First task" --description "Describe the change" --priority med --owner ORCHESTRATOR --tag docs
|
|
31
|
+
agentplane verify <task-id>
|
|
32
|
+
agentplane finish <task-id>
|
|
29
33
|
```
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
Prefer `npx` instead of a global install?
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
```bash
|
|
38
|
+
npx agentplane init
|
|
39
|
+
npx agentplane quickstart
|
|
40
|
+
```
|
|
34
41
|
|
|
35
|
-
##
|
|
42
|
+
## What gets installed automatically
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
- `.agentplane/` is created with config, tasks, agents, and caches.
|
|
45
|
+
- `AGENTS.md` is created if missing and defines the policy/guardrails.
|
|
46
|
+
- Built-in agent definitions are copied into `.agentplane/agents/`.
|
|
47
|
+
- Optional recipes can install additional agents when you run `agentplane recipes install ...`.
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
## Guardrails and artifacts
|
|
50
|
+
|
|
51
|
+
- Approval gates for plans and network access (configured in `.agentplane/config.json`).
|
|
52
|
+
- Role boundaries (ORCHESTRATOR, PLANNER, CODER, INTEGRATOR, etc.).
|
|
53
|
+
- Agent definitions in `.agentplane/agents/`.
|
|
54
|
+
- Task records in `.agentplane/tasks/` with a snapshot export in `.agentplane/tasks.json`.
|
|
55
|
+
- A visible, reproducible pipeline:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
Preflight -> Plan -> Approval -> Tasks -> Verify -> Finish -> Export
|
|
41
59
|
```
|
|
42
60
|
|
|
43
|
-
|
|
61
|
+
## Features
|
|
62
|
+
|
|
63
|
+
- Policy-first execution with explicit approvals and guardrails.
|
|
64
|
+
- Role-based workflows for teams: ORCHESTRATOR, PLANNER, CREATOR, INTEGRATOR, etc.
|
|
65
|
+
- Two workflow modes: `direct` (single checkout) and `branch_pr` (worktrees + integration).
|
|
66
|
+
- Task tracking, verification, and exports baked in.
|
|
67
|
+
- Recipes for repeatable setup and automation.
|
|
68
|
+
|
|
69
|
+
## Install
|
|
44
70
|
|
|
45
71
|
```bash
|
|
46
|
-
|
|
72
|
+
npm install -g agentplane
|
|
47
73
|
```
|
|
48
74
|
|
|
49
|
-
|
|
75
|
+
Or run without installing:
|
|
50
76
|
|
|
51
77
|
```bash
|
|
52
|
-
npx agentplane
|
|
78
|
+
npx agentplane --help
|
|
53
79
|
```
|
|
54
80
|
|
|
81
|
+
## Requirements
|
|
82
|
+
|
|
83
|
+
- Node.js >= 20
|
|
84
|
+
|
|
55
85
|
## Common Commands
|
|
56
86
|
|
|
57
87
|
```bash
|
|
@@ -73,15 +103,6 @@ agentplane recipes list
|
|
|
73
103
|
- Project layout: https://github.com/basilisk-labs/agentplane/blob/main/docs/developer/project-layout.mdx
|
|
74
104
|
- Recipes: https://github.com/basilisk-labs/agentplane/tree/main/agentplane-recipes
|
|
75
105
|
|
|
76
|
-
## How it works
|
|
77
|
-
|
|
78
|
-
Agent Plane expects a repository policy file (`AGENTS.md`) plus a project config (`.agentplane/config.json`).
|
|
79
|
-
Together, they define role boundaries, approval gates, and the execution pipeline:
|
|
80
|
-
|
|
81
|
-
```text
|
|
82
|
-
Preflight -> Plan -> Approval -> Tasks -> Verify -> Finish -> Export
|
|
83
|
-
```
|
|
84
|
-
|
|
85
106
|
## Support
|
|
86
107
|
|
|
87
108
|
- Issues: https://github.com/basilisk-labs/agentplane/issues
|
package/dist/run-cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../src/run-cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../src/run-cli.ts"],"names":[],"mappings":"AA69QA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4/D5D"}
|
package/dist/run-cli.js
CHANGED
|
@@ -437,7 +437,7 @@ const BRANCH_STATUS_USAGE_EXAMPLE = "agentplane branch status --base main";
|
|
|
437
437
|
const BRANCH_REMOVE_USAGE = "Usage: agentplane branch remove [--branch <name>] [--worktree <path>] [--force] [--quiet]";
|
|
438
438
|
const BRANCH_REMOVE_USAGE_EXAMPLE = "agentplane branch remove --branch task/20260203-F1Q8AB --worktree .agentplane/worktrees/task";
|
|
439
439
|
const UPGRADE_USAGE = "Usage: agentplane upgrade [--tag <tag>] [--dry-run] [--no-backup] [--source <repo-url>] [--bundle <path|url>] [--checksum <path|url>]";
|
|
440
|
-
const UPGRADE_USAGE_EXAMPLE = "agentplane upgrade --tag v0.1.
|
|
440
|
+
const UPGRADE_USAGE_EXAMPLE = "agentplane upgrade --tag v0.1.4 --dry-run";
|
|
441
441
|
const INIT_USAGE = "Usage: agentplane init --ide <...> --workflow <...> --hooks <...> --require-plan-approval <...> --require-network-approval <...> [--recipes <...>] [--yes] [--force|--backup]";
|
|
442
442
|
const INIT_USAGE_EXAMPLE = "agentplane init --ide codex --workflow direct --hooks false --require-plan-approval true --require-network-approval true --yes";
|
|
443
443
|
const CONFIG_SET_USAGE = "Usage: agentplane config set <key> <value>";
|
|
@@ -3016,7 +3016,7 @@ async function cmdTaskNew(opts) {
|
|
|
3016
3016
|
comments: [],
|
|
3017
3017
|
doc_version: 2,
|
|
3018
3018
|
doc_updated_at: nowIso(),
|
|
3019
|
-
doc_updated_by:
|
|
3019
|
+
doc_updated_by: flags.owner,
|
|
3020
3020
|
id_source: "generated",
|
|
3021
3021
|
};
|
|
3022
3022
|
if (requiresVerify(flags.tags, config.tasks.verify.required_tags) &&
|
|
@@ -3149,6 +3149,7 @@ async function cmdTaskAdd(opts) {
|
|
|
3149
3149
|
const tags = dedupeStrings(flags.tags);
|
|
3150
3150
|
const dependsOn = dedupeStrings(flags.dependsOn);
|
|
3151
3151
|
const verify = dedupeStrings(flags.verify);
|
|
3152
|
+
const docUpdatedBy = (flags.commentAuthor ?? "").trim() || flags.owner;
|
|
3152
3153
|
if (requiresVerify(tags, config.tasks.verify.required_tags) && verify.length === 0) {
|
|
3153
3154
|
throw new CliError({
|
|
3154
3155
|
exitCode: 2,
|
|
@@ -3171,7 +3172,7 @@ async function cmdTaskAdd(opts) {
|
|
|
3171
3172
|
: [],
|
|
3172
3173
|
doc_version: 2,
|
|
3173
3174
|
doc_updated_at: nowIso(),
|
|
3174
|
-
doc_updated_by:
|
|
3175
|
+
doc_updated_by: docUpdatedBy,
|
|
3175
3176
|
id_source: "explicit",
|
|
3176
3177
|
}));
|
|
3177
3178
|
if (backend.writeTasks) {
|
|
@@ -3844,10 +3845,15 @@ async function cmdTaskScaffold(opts) {
|
|
|
3844
3845
|
comments: [],
|
|
3845
3846
|
doc_version: 2,
|
|
3846
3847
|
doc_updated_at: nowIso(),
|
|
3847
|
-
doc_updated_by: "
|
|
3848
|
+
doc_updated_by: "UNKNOWN",
|
|
3848
3849
|
};
|
|
3849
3850
|
if (flags.title)
|
|
3850
3851
|
baseTask.title = flags.title;
|
|
3852
|
+
if (typeof baseTask.doc_updated_by !== "string" ||
|
|
3853
|
+
baseTask.doc_updated_by.trim().length === 0 ||
|
|
3854
|
+
baseTask.doc_updated_by.trim().toLowerCase() === "agentplane") {
|
|
3855
|
+
baseTask.doc_updated_by = baseTask.owner?.trim() ? baseTask.owner : "UNKNOWN";
|
|
3856
|
+
}
|
|
3851
3857
|
const frontmatter = taskDataToFrontmatter(baseTask);
|
|
3852
3858
|
const body = ensureDocSections("", config.tasks.doc.required_sections);
|
|
3853
3859
|
const text = renderTaskReadme(frontmatter, body);
|
|
@@ -3983,7 +3989,7 @@ async function cmdTaskComment(opts) {
|
|
|
3983
3989
|
comments: [...existing, { author: opts.author, body: opts.body }],
|
|
3984
3990
|
doc_version: 2,
|
|
3985
3991
|
doc_updated_at: nowIso(),
|
|
3986
|
-
doc_updated_by:
|
|
3992
|
+
doc_updated_by: opts.author,
|
|
3987
3993
|
};
|
|
3988
3994
|
await backend.writeTask(next);
|
|
3989
3995
|
process.stdout.write(`${successMessage("commented", opts.taskId)}\n`);
|
|
@@ -4086,7 +4092,7 @@ async function cmdTaskSetStatus(opts) {
|
|
|
4086
4092
|
comments,
|
|
4087
4093
|
doc_version: 2,
|
|
4088
4094
|
doc_updated_at: nowIso(),
|
|
4089
|
-
doc_updated_by:
|
|
4095
|
+
doc_updated_by: resolveDocUpdatedBy(task, opts.author),
|
|
4090
4096
|
};
|
|
4091
4097
|
if (opts.commit) {
|
|
4092
4098
|
const commitInfo = await readCommitInfo(resolved.gitRoot, opts.commit);
|
|
@@ -5365,7 +5371,7 @@ async function cmdStart(opts) {
|
|
|
5365
5371
|
comments: commentsValue,
|
|
5366
5372
|
doc_version: 2,
|
|
5367
5373
|
doc_updated_at: nowIso(),
|
|
5368
|
-
doc_updated_by:
|
|
5374
|
+
doc_updated_by: opts.author,
|
|
5369
5375
|
};
|
|
5370
5376
|
await backend.writeTask(nextTask);
|
|
5371
5377
|
let commitInfo = null;
|
|
@@ -5441,7 +5447,7 @@ async function cmdBlock(opts) {
|
|
|
5441
5447
|
comments: commentsValue,
|
|
5442
5448
|
doc_version: 2,
|
|
5443
5449
|
doc_updated_at: nowIso(),
|
|
5444
|
-
doc_updated_by:
|
|
5450
|
+
doc_updated_by: opts.author,
|
|
5445
5451
|
};
|
|
5446
5452
|
await backend.writeTask(nextTask);
|
|
5447
5453
|
let commitInfo = null;
|
|
@@ -5542,7 +5548,7 @@ async function cmdFinish(opts) {
|
|
|
5542
5548
|
comments: commentsValue,
|
|
5543
5549
|
doc_version: 2,
|
|
5544
5550
|
doc_updated_at: nowIso(),
|
|
5545
|
-
doc_updated_by:
|
|
5551
|
+
doc_updated_by: opts.author,
|
|
5546
5552
|
};
|
|
5547
5553
|
await backend.writeTask(nextTask);
|
|
5548
5554
|
}
|
|
@@ -7071,6 +7077,23 @@ function setMarkdownSection(body, section, text) {
|
|
|
7071
7077
|
function normalizeDocSectionName(section) {
|
|
7072
7078
|
return section.trim().replaceAll(/\s+/g, " ").toLowerCase();
|
|
7073
7079
|
}
|
|
7080
|
+
function normalizeDocUpdatedBy(value) {
|
|
7081
|
+
const trimmed = value?.trim() ?? "";
|
|
7082
|
+
if (!trimmed)
|
|
7083
|
+
return "";
|
|
7084
|
+
if (trimmed.toLowerCase() === "agentplane")
|
|
7085
|
+
return "";
|
|
7086
|
+
return trimmed;
|
|
7087
|
+
}
|
|
7088
|
+
function resolveDocUpdatedBy(task, author) {
|
|
7089
|
+
const fromAuthor = normalizeDocUpdatedBy(author);
|
|
7090
|
+
if (fromAuthor)
|
|
7091
|
+
return fromAuthor;
|
|
7092
|
+
const fromTask = normalizeDocUpdatedBy(typeof task.doc_updated_by === "string" ? task.doc_updated_by : undefined);
|
|
7093
|
+
if (fromTask)
|
|
7094
|
+
return fromTask;
|
|
7095
|
+
return normalizeDocUpdatedBy(typeof task.owner === "string" ? task.owner : undefined);
|
|
7096
|
+
}
|
|
7074
7097
|
function splitCombinedHeadingLines(doc) {
|
|
7075
7098
|
const lines = doc.replaceAll("\r\n", "\n").split("\n");
|
|
7076
7099
|
const out = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-backend.d.ts","sourceRoot":"","sources":["../src/task-backend.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"task-backend.d.ts","sourceRoot":"","sources":["../src/task-backend.ts"],"names":[],"mappings":"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"}
|
package/dist/task-backend.js
CHANGED
|
@@ -42,13 +42,158 @@ function normalizeDoc(text) {
|
|
|
42
42
|
.join("\n")
|
|
43
43
|
.trim();
|
|
44
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
|
+
}
|
|
45
174
|
function docChanged(existing, updated) {
|
|
46
175
|
return normalizeDoc(existing) !== normalizeDoc(updated);
|
|
47
176
|
}
|
|
177
|
+
function normalizeUpdatedBy(value) {
|
|
178
|
+
if (typeof value !== "string")
|
|
179
|
+
return "";
|
|
180
|
+
const trimmed = value.trim();
|
|
181
|
+
if (!trimmed)
|
|
182
|
+
return "";
|
|
183
|
+
if (trimmed.toLowerCase() === DEFAULT_DOC_UPDATED_BY.toLowerCase())
|
|
184
|
+
return "";
|
|
185
|
+
return trimmed;
|
|
186
|
+
}
|
|
48
187
|
function ensureDocMetadata(task, updatedBy) {
|
|
49
188
|
task.doc_version = DOC_VERSION;
|
|
50
189
|
task.doc_updated_at = nowIso();
|
|
51
|
-
|
|
190
|
+
const explicit = normalizeUpdatedBy(updatedBy);
|
|
191
|
+
if (updatedBy !== undefined) {
|
|
192
|
+
task.doc_updated_by =
|
|
193
|
+
explicit || resolveDocUpdatedByFromTask(task, DEFAULT_DOC_UPDATED_BY);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
task.doc_updated_by = resolveDocUpdatedByFromTask(task, DEFAULT_DOC_UPDATED_BY);
|
|
52
197
|
}
|
|
53
198
|
function lastCommentAuthor(comments) {
|
|
54
199
|
if (!Array.isArray(comments))
|
|
@@ -69,31 +214,34 @@ function lastCommentAuthor(comments) {
|
|
|
69
214
|
}
|
|
70
215
|
function resolveDocUpdatedByFromFrontmatter(frontmatter, updatedBy, fallback) {
|
|
71
216
|
if (updatedBy !== undefined) {
|
|
72
|
-
const
|
|
73
|
-
|
|
217
|
+
const explicit = normalizeUpdatedBy(updatedBy);
|
|
218
|
+
if (explicit)
|
|
219
|
+
return explicit;
|
|
74
220
|
}
|
|
75
221
|
const author = lastCommentAuthor(frontmatter.comments);
|
|
76
222
|
if (author)
|
|
77
223
|
return author;
|
|
78
|
-
const existing = frontmatter.doc_updated_by;
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
224
|
+
const existing = normalizeUpdatedBy(frontmatter.doc_updated_by);
|
|
225
|
+
if (existing)
|
|
226
|
+
return existing;
|
|
227
|
+
const owner = normalizeUpdatedBy(frontmatter.owner);
|
|
228
|
+
if (owner)
|
|
229
|
+
return owner;
|
|
230
|
+
const fallbackValue = normalizeUpdatedBy(fallback);
|
|
231
|
+
return fallbackValue || fallback;
|
|
85
232
|
}
|
|
86
233
|
function resolveDocUpdatedByFromTask(task, fallback) {
|
|
87
234
|
const author = lastCommentAuthor(task.comments);
|
|
88
235
|
if (author)
|
|
89
236
|
return author;
|
|
90
|
-
const existing = task.doc_updated_by;
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
237
|
+
const existing = normalizeUpdatedBy(task.doc_updated_by);
|
|
238
|
+
if (existing)
|
|
239
|
+
return existing;
|
|
240
|
+
const owner = normalizeUpdatedBy(task.owner);
|
|
241
|
+
if (owner)
|
|
242
|
+
return owner;
|
|
243
|
+
const fallbackValue = normalizeUpdatedBy(fallback);
|
|
244
|
+
return fallbackValue || fallback;
|
|
97
245
|
}
|
|
98
246
|
function isDocSectionHeader(line) {
|
|
99
247
|
return DOC_SECTION_HEADER_RE.test(line.trim());
|
|
@@ -121,10 +269,11 @@ export function extractTaskDoc(body) {
|
|
|
121
269
|
break;
|
|
122
270
|
}
|
|
123
271
|
}
|
|
124
|
-
|
|
272
|
+
const doc = lines.slice(startIdx, endIdx).join("\n").trimEnd();
|
|
273
|
+
return normalizeTaskDoc(doc);
|
|
125
274
|
}
|
|
126
275
|
export function mergeTaskDoc(body, doc) {
|
|
127
|
-
const docText = String(doc ?? "")
|
|
276
|
+
const docText = normalizeTaskDoc(String(doc ?? ""));
|
|
128
277
|
if (docText) {
|
|
129
278
|
const lines = body ? body.split("\n") : [];
|
|
130
279
|
let prefixIdx = null;
|
|
@@ -263,7 +412,7 @@ function taskDataToExport(task) {
|
|
|
263
412
|
: [],
|
|
264
413
|
doc_version: task.doc_version ?? DOC_VERSION,
|
|
265
414
|
doc_updated_at: task.doc_updated_at ?? "",
|
|
266
|
-
doc_updated_by: task
|
|
415
|
+
doc_updated_by: resolveDocUpdatedByFromTask(task, DEFAULT_DOC_UPDATED_BY),
|
|
267
416
|
dirty: Boolean(task.dirty),
|
|
268
417
|
id_source: task.id_source ?? "generated",
|
|
269
418
|
};
|
|
@@ -445,7 +594,7 @@ export class LocalBackend {
|
|
|
445
594
|
payload.doc_updated_at = nowIso();
|
|
446
595
|
}
|
|
447
596
|
if (payload.doc_updated_by === undefined || payload.doc_updated_by === "") {
|
|
448
|
-
payload.doc_updated_by = this.updatedBy;
|
|
597
|
+
payload.doc_updated_by = resolveDocUpdatedByFromTask(task, this.updatedBy);
|
|
449
598
|
}
|
|
450
599
|
await mkdir(path.dirname(readme), { recursive: true });
|
|
451
600
|
const text = renderTaskReadme(payload, body || "");
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentplane",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Agent Plane CLI for task workflows, recipes, and project automation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentplane",
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
"prepublishOnly": "npm run prepack"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@agentplaneorg/core": "0.1.
|
|
57
|
+
"@agentplaneorg/core": "0.1.4"
|
|
58
58
|
}
|
|
59
59
|
}
|