@byrde/cursor 0.1.1
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 +116 -0
- package/assets/agents/architect.md +128 -0
- package/assets/agents/developer.md +84 -0
- package/assets/agents/planner.md +59 -0
- package/assets/agents/tester.md +77 -0
- package/assets/rules/global.mdc +180 -0
- package/assets/rules/init.mdc +26 -0
- package/assets/templates/backlog.md +18 -0
- package/assets/templates/design.md +25 -0
- package/assets/templates/overview.md +38 -0
- package/assets/templates/testability/README.md +102 -0
- package/dist/cli.js +1241 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +155 -0
- package/dist/index.js +465 -0
- package/dist/index.js.map +1 -0
- package/dist/sync-workflow.js +237 -0
- package/dist/sync-workflow.js.map +1 -0
- package/package.json +53 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
// src/domain/asset-manifest.ts
|
|
2
|
+
var DEFAULT_MANIFEST = [
|
|
3
|
+
{
|
|
4
|
+
source: "assets/agents/architect.md",
|
|
5
|
+
target: "agents/architect.md",
|
|
6
|
+
renderAgent: "architect"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
source: "assets/agents/developer.md",
|
|
10
|
+
target: "agents/developer.md",
|
|
11
|
+
renderAgent: "developer"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
source: "assets/agents/planner.md",
|
|
15
|
+
target: "agents/planner.md",
|
|
16
|
+
renderAgent: "planner"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
source: "assets/agents/tester.md",
|
|
20
|
+
target: "agents/tester.md",
|
|
21
|
+
renderAgent: "tester"
|
|
22
|
+
},
|
|
23
|
+
{ source: "assets/rules/global.mdc", target: "rules/global.mdc" },
|
|
24
|
+
{ source: "assets/rules/init.mdc", target: "rules/init.mdc" },
|
|
25
|
+
{ source: "assets/templates/backlog.md", target: "templates/backlog.md" },
|
|
26
|
+
{ source: "assets/templates/design.md", target: "templates/design.md" },
|
|
27
|
+
{ source: "assets/templates/overview.md", target: "templates/overview.md" },
|
|
28
|
+
{
|
|
29
|
+
source: "assets/templates/testability/README.md",
|
|
30
|
+
target: "templates/testability/README.md"
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// src/domain/backlog/types.ts
|
|
35
|
+
var TASK_STATUS_VALUES = [
|
|
36
|
+
"TODO",
|
|
37
|
+
"In Progress",
|
|
38
|
+
"Ready to Test",
|
|
39
|
+
"Complete"
|
|
40
|
+
];
|
|
41
|
+
var DEFAULT_TASK_PRIORITY = 1e3;
|
|
42
|
+
|
|
43
|
+
// src/domain/config.ts
|
|
44
|
+
function createDefaultWorkflowModels() {
|
|
45
|
+
return {
|
|
46
|
+
planner: "gpt-5.4-high",
|
|
47
|
+
architect: "gpt-5.4-high",
|
|
48
|
+
developer: "composer-2-fast",
|
|
49
|
+
tester: "composer-2-fast"
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function createDefaultProjectConfig() {
|
|
53
|
+
return {
|
|
54
|
+
backlog: {
|
|
55
|
+
provider: "file",
|
|
56
|
+
file: {
|
|
57
|
+
path: "docs/backlog.md"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
workflow: {
|
|
61
|
+
defaults: {
|
|
62
|
+
architectReview: "required",
|
|
63
|
+
testing: "required"
|
|
64
|
+
},
|
|
65
|
+
models: createDefaultWorkflowModels()
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
var DEFAULT_PROJECT_CONFIG = createDefaultProjectConfig();
|
|
70
|
+
function isNonEmptyString(v) {
|
|
71
|
+
return typeof v === "string" && v.trim().length > 0;
|
|
72
|
+
}
|
|
73
|
+
function normalizeBacklog(raw, base) {
|
|
74
|
+
if (!raw || typeof raw !== "object") {
|
|
75
|
+
return base;
|
|
76
|
+
}
|
|
77
|
+
const b = raw;
|
|
78
|
+
const provider = b.provider === "github-issues" || b.provider === "file" ? b.provider : base.provider;
|
|
79
|
+
if (provider === "file") {
|
|
80
|
+
const fileRaw = b.file;
|
|
81
|
+
const pathFrom = fileRaw && typeof fileRaw === "object" && isNonEmptyString(fileRaw.path) ? String(fileRaw.path).trim() : base.file.path;
|
|
82
|
+
return { provider: "file", file: { path: pathFrom } };
|
|
83
|
+
}
|
|
84
|
+
const ghRaw = b["github-issues"];
|
|
85
|
+
const githubOptionalDefaults = {
|
|
86
|
+
priorityField: "Priority",
|
|
87
|
+
statusField: "Status",
|
|
88
|
+
mcpServerName: "github"
|
|
89
|
+
};
|
|
90
|
+
function parsePositiveInt(v) {
|
|
91
|
+
if (typeof v === "number" && Number.isFinite(v) && v > 0) {
|
|
92
|
+
return Math.trunc(v);
|
|
93
|
+
}
|
|
94
|
+
if (isNonEmptyString(v)) {
|
|
95
|
+
const n = Number.parseInt(String(v).trim(), 10);
|
|
96
|
+
if (Number.isFinite(n) && n > 0) {
|
|
97
|
+
return n;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return void 0;
|
|
101
|
+
}
|
|
102
|
+
if (ghRaw && typeof ghRaw === "object") {
|
|
103
|
+
const g = ghRaw;
|
|
104
|
+
const repository = isNonEmptyString(g.repository) ? g.repository.trim() : void 0;
|
|
105
|
+
const projectNumber = parsePositiveInt(g.projectNumber);
|
|
106
|
+
if (repository !== void 0 && projectNumber !== void 0) {
|
|
107
|
+
const priorityField = isNonEmptyString(g.priorityField) ? g.priorityField.trim() : githubOptionalDefaults.priorityField;
|
|
108
|
+
const statusField = isNonEmptyString(g.statusField) ? g.statusField.trim() : githubOptionalDefaults.statusField;
|
|
109
|
+
const labelRaw = g.label;
|
|
110
|
+
const label = isNonEmptyString(labelRaw) ? labelRaw.trim() : void 0;
|
|
111
|
+
return {
|
|
112
|
+
provider: "github-issues",
|
|
113
|
+
"github-issues": {
|
|
114
|
+
repository,
|
|
115
|
+
projectNumber,
|
|
116
|
+
projectOwner: isNonEmptyString(g.projectOwner) ? g.projectOwner.trim() : void 0,
|
|
117
|
+
priorityField,
|
|
118
|
+
statusField,
|
|
119
|
+
...label !== void 0 ? { label } : {},
|
|
120
|
+
mcpServerName: isNonEmptyString(g.mcpServerName) ? g.mcpServerName.trim() : githubOptionalDefaults.mcpServerName
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return base;
|
|
126
|
+
}
|
|
127
|
+
function normalizeWorkflow(raw, base) {
|
|
128
|
+
const models = { ...base.models };
|
|
129
|
+
let architectReview = base.defaults.architectReview;
|
|
130
|
+
let testing = base.defaults.testing;
|
|
131
|
+
if (raw && typeof raw === "object") {
|
|
132
|
+
const w = raw;
|
|
133
|
+
const d = w.defaults;
|
|
134
|
+
if (d && typeof d === "object") {
|
|
135
|
+
const def = d;
|
|
136
|
+
if (def.architectReview === "required" || def.architectReview === "optional") {
|
|
137
|
+
architectReview = def.architectReview;
|
|
138
|
+
}
|
|
139
|
+
if (def.testing === "required" || def.testing === "optional") {
|
|
140
|
+
testing = def.testing;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const m = w.models;
|
|
144
|
+
if (m && typeof m === "object") {
|
|
145
|
+
const mo = m;
|
|
146
|
+
const pick = (key) => {
|
|
147
|
+
const v = mo[key];
|
|
148
|
+
return isNonEmptyString(v) ? v.trim() : base.models[key];
|
|
149
|
+
};
|
|
150
|
+
models.planner = pick("planner");
|
|
151
|
+
models.architect = pick("architect");
|
|
152
|
+
models.developer = pick("developer");
|
|
153
|
+
models.tester = pick("tester");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
defaults: { architectReview, testing },
|
|
158
|
+
models
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function normalizeProjectConfig(raw) {
|
|
162
|
+
const base = createDefaultProjectConfig();
|
|
163
|
+
if (!raw || typeof raw !== "object") {
|
|
164
|
+
return base;
|
|
165
|
+
}
|
|
166
|
+
const o = raw;
|
|
167
|
+
return {
|
|
168
|
+
backlog: normalizeBacklog(o.backlog, base.backlog),
|
|
169
|
+
workflow: normalizeWorkflow(o.workflow, base.workflow)
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/infrastructure/file-backlog-provider.ts
|
|
174
|
+
import { readFile, writeFile } from "fs/promises";
|
|
175
|
+
import path from "path";
|
|
176
|
+
var LEGACY_COLUMN_ORDER = [
|
|
177
|
+
"Epic",
|
|
178
|
+
"Task Description",
|
|
179
|
+
"Acceptance Criteria",
|
|
180
|
+
"Status",
|
|
181
|
+
"Prototype",
|
|
182
|
+
"Notes"
|
|
183
|
+
];
|
|
184
|
+
var COLUMN_ORDER = [
|
|
185
|
+
"Epic",
|
|
186
|
+
"Priority",
|
|
187
|
+
"Task Description",
|
|
188
|
+
"Acceptance Criteria",
|
|
189
|
+
"Status",
|
|
190
|
+
"Prototype",
|
|
191
|
+
"Notes"
|
|
192
|
+
];
|
|
193
|
+
function isTaskStatus(value) {
|
|
194
|
+
return TASK_STATUS_VALUES.includes(value);
|
|
195
|
+
}
|
|
196
|
+
function normalizeStatus(raw) {
|
|
197
|
+
const stripped = raw.replace(/^`|`$/g, "").trim();
|
|
198
|
+
if (!isTaskStatus(stripped)) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`Invalid task status "${stripped}" (expected one of: ${TASK_STATUS_VALUES.join(", ")})`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
return stripped;
|
|
204
|
+
}
|
|
205
|
+
function formatStatus(status) {
|
|
206
|
+
return `\`${status}\``;
|
|
207
|
+
}
|
|
208
|
+
function parsePriorityCell(raw) {
|
|
209
|
+
const t = raw.replace(/^`|`$/g, "").trim();
|
|
210
|
+
if (!t.length) {
|
|
211
|
+
return DEFAULT_TASK_PRIORITY;
|
|
212
|
+
}
|
|
213
|
+
const n = Number.parseInt(t, 10);
|
|
214
|
+
return Number.isFinite(n) ? n : DEFAULT_TASK_PRIORITY;
|
|
215
|
+
}
|
|
216
|
+
function formatPriority(priority) {
|
|
217
|
+
return String(priority);
|
|
218
|
+
}
|
|
219
|
+
function splitMarkdownRow(line) {
|
|
220
|
+
const trimmed = line.trim();
|
|
221
|
+
if (!trimmed.startsWith("|") || !trimmed.endsWith("|")) {
|
|
222
|
+
throw new Error(`Invalid backlog table row: ${line}`);
|
|
223
|
+
}
|
|
224
|
+
return trimmed.slice(1, -1).split("|").map((cell) => cell.trim());
|
|
225
|
+
}
|
|
226
|
+
function headerMatches(cells, expected) {
|
|
227
|
+
if (cells.length !== expected.length) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
return expected.every((name, i) => cells[i] === name);
|
|
231
|
+
}
|
|
232
|
+
function parseBacklogDocument(content) {
|
|
233
|
+
const lines = content.split(/\r?\n/);
|
|
234
|
+
const tableStart = lines.findIndex((line, index) => {
|
|
235
|
+
return line.trim().startsWith("|") && lines[index + 1]?.trim().startsWith("|");
|
|
236
|
+
});
|
|
237
|
+
if (tableStart < 0) {
|
|
238
|
+
throw new Error("Could not find backlog markdown table.");
|
|
239
|
+
}
|
|
240
|
+
let tableEnd = tableStart;
|
|
241
|
+
while (tableEnd < lines.length && lines[tableEnd].trim().startsWith("|")) {
|
|
242
|
+
tableEnd += 1;
|
|
243
|
+
}
|
|
244
|
+
const headerCells = splitMarkdownRow(lines[tableStart]);
|
|
245
|
+
let variant;
|
|
246
|
+
let columnNames;
|
|
247
|
+
if (headerMatches(headerCells, COLUMN_ORDER)) {
|
|
248
|
+
variant = "withPriority";
|
|
249
|
+
columnNames = COLUMN_ORDER;
|
|
250
|
+
} else if (headerMatches(headerCells, LEGACY_COLUMN_ORDER)) {
|
|
251
|
+
variant = "legacy";
|
|
252
|
+
columnNames = LEGACY_COLUMN_ORDER;
|
|
253
|
+
} else {
|
|
254
|
+
throw new Error(
|
|
255
|
+
"Unexpected backlog table header (expected Epic + Priority + \u2026 or legacy Epic + Task Description + \u2026)."
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
const rowLines = lines.slice(tableStart + 2, tableEnd);
|
|
259
|
+
const rows = rowLines.map((line, rowIndex) => {
|
|
260
|
+
const cells = splitMarkdownRow(line);
|
|
261
|
+
if (cells.length !== columnNames.length) {
|
|
262
|
+
throw new Error(`Unexpected backlog row width at row ${rowIndex + 1}.`);
|
|
263
|
+
}
|
|
264
|
+
if (variant === "legacy") {
|
|
265
|
+
const legacyCells = Object.fromEntries(
|
|
266
|
+
LEGACY_COLUMN_ORDER.map((column, columnIndex) => [
|
|
267
|
+
column,
|
|
268
|
+
cells[columnIndex]
|
|
269
|
+
])
|
|
270
|
+
);
|
|
271
|
+
const full = {
|
|
272
|
+
Epic: legacyCells.Epic,
|
|
273
|
+
Priority: formatPriority(DEFAULT_TASK_PRIORITY),
|
|
274
|
+
"Task Description": legacyCells["Task Description"],
|
|
275
|
+
"Acceptance Criteria": legacyCells["Acceptance Criteria"],
|
|
276
|
+
Status: legacyCells.Status,
|
|
277
|
+
Prototype: legacyCells.Prototype,
|
|
278
|
+
Notes: legacyCells.Notes
|
|
279
|
+
};
|
|
280
|
+
return {
|
|
281
|
+
id: `backlog-${rowIndex + 1}`,
|
|
282
|
+
cells: full
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const withP = Object.fromEntries(
|
|
286
|
+
COLUMN_ORDER.map((column, columnIndex) => [column, cells[columnIndex]])
|
|
287
|
+
);
|
|
288
|
+
return {
|
|
289
|
+
id: `backlog-${rowIndex + 1}`,
|
|
290
|
+
cells: withP
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
return {
|
|
294
|
+
variant,
|
|
295
|
+
beforeTable: lines.slice(0, tableStart),
|
|
296
|
+
rows,
|
|
297
|
+
afterTable: lines.slice(tableEnd)
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function renderTable(rows, variant) {
|
|
301
|
+
if (variant === "legacy") {
|
|
302
|
+
const bodyRows2 = rows.map(
|
|
303
|
+
(row) => LEGACY_COLUMN_ORDER.map((column) => {
|
|
304
|
+
if (column === "Epic") {
|
|
305
|
+
return row.cells.Epic;
|
|
306
|
+
}
|
|
307
|
+
if (column === "Task Description") {
|
|
308
|
+
return row.cells["Task Description"];
|
|
309
|
+
}
|
|
310
|
+
if (column === "Acceptance Criteria") {
|
|
311
|
+
return row.cells["Acceptance Criteria"];
|
|
312
|
+
}
|
|
313
|
+
if (column === "Status") {
|
|
314
|
+
return row.cells.Status;
|
|
315
|
+
}
|
|
316
|
+
if (column === "Prototype") {
|
|
317
|
+
return row.cells.Prototype;
|
|
318
|
+
}
|
|
319
|
+
return row.cells.Notes;
|
|
320
|
+
})
|
|
321
|
+
);
|
|
322
|
+
const widths2 = LEGACY_COLUMN_ORDER.map(
|
|
323
|
+
(column, index) => Math.max(
|
|
324
|
+
column.length,
|
|
325
|
+
...bodyRows2.map((cells) => cells[index]?.length ?? 0)
|
|
326
|
+
)
|
|
327
|
+
);
|
|
328
|
+
const renderRow2 = (cells) => `| ${cells.map((cell, index) => cell.padEnd(widths2[index])).join(" | ")} |`;
|
|
329
|
+
const separator2 = `| ${widths2.map((width) => "-".repeat(width)).join(" | ")} |`;
|
|
330
|
+
return [
|
|
331
|
+
renderRow2(LEGACY_COLUMN_ORDER),
|
|
332
|
+
separator2,
|
|
333
|
+
...bodyRows2.map(renderRow2)
|
|
334
|
+
];
|
|
335
|
+
}
|
|
336
|
+
const bodyRows = rows.map((row) => COLUMN_ORDER.map((column) => row.cells[column]));
|
|
337
|
+
const widths = COLUMN_ORDER.map(
|
|
338
|
+
(column, index) => Math.max(
|
|
339
|
+
column.length,
|
|
340
|
+
...bodyRows.map((cells) => cells[index]?.length ?? 0)
|
|
341
|
+
)
|
|
342
|
+
);
|
|
343
|
+
const renderRow = (cells) => `| ${cells.map((cell, index) => cell.padEnd(widths[index])).join(" | ")} |`;
|
|
344
|
+
const separator = `| ${widths.map((width) => "-".repeat(width)).join(" | ")} |`;
|
|
345
|
+
return [renderRow(COLUMN_ORDER), separator, ...bodyRows.map(renderRow)];
|
|
346
|
+
}
|
|
347
|
+
function toTask(row) {
|
|
348
|
+
return {
|
|
349
|
+
id: row.id,
|
|
350
|
+
epic: row.cells.Epic,
|
|
351
|
+
priority: parsePriorityCell(row.cells.Priority),
|
|
352
|
+
description: row.cells["Task Description"],
|
|
353
|
+
acceptanceCriteria: row.cells["Acceptance Criteria"],
|
|
354
|
+
status: normalizeStatus(row.cells.Status),
|
|
355
|
+
prototype: row.cells.Prototype,
|
|
356
|
+
notes: row.cells.Notes
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function sortTasksForList(tasks) {
|
|
360
|
+
return [...tasks].sort((a, b) => {
|
|
361
|
+
if (a.priority !== b.priority) {
|
|
362
|
+
return a.priority - b.priority;
|
|
363
|
+
}
|
|
364
|
+
const ai = Number.parseInt(a.id.replace(/^backlog-/, ""), 10);
|
|
365
|
+
const bi = Number.parseInt(b.id.replace(/^backlog-/, ""), 10);
|
|
366
|
+
return ai - bi;
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
function applyFilter(tasks, filter) {
|
|
370
|
+
if (!filter) {
|
|
371
|
+
return [...tasks];
|
|
372
|
+
}
|
|
373
|
+
return tasks.filter((task) => {
|
|
374
|
+
if (filter.status && task.status !== filter.status) {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
if (filter.epic && task.epic !== filter.epic) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
return true;
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
var FileBacklogProvider = class {
|
|
384
|
+
constructor(backlogPath) {
|
|
385
|
+
this.backlogPath = backlogPath;
|
|
386
|
+
}
|
|
387
|
+
async listTasks(filter) {
|
|
388
|
+
const doc = await this.readDocument();
|
|
389
|
+
const tasks = doc.rows.map(toTask);
|
|
390
|
+
return sortTasksForList(applyFilter(tasks, filter));
|
|
391
|
+
}
|
|
392
|
+
async getTask(id) {
|
|
393
|
+
const doc = await this.readDocument();
|
|
394
|
+
const row = doc.rows.find((entry) => entry.id === id);
|
|
395
|
+
return row ? toTask(row) : void 0;
|
|
396
|
+
}
|
|
397
|
+
async updateTaskStatus(id, status) {
|
|
398
|
+
const doc = await this.readDocument();
|
|
399
|
+
const row = doc.rows.find((entry) => entry.id === id);
|
|
400
|
+
if (!row) {
|
|
401
|
+
throw new Error(`Backlog task not found: ${id}`);
|
|
402
|
+
}
|
|
403
|
+
row.cells.Status = formatStatus(status);
|
|
404
|
+
await this.writeDocument(doc);
|
|
405
|
+
}
|
|
406
|
+
async createTask(task) {
|
|
407
|
+
const doc = await this.readDocument();
|
|
408
|
+
let variant = doc.variant;
|
|
409
|
+
if (variant === "legacy") {
|
|
410
|
+
for (const r of doc.rows) {
|
|
411
|
+
r.cells.Priority = formatPriority(DEFAULT_TASK_PRIORITY);
|
|
412
|
+
}
|
|
413
|
+
variant = "withPriority";
|
|
414
|
+
}
|
|
415
|
+
const nextRow = {
|
|
416
|
+
id: `backlog-${doc.rows.length + 1}`,
|
|
417
|
+
cells: {
|
|
418
|
+
Epic: task.epic,
|
|
419
|
+
Priority: formatPriority(task.priority),
|
|
420
|
+
"Task Description": task.description,
|
|
421
|
+
"Acceptance Criteria": task.acceptanceCriteria,
|
|
422
|
+
Status: formatStatus(task.status),
|
|
423
|
+
Prototype: task.prototype,
|
|
424
|
+
Notes: task.notes
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
const nextDoc = {
|
|
428
|
+
...doc,
|
|
429
|
+
variant,
|
|
430
|
+
rows: [...doc.rows, nextRow]
|
|
431
|
+
};
|
|
432
|
+
await this.writeDocument(nextDoc);
|
|
433
|
+
return toTask(nextRow);
|
|
434
|
+
}
|
|
435
|
+
async readDocument() {
|
|
436
|
+
const raw = await readFile(this.backlogPath, "utf8");
|
|
437
|
+
return parseBacklogDocument(raw);
|
|
438
|
+
}
|
|
439
|
+
async writeDocument(doc) {
|
|
440
|
+
const nextLines = [
|
|
441
|
+
...doc.beforeTable,
|
|
442
|
+
...renderTable(doc.rows, doc.variant),
|
|
443
|
+
...doc.afterTable
|
|
444
|
+
];
|
|
445
|
+
await writeFile(this.backlogPath, nextLines.join("\n"), "utf8");
|
|
446
|
+
}
|
|
447
|
+
get path() {
|
|
448
|
+
return path.resolve(this.backlogPath);
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// src/index.ts
|
|
453
|
+
var BYRDE_CURSOR_PACKAGE_NAME = "@byrde/cursor";
|
|
454
|
+
export {
|
|
455
|
+
BYRDE_CURSOR_PACKAGE_NAME,
|
|
456
|
+
DEFAULT_MANIFEST,
|
|
457
|
+
DEFAULT_PROJECT_CONFIG,
|
|
458
|
+
DEFAULT_TASK_PRIORITY,
|
|
459
|
+
FileBacklogProvider,
|
|
460
|
+
TASK_STATUS_VALUES,
|
|
461
|
+
createDefaultProjectConfig,
|
|
462
|
+
createDefaultWorkflowModels,
|
|
463
|
+
normalizeProjectConfig
|
|
464
|
+
};
|
|
465
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domain/asset-manifest.ts","../src/domain/backlog/types.ts","../src/domain/config.ts","../src/infrastructure/file-backlog-provider.ts","../src/index.ts"],"sourcesContent":["import type { WorkflowModelRole } from \"./config.js\";\n\nexport interface AssetEntry {\n readonly source: string;\n readonly target: string;\n /**\n * When set, `source` is a UTF-8 template with `{{MODEL}}`; install/sync\n * substitutes the value from `workflow.models.<role>`.\n */\n readonly renderAgent?: WorkflowModelRole;\n}\n\n/** Maps each shipped file under `assets/` to its path under `<cwd>/.cursor/`. */\nexport const DEFAULT_MANIFEST = [\n {\n source: \"assets/agents/architect.md\",\n target: \"agents/architect.md\",\n renderAgent: \"architect\",\n },\n {\n source: \"assets/agents/developer.md\",\n target: \"agents/developer.md\",\n renderAgent: \"developer\",\n },\n {\n source: \"assets/agents/planner.md\",\n target: \"agents/planner.md\",\n renderAgent: \"planner\",\n },\n {\n source: \"assets/agents/tester.md\",\n target: \"agents/tester.md\",\n renderAgent: \"tester\",\n },\n { source: \"assets/rules/global.mdc\", target: \"rules/global.mdc\" },\n { source: \"assets/rules/init.mdc\", target: \"rules/init.mdc\" },\n { source: \"assets/templates/backlog.md\", target: \"templates/backlog.md\" },\n { source: \"assets/templates/design.md\", target: \"templates/design.md\" },\n { source: \"assets/templates/overview.md\", target: \"templates/overview.md\" },\n {\n source: \"assets/templates/testability/README.md\",\n target: \"templates/testability/README.md\",\n },\n] as const satisfies readonly AssetEntry[];\n","/** Canonical status values for markdown and GitHub-backed tasks. */\nexport const TASK_STATUS_VALUES = [\n \"TODO\",\n \"In Progress\",\n \"Ready to Test\",\n \"Complete\",\n] as const;\n\nexport type TaskStatus = (typeof TASK_STATUS_VALUES)[number];\n\n/**\n * Lower numbers sort first (1 = highest priority). File-backed backlogs without\n * a Priority column assign {@link DEFAULT_TASK_PRIORITY} when reading.\n */\nexport type TaskPriority = number;\n\n/** Default for rows missing a Priority cell (unprioritized / lowest). */\nexport const DEFAULT_TASK_PRIORITY = 1000;\n\nexport interface Task {\n readonly id: string;\n readonly epic: string;\n readonly priority: TaskPriority;\n readonly description: string;\n readonly acceptanceCriteria: string;\n readonly status: TaskStatus;\n readonly prototype: string;\n readonly notes: string;\n}\n\nexport interface TaskFilter {\n readonly status?: TaskStatus;\n readonly epic?: string;\n}\n\nexport type NewTask = Omit<Task, \"id\">;\n","export const PROJECT_CONFIG_FILENAME = \"workflow.json\";\n\nexport type BacklogProviderKind = \"file\" | \"github-issues\";\nexport type WorkflowDefaultMode = \"required\" | \"optional\";\n\n/** Subagent roles with configurable Cursor model ids (see `assets/agents/*.md`). */\nexport type WorkflowModelRole =\n | \"planner\"\n | \"architect\"\n | \"developer\"\n | \"tester\";\n\nexport interface WorkflowModels {\n readonly planner: string;\n readonly architect: string;\n readonly developer: string;\n readonly tester: string;\n}\n\n/**\n * GitHub backlog mode uses provider key `github-issues` (legacy name) and is\n * GitHub Project v2–first: issues are ordered by the Project **Priority** field,\n * workflow state by the Project **Status** field, and **milestones** represent epics.\n */\nexport interface GitHubIssuesBacklogConfig {\n readonly repository: string;\n /** GitHub Project (v2) number as shown on the repository Projects tab. */\n readonly projectNumber: number;\n /**\n * Organization or user login that owns the project. When omitted, tooling\n * assumes the repository owner (the segment before `/` in `repository`).\n */\n readonly projectOwner?: string;\n /** Project field name used for backlog ordering (default `Priority`). */\n readonly priorityField: string;\n /** Project field name used for workflow status (default `Status`). */\n readonly statusField: string;\n /**\n * Optional issue label filter (secondary to Project membership). Omit or leave\n * empty when everything is driven from the Project.\n */\n readonly label?: string;\n readonly mcpServerName: string;\n}\n\nexport interface ProjectConfig {\n readonly backlog: {\n readonly provider: BacklogProviderKind;\n readonly file?: {\n readonly path: string;\n };\n readonly \"github-issues\"?: GitHubIssuesBacklogConfig;\n };\n readonly workflow: {\n readonly defaults: {\n readonly architectReview: WorkflowDefaultMode;\n readonly testing: WorkflowDefaultMode;\n };\n readonly models: WorkflowModels;\n };\n}\n\n/** Defaults match pre-template agent frontmatter in `assets/agents/`. */\nexport function createDefaultWorkflowModels(): WorkflowModels {\n return {\n planner: \"gpt-5.4-high\",\n architect: \"gpt-5.4-high\",\n developer: \"composer-2-fast\",\n tester: \"composer-2-fast\",\n };\n}\n\nexport function createDefaultProjectConfig(): ProjectConfig {\n return {\n backlog: {\n provider: \"file\",\n file: {\n path: \"docs/backlog.md\",\n },\n },\n workflow: {\n defaults: {\n architectReview: \"required\",\n testing: \"required\",\n },\n models: createDefaultWorkflowModels(),\n },\n };\n}\n\nexport const DEFAULT_PROJECT_CONFIG = createDefaultProjectConfig();\n\nfunction isNonEmptyString(v: unknown): v is string {\n return typeof v === \"string\" && v.trim().length > 0;\n}\n\nfunction normalizeBacklog(\n raw: unknown,\n base: ProjectConfig[\"backlog\"],\n): ProjectConfig[\"backlog\"] {\n if (!raw || typeof raw !== \"object\") {\n return base;\n }\n const b = raw as Record<string, unknown>;\n const provider =\n b.provider === \"github-issues\" || b.provider === \"file\"\n ? b.provider\n : base.provider;\n\n if (provider === \"file\") {\n const fileRaw = b.file;\n const pathFrom =\n fileRaw && typeof fileRaw === \"object\" &&\n isNonEmptyString((fileRaw as Record<string, unknown>).path)\n ? String((fileRaw as Record<string, unknown>).path).trim()\n : base.file!.path;\n return { provider: \"file\", file: { path: pathFrom } };\n }\n\n const ghRaw = b[\"github-issues\"];\n const githubOptionalDefaults = {\n priorityField: \"Priority\",\n statusField: \"Status\",\n mcpServerName: \"github\",\n } as const;\n\n function parsePositiveInt(v: unknown): number | undefined {\n if (typeof v === \"number\" && Number.isFinite(v) && v > 0) {\n return Math.trunc(v);\n }\n if (isNonEmptyString(v)) {\n const n = Number.parseInt(String(v).trim(), 10);\n if (Number.isFinite(n) && n > 0) {\n return n;\n }\n }\n return undefined;\n }\n\n /**\n * GitHub mode requires an explicit repository and project number. Missing or\n * invalid nested config falls back to the default file backlog so we never\n * invent a plausible-looking `owner/repo` + `projectNumber: 1` target.\n */\n if (ghRaw && typeof ghRaw === \"object\") {\n const g = ghRaw as Record<string, unknown>;\n const repository = isNonEmptyString(g.repository)\n ? g.repository.trim()\n : undefined;\n const projectNumber = parsePositiveInt(g.projectNumber);\n\n if (repository !== undefined && projectNumber !== undefined) {\n const priorityField = isNonEmptyString(g.priorityField)\n ? g.priorityField.trim()\n : githubOptionalDefaults.priorityField;\n const statusField = isNonEmptyString(g.statusField)\n ? g.statusField.trim()\n : githubOptionalDefaults.statusField;\n const labelRaw = g.label;\n const label =\n isNonEmptyString(labelRaw) ? labelRaw.trim() : undefined;\n\n return {\n provider: \"github-issues\",\n \"github-issues\": {\n repository,\n projectNumber,\n projectOwner: isNonEmptyString(g.projectOwner)\n ? g.projectOwner.trim()\n : undefined,\n priorityField,\n statusField,\n ...(label !== undefined ? { label } : {}),\n mcpServerName: isNonEmptyString(g.mcpServerName)\n ? g.mcpServerName.trim()\n : githubOptionalDefaults.mcpServerName,\n },\n };\n }\n }\n\n return base;\n}\n\nfunction normalizeWorkflow(\n raw: unknown,\n base: ProjectConfig[\"workflow\"],\n): ProjectConfig[\"workflow\"] {\n const models = { ...base.models };\n let architectReview = base.defaults.architectReview;\n let testing = base.defaults.testing;\n\n if (raw && typeof raw === \"object\") {\n const w = raw as Record<string, unknown>;\n const d = w.defaults;\n if (d && typeof d === \"object\") {\n const def = d as Record<string, unknown>;\n if (def.architectReview === \"required\" || def.architectReview === \"optional\") {\n architectReview = def.architectReview;\n }\n if (def.testing === \"required\" || def.testing === \"optional\") {\n testing = def.testing;\n }\n }\n const m = w.models;\n if (m && typeof m === \"object\") {\n const mo = m as Record<string, unknown>;\n const pick = (key: keyof WorkflowModels): string => {\n const v = mo[key];\n return isNonEmptyString(v) ? v.trim() : base.models[key];\n };\n models.planner = pick(\"planner\");\n models.architect = pick(\"architect\");\n models.developer = pick(\"developer\");\n models.tester = pick(\"tester\");\n }\n }\n\n return {\n defaults: { architectReview, testing },\n models,\n };\n}\n\n/**\n * Merges parsed JSON with defaults so older configs without `workflow.models`\n * (or partial fields) remain valid.\n */\nexport function normalizeProjectConfig(raw: unknown): ProjectConfig {\n const base = createDefaultProjectConfig();\n if (!raw || typeof raw !== \"object\") {\n return base;\n }\n\n const o = raw as Record<string, unknown>;\n return {\n backlog: normalizeBacklog(o.backlog, base.backlog),\n workflow: normalizeWorkflow(o.workflow, base.workflow),\n };\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { BacklogProvider } from \"../domain/backlog/provider.js\";\nimport {\n DEFAULT_TASK_PRIORITY,\n TASK_STATUS_VALUES,\n type NewTask,\n type Task,\n type TaskFilter,\n type TaskStatus,\n} from \"../domain/backlog/types.js\";\n\nconst LEGACY_COLUMN_ORDER = [\n \"Epic\",\n \"Task Description\",\n \"Acceptance Criteria\",\n \"Status\",\n \"Prototype\",\n \"Notes\",\n] as const;\n\nconst COLUMN_ORDER = [\n \"Epic\",\n \"Priority\",\n \"Task Description\",\n \"Acceptance Criteria\",\n \"Status\",\n \"Prototype\",\n \"Notes\",\n] as const;\n\ntype LegacyColumnName = (typeof LEGACY_COLUMN_ORDER)[number];\ntype ColumnName = (typeof COLUMN_ORDER)[number];\n\ntype TableVariant = \"legacy\" | \"withPriority\";\n\ninterface ParsedRow {\n readonly id: string;\n readonly cells: Record<ColumnName, string>;\n}\n\ninterface ParsedBacklogDocument {\n readonly variant: TableVariant;\n readonly beforeTable: string[];\n readonly rows: ParsedRow[];\n readonly afterTable: string[];\n}\n\nfunction isTaskStatus(value: string): value is TaskStatus {\n return (TASK_STATUS_VALUES as readonly string[]).includes(value);\n}\n\nfunction normalizeStatus(raw: string): TaskStatus {\n const stripped = raw.replace(/^`|`$/g, \"\").trim();\n if (!isTaskStatus(stripped)) {\n throw new Error(\n `Invalid task status \"${stripped}\" (expected one of: ${TASK_STATUS_VALUES.join(\", \")})`,\n );\n }\n return stripped;\n}\n\nfunction formatStatus(status: TaskStatus): string {\n return `\\`${status}\\``;\n}\n\nfunction parsePriorityCell(raw: string): number {\n const t = raw.replace(/^`|`$/g, \"\").trim();\n if (!t.length) {\n return DEFAULT_TASK_PRIORITY;\n }\n const n = Number.parseInt(t, 10);\n return Number.isFinite(n) ? n : DEFAULT_TASK_PRIORITY;\n}\n\nfunction formatPriority(priority: number): string {\n return String(priority);\n}\n\nfunction splitMarkdownRow(line: string): string[] {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"|\") || !trimmed.endsWith(\"|\")) {\n throw new Error(`Invalid backlog table row: ${line}`);\n }\n return trimmed\n .slice(1, -1)\n .split(\"|\")\n .map((cell) => cell.trim());\n}\n\nfunction headerMatches(\n cells: readonly string[],\n expected: readonly string[],\n): boolean {\n if (cells.length !== expected.length) {\n return false;\n }\n return expected.every((name, i) => cells[i] === name);\n}\n\nfunction parseBacklogDocument(content: string): ParsedBacklogDocument {\n const lines = content.split(/\\r?\\n/);\n const tableStart = lines.findIndex((line, index) => {\n return line.trim().startsWith(\"|\") && lines[index + 1]?.trim().startsWith(\"|\");\n });\n\n if (tableStart < 0) {\n throw new Error(\"Could not find backlog markdown table.\");\n }\n\n let tableEnd = tableStart;\n while (tableEnd < lines.length && lines[tableEnd].trim().startsWith(\"|\")) {\n tableEnd += 1;\n }\n\n const headerCells = splitMarkdownRow(lines[tableStart]);\n let variant: TableVariant;\n let columnNames: readonly string[];\n\n if (headerMatches(headerCells, COLUMN_ORDER)) {\n variant = \"withPriority\";\n columnNames = COLUMN_ORDER;\n } else if (headerMatches(headerCells, LEGACY_COLUMN_ORDER)) {\n variant = \"legacy\";\n columnNames = LEGACY_COLUMN_ORDER;\n } else {\n throw new Error(\n \"Unexpected backlog table header (expected Epic + Priority + … or legacy Epic + Task Description + …).\",\n );\n }\n\n const rowLines = lines.slice(tableStart + 2, tableEnd);\n const rows: ParsedRow[] = rowLines.map((line, rowIndex) => {\n const cells = splitMarkdownRow(line);\n if (cells.length !== columnNames.length) {\n throw new Error(`Unexpected backlog row width at row ${rowIndex + 1}.`);\n }\n\n if (variant === \"legacy\") {\n const legacyCells = Object.fromEntries(\n LEGACY_COLUMN_ORDER.map((column, columnIndex) => [\n column,\n cells[columnIndex],\n ]),\n ) as Record<LegacyColumnName, string>;\n\n const full: Record<ColumnName, string> = {\n Epic: legacyCells.Epic,\n Priority: formatPriority(DEFAULT_TASK_PRIORITY),\n \"Task Description\": legacyCells[\"Task Description\"],\n \"Acceptance Criteria\": legacyCells[\"Acceptance Criteria\"],\n Status: legacyCells.Status,\n Prototype: legacyCells.Prototype,\n Notes: legacyCells.Notes,\n };\n\n return {\n id: `backlog-${rowIndex + 1}`,\n cells: full,\n };\n }\n\n const withP = Object.fromEntries(\n COLUMN_ORDER.map((column, columnIndex) => [column, cells[columnIndex]]),\n ) as Record<ColumnName, string>;\n\n return {\n id: `backlog-${rowIndex + 1}`,\n cells: withP,\n };\n });\n\n return {\n variant,\n beforeTable: lines.slice(0, tableStart),\n rows,\n afterTable: lines.slice(tableEnd),\n };\n}\n\nfunction renderTable(\n rows: readonly ParsedRow[],\n variant: TableVariant,\n): string[] {\n if (variant === \"legacy\") {\n const bodyRows = rows.map((row) =>\n LEGACY_COLUMN_ORDER.map((column) => {\n if (column === \"Epic\") {\n return row.cells.Epic;\n }\n if (column === \"Task Description\") {\n return row.cells[\"Task Description\"];\n }\n if (column === \"Acceptance Criteria\") {\n return row.cells[\"Acceptance Criteria\"];\n }\n if (column === \"Status\") {\n return row.cells.Status;\n }\n if (column === \"Prototype\") {\n return row.cells.Prototype;\n }\n return row.cells.Notes;\n }),\n );\n const widths = LEGACY_COLUMN_ORDER.map((column, index) =>\n Math.max(\n column.length,\n ...bodyRows.map((cells) => cells[index]?.length ?? 0),\n ),\n );\n const renderRow = (cells: readonly string[]): string =>\n `| ${cells.map((cell, index) => cell.padEnd(widths[index])).join(\" | \")} |`;\n const separator = `| ${widths.map((width) => \"-\".repeat(width)).join(\" | \")} |`;\n return [\n renderRow(LEGACY_COLUMN_ORDER),\n separator,\n ...bodyRows.map(renderRow),\n ];\n }\n\n const bodyRows = rows.map((row) => COLUMN_ORDER.map((column) => row.cells[column]));\n const widths = COLUMN_ORDER.map((column, index) =>\n Math.max(\n column.length,\n ...bodyRows.map((cells) => cells[index]?.length ?? 0),\n ),\n );\n\n const renderRow = (cells: readonly string[]): string =>\n `| ${cells.map((cell, index) => cell.padEnd(widths[index])).join(\" | \")} |`;\n\n const separator = `| ${widths.map((width) => \"-\".repeat(width)).join(\" | \")} |`;\n\n return [renderRow(COLUMN_ORDER), separator, ...bodyRows.map(renderRow)];\n}\n\nfunction toTask(row: ParsedRow): Task {\n return {\n id: row.id,\n epic: row.cells.Epic,\n priority: parsePriorityCell(row.cells.Priority),\n description: row.cells[\"Task Description\"],\n acceptanceCriteria: row.cells[\"Acceptance Criteria\"],\n status: normalizeStatus(row.cells.Status),\n prototype: row.cells.Prototype,\n notes: row.cells.Notes,\n };\n}\n\nfunction sortTasksForList(tasks: Task[]): Task[] {\n return [...tasks].sort((a, b) => {\n if (a.priority !== b.priority) {\n return a.priority - b.priority;\n }\n const ai = Number.parseInt(a.id.replace(/^backlog-/, \"\"), 10);\n const bi = Number.parseInt(b.id.replace(/^backlog-/, \"\"), 10);\n return ai - bi;\n });\n}\n\nfunction applyFilter(tasks: readonly Task[], filter?: TaskFilter): Task[] {\n if (!filter) {\n return [...tasks];\n }\n\n return tasks.filter((task) => {\n if (filter.status && task.status !== filter.status) {\n return false;\n }\n if (filter.epic && task.epic !== filter.epic) {\n return false;\n }\n return true;\n });\n}\n\nexport class FileBacklogProvider implements BacklogProvider {\n constructor(private readonly backlogPath: string) {}\n\n async listTasks(filter?: TaskFilter): Promise<Task[]> {\n const doc = await this.readDocument();\n const tasks = doc.rows.map(toTask);\n return sortTasksForList(applyFilter(tasks, filter));\n }\n\n async getTask(id: string): Promise<Task | undefined> {\n const doc = await this.readDocument();\n const row = doc.rows.find((entry) => entry.id === id);\n return row ? toTask(row) : undefined;\n }\n\n async updateTaskStatus(id: string, status: TaskStatus): Promise<void> {\n const doc = await this.readDocument();\n const row = doc.rows.find((entry) => entry.id === id);\n if (!row) {\n throw new Error(`Backlog task not found: ${id}`);\n }\n\n row.cells.Status = formatStatus(status);\n await this.writeDocument(doc);\n }\n\n async createTask(task: NewTask): Promise<Task> {\n const doc = await this.readDocument();\n let variant = doc.variant;\n\n if (variant === \"legacy\") {\n for (const r of doc.rows) {\n r.cells.Priority = formatPriority(DEFAULT_TASK_PRIORITY);\n }\n variant = \"withPriority\";\n }\n\n const nextRow: ParsedRow = {\n id: `backlog-${doc.rows.length + 1}`,\n cells: {\n Epic: task.epic,\n Priority: formatPriority(task.priority),\n \"Task Description\": task.description,\n \"Acceptance Criteria\": task.acceptanceCriteria,\n Status: formatStatus(task.status),\n Prototype: task.prototype,\n Notes: task.notes,\n },\n };\n\n const nextDoc: ParsedBacklogDocument = {\n ...doc,\n variant,\n rows: [...doc.rows, nextRow],\n };\n\n await this.writeDocument(nextDoc);\n return toTask(nextRow);\n }\n\n private async readDocument(): Promise<ParsedBacklogDocument> {\n const raw = await readFile(this.backlogPath, \"utf8\");\n return parseBacklogDocument(raw);\n }\n\n private async writeDocument(doc: ParsedBacklogDocument): Promise<void> {\n const nextLines = [\n ...doc.beforeTable,\n ...renderTable(doc.rows, doc.variant),\n ...doc.afterTable,\n ];\n await writeFile(this.backlogPath, nextLines.join(\"\\n\"), \"utf8\");\n }\n\n get path(): string {\n return path.resolve(this.backlogPath);\n }\n}\n","export const BYRDE_CURSOR_PACKAGE_NAME = \"@byrde/cursor\";\n\nexport type { AssetEntry } from \"./domain/asset-manifest.js\";\nexport { DEFAULT_MANIFEST } from \"./domain/asset-manifest.js\";\nexport type { BacklogProvider } from \"./domain/backlog/provider.js\";\nexport type {\n NewTask,\n Task,\n TaskFilter,\n TaskPriority,\n TaskStatus,\n} from \"./domain/backlog/types.js\";\nexport {\n DEFAULT_TASK_PRIORITY,\n TASK_STATUS_VALUES,\n} from \"./domain/backlog/types.js\";\nexport type {\n GitHubIssuesBacklogConfig,\n ProjectConfig,\n WorkflowModelRole,\n WorkflowModels,\n} from \"./domain/config.js\";\nexport {\n createDefaultProjectConfig,\n createDefaultWorkflowModels,\n DEFAULT_PROJECT_CONFIG,\n normalizeProjectConfig,\n} from \"./domain/config.js\";\nexport { FileBacklogProvider } from \"./infrastructure/file-backlog-provider.js\";\n"],"mappings":"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","names":["bodyRows","widths","renderRow","separator"]}
|