meto-cli 0.7.6 → 0.9.0
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 +61 -8
- package/dist/cli/ai-generator.d.ts.map +1 -1
- package/dist/cli/ai-generator.js +22 -6
- package/dist/cli/ai-generator.js.map +1 -1
- package/dist/cli/index.js +26 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/prompts.d.ts.map +1 -1
- package/dist/cli/prompts.js +20 -0
- package/dist/cli/prompts.js.map +1 -1
- package/dist/cli/renderer.d.ts +14 -2
- package/dist/cli/renderer.d.ts.map +1 -1
- package/dist/cli/renderer.js +90 -1
- package/dist/cli/renderer.js.map +1 -1
- package/dist/cli/status.d.ts +16 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +129 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/swarm-parser.d.ts +60 -0
- package/dist/cli/swarm-parser.d.ts.map +1 -0
- package/dist/cli/swarm-parser.js +237 -0
- package/dist/cli/swarm-parser.js.map +1 -0
- package/dist/cli/swarm.d.ts +48 -0
- package/dist/cli/swarm.d.ts.map +1 -0
- package/dist/cli/swarm.js +101 -0
- package/dist/cli/swarm.js.map +1 -0
- package/dist/cli/types.d.ts +6 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/.claude/agents/epic-agent.md +63 -0
- package/templates/CLAUDE.md +1 -11
- package/templates/ai/swarm/SWARM_AWARENESS.md +62 -0
- package/templates/ai/swarm/domain-map.md +46 -0
- package/templates/ai/workflows/swarm-workflow.md +97 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import * as p from "@clack/prompts";
|
|
4
|
+
import { findProjectRoot } from "./doctor.js";
|
|
5
|
+
import { parseSwarmAwareness } from "./swarm-parser.js";
|
|
6
|
+
/**
|
|
7
|
+
* Checks whether the SWARM_AWARENESS.md file exists at the given project root.
|
|
8
|
+
*/
|
|
9
|
+
export async function swarmFileExists(projectRoot) {
|
|
10
|
+
try {
|
|
11
|
+
await access(join(projectRoot, "ai", "swarm", "SWARM_AWARENESS.md"));
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Calculates the number of days between a start date string and now.
|
|
20
|
+
* Returns the string "unknown" if the date cannot be parsed.
|
|
21
|
+
*/
|
|
22
|
+
function formatDuration(started) {
|
|
23
|
+
const startDate = new Date(started);
|
|
24
|
+
if (isNaN(startDate.getTime())) {
|
|
25
|
+
return "unknown duration";
|
|
26
|
+
}
|
|
27
|
+
const now = new Date();
|
|
28
|
+
const diffMs = now.getTime() - startDate.getTime();
|
|
29
|
+
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
30
|
+
if (diffDays === 0) {
|
|
31
|
+
return "started today";
|
|
32
|
+
}
|
|
33
|
+
if (diffDays === 1) {
|
|
34
|
+
return "1 day";
|
|
35
|
+
}
|
|
36
|
+
return `${diffDays} days`;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Renders the epic list, one line per epic with the appropriate clack log level.
|
|
40
|
+
*/
|
|
41
|
+
function displayEpics(epics) {
|
|
42
|
+
if (epics.length === 0) {
|
|
43
|
+
p.log.warning("No epics found in swarm state.");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
for (const epic of epics) {
|
|
47
|
+
const line = `${epic.id} -- ${epic.name} [${epic.status}] ${epic.tasksDone} tasks done`;
|
|
48
|
+
switch (epic.status) {
|
|
49
|
+
case "complete":
|
|
50
|
+
p.log.success(line);
|
|
51
|
+
break;
|
|
52
|
+
case "on-track":
|
|
53
|
+
p.log.info(line);
|
|
54
|
+
break;
|
|
55
|
+
case "blocked":
|
|
56
|
+
p.log.error(line);
|
|
57
|
+
break;
|
|
58
|
+
case "not-started":
|
|
59
|
+
p.log.warning(line);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Renders the blockers section.
|
|
66
|
+
*/
|
|
67
|
+
function displayBlockers(epics) {
|
|
68
|
+
const blocked = epics.filter((e) => e.status === "blocked");
|
|
69
|
+
if (blocked.length === 0) {
|
|
70
|
+
p.log.success("No blockers");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
for (const epic of blocked) {
|
|
74
|
+
p.log.error(`${epic.id} blocker: ${epic.blocker}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Renders the conflicts section (only if there are pending conflicts).
|
|
79
|
+
*/
|
|
80
|
+
function displayConflicts(state) {
|
|
81
|
+
const pending = state.conflicts.filter((c) => c.resolution === "pending");
|
|
82
|
+
if (pending.length === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
for (const conflict of pending) {
|
|
86
|
+
p.log.warning(`Conflict: ${conflict.file} -- ${conflict.agents} [${conflict.resolution}]`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Formats and displays the full swarm status dashboard.
|
|
91
|
+
*/
|
|
92
|
+
export function displayDashboard(state) {
|
|
93
|
+
const duration = formatDuration(state.meta.started);
|
|
94
|
+
p.note([
|
|
95
|
+
`Project: ${state.meta.projectName}`,
|
|
96
|
+
`Mode: ${state.meta.mode}`,
|
|
97
|
+
`Duration: ${duration}`,
|
|
98
|
+
].join("\n"), "Swarm Dashboard");
|
|
99
|
+
displayEpics(state.epics);
|
|
100
|
+
p.note(`${state.meta.acPassed} of ${state.meta.acTotal} passed`, "Acceptance Criteria");
|
|
101
|
+
displayBlockers(state.epics);
|
|
102
|
+
displayConflicts(state);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Entry point for the `meto-cli status` command.
|
|
106
|
+
* Detects the project root, verifies swarm mode, parses SWARM_AWARENESS.md,
|
|
107
|
+
* and displays the dashboard.
|
|
108
|
+
*/
|
|
109
|
+
export async function runStatus() {
|
|
110
|
+
p.intro("meto-cli status");
|
|
111
|
+
const projectRoot = await findProjectRoot(process.cwd());
|
|
112
|
+
if (projectRoot === undefined) {
|
|
113
|
+
p.log.error("No Meto project found. Run this command from within a Meto-scaffolded project.");
|
|
114
|
+
p.outro("");
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
const hasSwarmFile = await swarmFileExists(projectRoot);
|
|
118
|
+
if (!hasSwarmFile) {
|
|
119
|
+
p.log.error("This project is not using swarm mode. Run 'meto-cli init' with Swarm workflow to enable.");
|
|
120
|
+
p.outro("");
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
const swarmPath = join(projectRoot, "ai", "swarm", "SWARM_AWARENESS.md");
|
|
124
|
+
const content = await readFile(swarmPath, "utf-8");
|
|
125
|
+
const state = parseSwarmAwareness(content);
|
|
126
|
+
displayDashboard(state);
|
|
127
|
+
p.outro("Status complete.");
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsed swarm metadata from the [swarm:meta] section.
|
|
3
|
+
*/
|
|
4
|
+
export interface SwarmMeta {
|
|
5
|
+
projectName: string;
|
|
6
|
+
mode: string;
|
|
7
|
+
started: string;
|
|
8
|
+
totalEpics: number;
|
|
9
|
+
totalTasks: number;
|
|
10
|
+
acPassed: number;
|
|
11
|
+
acTotal: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A single epic row from the [swarm:epics] table.
|
|
15
|
+
*/
|
|
16
|
+
export interface SwarmEpic {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
agent: string;
|
|
20
|
+
status: "not-started" | "on-track" | "blocked" | "complete";
|
|
21
|
+
tasksDone: number;
|
|
22
|
+
blocker: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A single checkpoint entry from the [swarm:checkpoints] section.
|
|
26
|
+
*/
|
|
27
|
+
export interface SwarmCheckpoint {
|
|
28
|
+
date: string;
|
|
29
|
+
epicId: string;
|
|
30
|
+
done: number;
|
|
31
|
+
status: string;
|
|
32
|
+
blocker: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A single conflict entry from the [swarm:conflicts] section.
|
|
36
|
+
*/
|
|
37
|
+
export interface SwarmConflict {
|
|
38
|
+
date: string;
|
|
39
|
+
file: string;
|
|
40
|
+
agents: string;
|
|
41
|
+
resolution: "pending" | "resolved";
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Full parsed state from SWARM_AWARENESS.md.
|
|
45
|
+
*/
|
|
46
|
+
export interface SwarmState {
|
|
47
|
+
meta: SwarmMeta;
|
|
48
|
+
epics: SwarmEpic[];
|
|
49
|
+
checkpoints: SwarmCheckpoint[];
|
|
50
|
+
conflicts: SwarmConflict[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parses the full SWARM_AWARENESS.md content into a typed SwarmState.
|
|
54
|
+
*
|
|
55
|
+
* Uses section header markers (`[swarm:meta]`, `[swarm:epics]`, etc.) to locate
|
|
56
|
+
* each section. Missing or empty sections return sensible defaults (empty arrays,
|
|
57
|
+
* zero counts) rather than throwing.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseSwarmAwareness(content: string): SwarmState;
|
|
60
|
+
//# sourceMappingURL=swarm-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swarm-parser.d.ts","sourceRoot":"","sources":["../../src/cli/swarm-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,SAAS,GAAG,UAAU,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAyQD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAY/D"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Valid epic status values.
|
|
3
|
+
*/
|
|
4
|
+
const VALID_EPIC_STATUSES = new Set([
|
|
5
|
+
"not-started",
|
|
6
|
+
"on-track",
|
|
7
|
+
"blocked",
|
|
8
|
+
"complete",
|
|
9
|
+
]);
|
|
10
|
+
/**
|
|
11
|
+
* Valid conflict resolution values.
|
|
12
|
+
*/
|
|
13
|
+
const VALID_RESOLUTIONS = new Set(["pending", "resolved"]);
|
|
14
|
+
/**
|
|
15
|
+
* Extracts content between a section header marker and the next section or end of file.
|
|
16
|
+
* Section markers are markdown headings like `## [swarm:meta]`.
|
|
17
|
+
*/
|
|
18
|
+
function extractSection(content, sectionName) {
|
|
19
|
+
const marker = `## [swarm:${sectionName}]`;
|
|
20
|
+
const startIndex = content.indexOf(marker);
|
|
21
|
+
if (startIndex === -1) {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
const contentStart = startIndex + marker.length;
|
|
25
|
+
// Find the next ## [swarm: section or end of content
|
|
26
|
+
const nextSectionPattern = /\n## \[swarm:/;
|
|
27
|
+
const remaining = content.slice(contentStart);
|
|
28
|
+
const nextMatch = nextSectionPattern.exec(remaining);
|
|
29
|
+
if (nextMatch !== null) {
|
|
30
|
+
return remaining.slice(0, nextMatch.index).trim();
|
|
31
|
+
}
|
|
32
|
+
return remaining.trim();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parses the [swarm:meta] section as key-value pairs.
|
|
36
|
+
* Lines matching `- **Key:** value` are extracted.
|
|
37
|
+
*/
|
|
38
|
+
function parseMeta(section) {
|
|
39
|
+
const defaults = {
|
|
40
|
+
projectName: "",
|
|
41
|
+
mode: "",
|
|
42
|
+
started: "",
|
|
43
|
+
totalEpics: 0,
|
|
44
|
+
totalTasks: 0,
|
|
45
|
+
acPassed: 0,
|
|
46
|
+
acTotal: 0,
|
|
47
|
+
};
|
|
48
|
+
if (section.length === 0) {
|
|
49
|
+
return defaults;
|
|
50
|
+
}
|
|
51
|
+
const kvPattern = /^- \*\*(.+?):\*\*\s*(.*)$/;
|
|
52
|
+
const lines = section.split("\n");
|
|
53
|
+
for (const line of lines) {
|
|
54
|
+
const match = kvPattern.exec(line.trim());
|
|
55
|
+
if (match === null) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const key = match[1].toLowerCase();
|
|
59
|
+
const value = match[2].trim();
|
|
60
|
+
switch (key) {
|
|
61
|
+
case "project":
|
|
62
|
+
defaults.projectName = value;
|
|
63
|
+
break;
|
|
64
|
+
case "mode":
|
|
65
|
+
defaults.mode = value;
|
|
66
|
+
break;
|
|
67
|
+
case "started":
|
|
68
|
+
defaults.started = value;
|
|
69
|
+
break;
|
|
70
|
+
case "total epics":
|
|
71
|
+
defaults.totalEpics = parseInt(value, 10) || 0;
|
|
72
|
+
break;
|
|
73
|
+
case "total tasks":
|
|
74
|
+
defaults.totalTasks = parseInt(value, 10) || 0;
|
|
75
|
+
break;
|
|
76
|
+
case "acceptance criteria": {
|
|
77
|
+
// Format: "N / M passed"
|
|
78
|
+
const acMatch = /(\d+)\s*\/\s*(\d+)\s*passed/.exec(value);
|
|
79
|
+
if (acMatch !== null) {
|
|
80
|
+
defaults.acPassed = parseInt(acMatch[1], 10) || 0;
|
|
81
|
+
defaults.acTotal = parseInt(acMatch[2], 10) || 0;
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return defaults;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Parses the [swarm:epics] section as a markdown table.
|
|
91
|
+
* Skips the header row and separator row.
|
|
92
|
+
*/
|
|
93
|
+
function parseEpics(section) {
|
|
94
|
+
if (section.length === 0) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
const lines = section.split("\n").filter((line) => line.trim().startsWith("|"));
|
|
98
|
+
// Need at least header + separator + 1 data row
|
|
99
|
+
if (lines.length < 3) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
// Skip header (index 0) and separator (index 1)
|
|
103
|
+
const dataRows = lines.slice(2);
|
|
104
|
+
const epics = [];
|
|
105
|
+
for (const row of dataRows) {
|
|
106
|
+
const cells = row
|
|
107
|
+
.split("|")
|
|
108
|
+
.map((cell) => cell.trim())
|
|
109
|
+
.filter((cell) => cell.length > 0);
|
|
110
|
+
// Expect 6 columns: Epic ID, Name, Agent, Status, Tasks Done, Blocker
|
|
111
|
+
if (cells.length < 6) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const statusRaw = cells[3].toLowerCase();
|
|
115
|
+
const status = VALID_EPIC_STATUSES.has(statusRaw)
|
|
116
|
+
? statusRaw
|
|
117
|
+
: "not-started";
|
|
118
|
+
const tasksDone = parseInt(cells[4], 10) || 0;
|
|
119
|
+
epics.push({
|
|
120
|
+
id: cells[0],
|
|
121
|
+
name: cells[1],
|
|
122
|
+
agent: cells[2],
|
|
123
|
+
status,
|
|
124
|
+
tasksDone,
|
|
125
|
+
blocker: cells[5],
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return epics;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Parses the [swarm:checkpoints] section.
|
|
132
|
+
* Entries are pipe-delimited lines inside a code block.
|
|
133
|
+
*/
|
|
134
|
+
function parseCheckpoints(section) {
|
|
135
|
+
if (section.length === 0) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
// Extract content inside code blocks
|
|
139
|
+
const codeBlockMatch = /```\n?([\s\S]*?)```/.exec(section);
|
|
140
|
+
if (codeBlockMatch === null) {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
const blockContent = codeBlockMatch[1].trim();
|
|
144
|
+
if (blockContent.length === 0) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
const lines = blockContent.split("\n");
|
|
148
|
+
const checkpoints = [];
|
|
149
|
+
for (const line of lines) {
|
|
150
|
+
const parts = line.split("|").map((p) => p.trim());
|
|
151
|
+
// Expect: date | EPIC_ID | done:N | status:X | blocker:X
|
|
152
|
+
if (parts.length < 5) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
// Skip template/example lines
|
|
156
|
+
if (parts[0].startsWith("[")) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const doneMatch = /done:(\d+)/.exec(parts[2]);
|
|
160
|
+
const statusMatch = /status:(.+)/.exec(parts[3]);
|
|
161
|
+
const blockerMatch = /blocker:(.+)/.exec(parts[4]);
|
|
162
|
+
checkpoints.push({
|
|
163
|
+
date: parts[0],
|
|
164
|
+
epicId: parts[1],
|
|
165
|
+
done: doneMatch !== null ? parseInt(doneMatch[1], 10) || 0 : 0,
|
|
166
|
+
status: statusMatch !== null ? statusMatch[1].trim() : "",
|
|
167
|
+
blocker: blockerMatch !== null ? blockerMatch[1].trim() : "none",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return checkpoints;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Parses the [swarm:conflicts] section.
|
|
174
|
+
* Entries are pipe-delimited lines inside a code block.
|
|
175
|
+
*/
|
|
176
|
+
function parseConflicts(section) {
|
|
177
|
+
if (section.length === 0) {
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
const codeBlockMatch = /```\n?([\s\S]*?)```/.exec(section);
|
|
181
|
+
if (codeBlockMatch === null) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
const blockContent = codeBlockMatch[1].trim();
|
|
185
|
+
if (blockContent.length === 0) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
const lines = blockContent.split("\n");
|
|
189
|
+
const conflicts = [];
|
|
190
|
+
for (const line of lines) {
|
|
191
|
+
const parts = line.split("|").map((p) => p.trim());
|
|
192
|
+
// Expect: date | CONFLICT | file:path | agents:X vs Y | resolution:X
|
|
193
|
+
if (parts.length < 5) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
// Skip template/example lines
|
|
197
|
+
if (parts[0].startsWith("[")) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const fileMatch = /file:(.+)/.exec(parts[2]);
|
|
201
|
+
const agentsMatch = /agents:(.+)/.exec(parts[3]);
|
|
202
|
+
const resolutionMatch = /resolution:(.+)/.exec(parts[4]);
|
|
203
|
+
const resolutionRaw = resolutionMatch !== null
|
|
204
|
+
? resolutionMatch[1].trim().toLowerCase()
|
|
205
|
+
: "pending";
|
|
206
|
+
const resolution = VALID_RESOLUTIONS.has(resolutionRaw)
|
|
207
|
+
? resolutionRaw
|
|
208
|
+
: "pending";
|
|
209
|
+
conflicts.push({
|
|
210
|
+
date: parts[0],
|
|
211
|
+
file: fileMatch !== null ? fileMatch[1].trim() : "",
|
|
212
|
+
agents: agentsMatch !== null ? agentsMatch[1].trim() : "",
|
|
213
|
+
resolution,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return conflicts;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Parses the full SWARM_AWARENESS.md content into a typed SwarmState.
|
|
220
|
+
*
|
|
221
|
+
* Uses section header markers (`[swarm:meta]`, `[swarm:epics]`, etc.) to locate
|
|
222
|
+
* each section. Missing or empty sections return sensible defaults (empty arrays,
|
|
223
|
+
* zero counts) rather than throwing.
|
|
224
|
+
*/
|
|
225
|
+
export function parseSwarmAwareness(content) {
|
|
226
|
+
const metaSection = extractSection(content, "meta");
|
|
227
|
+
const epicsSection = extractSection(content, "epics");
|
|
228
|
+
const checkpointsSection = extractSection(content, "checkpoints");
|
|
229
|
+
const conflictsSection = extractSection(content, "conflicts");
|
|
230
|
+
return {
|
|
231
|
+
meta: parseMeta(metaSection),
|
|
232
|
+
epics: parseEpics(epicsSection),
|
|
233
|
+
checkpoints: parseCheckpoints(checkpointsSection),
|
|
234
|
+
conflicts: parseConflicts(conflictsSection),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=swarm-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swarm-parser.js","sourceRoot":"","sources":["../../src/cli/swarm-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { RenderedFile } from "./renderer.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parsed epic extracted from epics markdown content.
|
|
4
|
+
*/
|
|
5
|
+
interface ParsedEpic {
|
|
6
|
+
/** Epic ID, e.g. "E1" */
|
|
7
|
+
id: string;
|
|
8
|
+
/** Epic name, e.g. "Project Setup" */
|
|
9
|
+
name: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parses epic IDs and names from markdown-formatted epics content.
|
|
13
|
+
* Expects headings in the format: `## E1 -- Epic Name`
|
|
14
|
+
*
|
|
15
|
+
* @param epicsContent - Markdown string containing epic definitions
|
|
16
|
+
* @returns Array of parsed epics with id and name
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseEpics(epicsContent: string): ParsedEpic[];
|
|
19
|
+
/**
|
|
20
|
+
* Generates rendered epic-agent files from the epic-agent template.
|
|
21
|
+
* One `.claude/agents/epic-agent-E[N].md` file is created per epic,
|
|
22
|
+
* with {{EPIC_ID}}, {{EPIC_NAME}}, and {{EPIC_DOMAIN}} tokens replaced.
|
|
23
|
+
*
|
|
24
|
+
* Also generates a corresponding memory file per epic:
|
|
25
|
+
* `.claude/agent-memory/meto-epic-E[N]/MEMORY.md`
|
|
26
|
+
*
|
|
27
|
+
* @param epicsContent - Markdown string containing epic definitions
|
|
28
|
+
* @param templateContent - Raw content of the epic-agent.md template
|
|
29
|
+
* @returns Array of rendered files (agent definitions + memory files)
|
|
30
|
+
*/
|
|
31
|
+
export declare function generateEpicAgents(epicsContent: string, templateContent: string): RenderedFile[];
|
|
32
|
+
/**
|
|
33
|
+
* Reads the epic-agent template from the templates directory.
|
|
34
|
+
*
|
|
35
|
+
* @param templatesDir - Absolute path to the templates directory
|
|
36
|
+
* @returns Raw template content
|
|
37
|
+
*/
|
|
38
|
+
export declare function readEpicAgentTemplate(templatesDir: string): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Generates a settings.json content with epic agent entries.
|
|
41
|
+
* Merges the base settings with agent file references for swarm mode.
|
|
42
|
+
*
|
|
43
|
+
* @param epicIds - Array of epic IDs (e.g. ["E1", "E2", "E3"])
|
|
44
|
+
* @returns Formatted JSON string for .claude/settings.json
|
|
45
|
+
*/
|
|
46
|
+
export declare function generateSwarmSettings(epicIds: string[]): string;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=swarm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swarm.d.ts","sourceRoot":"","sources":["../../src/cli/swarm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;GAEG;AACH,UAAU,UAAU;IAClB,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,EAAE,CAa7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GACtB,YAAY,EAAE,CAyChB;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAW/D"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { replaceTokens } from "./renderer.js";
|
|
4
|
+
/**
|
|
5
|
+
* Parses epic IDs and names from markdown-formatted epics content.
|
|
6
|
+
* Expects headings in the format: `## E1 -- Epic Name`
|
|
7
|
+
*
|
|
8
|
+
* @param epicsContent - Markdown string containing epic definitions
|
|
9
|
+
* @returns Array of parsed epics with id and name
|
|
10
|
+
*/
|
|
11
|
+
export function parseEpics(epicsContent) {
|
|
12
|
+
const epicPattern = /^## (E\d+) -- (.+)$/gm;
|
|
13
|
+
const epics = [];
|
|
14
|
+
let match;
|
|
15
|
+
while ((match = epicPattern.exec(epicsContent)) !== null) {
|
|
16
|
+
epics.push({
|
|
17
|
+
id: match[1],
|
|
18
|
+
name: match[2].trim(),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return epics;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generates rendered epic-agent files from the epic-agent template.
|
|
25
|
+
* One `.claude/agents/epic-agent-E[N].md` file is created per epic,
|
|
26
|
+
* with {{EPIC_ID}}, {{EPIC_NAME}}, and {{EPIC_DOMAIN}} tokens replaced.
|
|
27
|
+
*
|
|
28
|
+
* Also generates a corresponding memory file per epic:
|
|
29
|
+
* `.claude/agent-memory/meto-epic-E[N]/MEMORY.md`
|
|
30
|
+
*
|
|
31
|
+
* @param epicsContent - Markdown string containing epic definitions
|
|
32
|
+
* @param templateContent - Raw content of the epic-agent.md template
|
|
33
|
+
* @returns Array of rendered files (agent definitions + memory files)
|
|
34
|
+
*/
|
|
35
|
+
export function generateEpicAgents(epicsContent, templateContent) {
|
|
36
|
+
const epics = parseEpics(epicsContent);
|
|
37
|
+
const rendered = [];
|
|
38
|
+
for (const epic of epics) {
|
|
39
|
+
const tokens = {
|
|
40
|
+
EPIC_ID: epic.id,
|
|
41
|
+
EPIC_NAME: epic.name,
|
|
42
|
+
EPIC_DOMAIN: "to be assigned by @meto-pm",
|
|
43
|
+
};
|
|
44
|
+
const agentContent = replaceTokens(templateContent, tokens);
|
|
45
|
+
rendered.push({
|
|
46
|
+
relativePath: `.claude/agents/epic-agent-${epic.id}.md`,
|
|
47
|
+
content: agentContent,
|
|
48
|
+
});
|
|
49
|
+
const memoryContent = [
|
|
50
|
+
`# Epic Agent Memory -- ${epic.name} (${epic.id})`,
|
|
51
|
+
"",
|
|
52
|
+
"*Read at session start. Update at session end. Keep it concise.*",
|
|
53
|
+
"",
|
|
54
|
+
"---",
|
|
55
|
+
"",
|
|
56
|
+
"## Current State",
|
|
57
|
+
"- **Status:** not-started",
|
|
58
|
+
"- **Tasks completed:** 0",
|
|
59
|
+
"- **Checkpoint count:** 0",
|
|
60
|
+
"",
|
|
61
|
+
"## Session Log",
|
|
62
|
+
"*(no sessions yet)*",
|
|
63
|
+
"",
|
|
64
|
+
].join("\n");
|
|
65
|
+
rendered.push({
|
|
66
|
+
relativePath: `.claude/agent-memory/meto-epic-${epic.id}/MEMORY.md`,
|
|
67
|
+
content: memoryContent,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return rendered;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Reads the epic-agent template from the templates directory.
|
|
74
|
+
*
|
|
75
|
+
* @param templatesDir - Absolute path to the templates directory
|
|
76
|
+
* @returns Raw template content
|
|
77
|
+
*/
|
|
78
|
+
export async function readEpicAgentTemplate(templatesDir) {
|
|
79
|
+
const templatePath = join(templatesDir, ".claude", "agents", "epic-agent.md");
|
|
80
|
+
return readFile(templatePath, "utf-8");
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Generates a settings.json content with epic agent entries.
|
|
84
|
+
* Merges the base settings with agent file references for swarm mode.
|
|
85
|
+
*
|
|
86
|
+
* @param epicIds - Array of epic IDs (e.g. ["E1", "E2", "E3"])
|
|
87
|
+
* @returns Formatted JSON string for .claude/settings.json
|
|
88
|
+
*/
|
|
89
|
+
export function generateSwarmSettings(epicIds) {
|
|
90
|
+
const settings = {
|
|
91
|
+
env: {
|
|
92
|
+
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1",
|
|
93
|
+
},
|
|
94
|
+
agents: epicIds.map((id) => ({
|
|
95
|
+
slug: `meto-epic-${id.toLowerCase()}`,
|
|
96
|
+
file: `.claude/agents/epic-agent-${id}.md`,
|
|
97
|
+
})),
|
|
98
|
+
};
|
|
99
|
+
return JSON.stringify(settings, null, 2) + "\n";
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=swarm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swarm.js","sourceRoot":"","sources":["../../src/cli/swarm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAa9C;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,YAAoB;IAC7C,MAAM,WAAW,GAAG,uBAAuB,CAAC;IAC5C,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,IAAI,KAA6B,CAAC;IAElC,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACzD,KAAK,CAAC,IAAI,CAAC;YACT,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;YACZ,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;SACtB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAChC,YAAoB,EACpB,eAAuB;IAEvB,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG;YACb,OAAO,EAAE,IAAI,CAAC,EAAE;YAChB,SAAS,EAAE,IAAI,CAAC,IAAI;YACpB,WAAW,EAAE,4BAA4B;SAC1C,CAAC;QAEF,MAAM,YAAY,GAAG,aAAa,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QAC5D,QAAQ,CAAC,IAAI,CAAC;YACZ,YAAY,EAAE,6BAA6B,IAAI,CAAC,EAAE,KAAK;YACvD,OAAO,EAAE,YAAY;SACtB,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG;YACpB,0BAA0B,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,GAAG;YAClD,EAAE;YACF,kEAAkE;YAClE,EAAE;YACF,KAAK;YACL,EAAE;YACF,kBAAkB;YAClB,2BAA2B;YAC3B,0BAA0B;YAC1B,2BAA2B;YAC3B,EAAE;YACF,gBAAgB;YAChB,qBAAqB;YACrB,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,QAAQ,CAAC,IAAI,CAAC;YACZ,YAAY,EAAE,kCAAkC,IAAI,CAAC,EAAE,YAAY;YACnE,OAAO,EAAE,aAAa;SACvB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,YAAoB;IAEpB,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;IAC9E,OAAO,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAiB;IACrD,MAAM,QAAQ,GAA4B;QACxC,GAAG,EAAE;YACH,oCAAoC,EAAE,GAAG;SAC1C;QACD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,aAAa,EAAE,CAAC,WAAW,EAAE,EAAE;YACrC,IAAI,EAAE,6BAA6B,EAAE,KAAK;SAC3C,CAAC,CAAC;KACJ,CAAC;IACF,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAClD,CAAC"}
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Tech stack presets available during project scaffolding.
|
|
3
3
|
*/
|
|
4
4
|
export type TechStack = "nextjs-supabase" | "react-native" | "nodejs-cli" | "python-fastapi" | "go" | "vite-react" | "flutter" | "custom";
|
|
5
|
+
/**
|
|
6
|
+
* Workflow mode: sprint (sequential) or swarm (parallel epic agents).
|
|
7
|
+
*/
|
|
8
|
+
export type WorkflowMode = "sprint" | "swarm";
|
|
5
9
|
/**
|
|
6
10
|
* The brief collected from the user during `meto-cli init`.
|
|
7
11
|
* Contains everything needed to render templates and scaffold a project.
|
|
@@ -29,5 +33,7 @@ export interface ProjectBrief {
|
|
|
29
33
|
codeConventions: string;
|
|
30
34
|
/** Absolute or relative path where the scaffold will be written */
|
|
31
35
|
outputDirectory: string;
|
|
36
|
+
/** Workflow mode: sprint (sequential) or swarm (parallel epic agents) */
|
|
37
|
+
workflowMode: WorkflowMode;
|
|
32
38
|
}
|
|
33
39
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/cli/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB,iBAAiB,GACjB,cAAc,GACd,YAAY,GACZ,gBAAgB,GAChB,IAAI,GACJ,YAAY,GACZ,SAAS,GACT,QAAQ,CAAC;AAEb;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,SAAS,EAAE,SAAS,CAAC;IACrB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,uCAAuC;IACvC,gBAAgB,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,eAAe,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB,iBAAiB,GACjB,cAAc,GACd,YAAY,GACZ,gBAAgB,GAChB,IAAI,GACJ,YAAY,GACZ,SAAS,GACT,QAAQ,CAAC;AAEb;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9C;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,SAAS,EAAE,SAAS,CAAC;IACrB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,uCAAuC;IACvC,gBAAgB,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,YAAY,EAAE,YAAY,CAAC;CAC5B"}
|