@swarmcraftai/cli 0.1.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/dist/main.cjs ADDED
@@ -0,0 +1,4312 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __commonJS = (cb, mod) => function __require() {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+
29
+ // ../../packages/packet-workflow/dist/assistantActions.js
30
+ var require_assistantActions = __commonJS({
31
+ "../../packages/packet-workflow/dist/assistantActions.js"(exports2) {
32
+ "use strict";
33
+ Object.defineProperty(exports2, "__esModule", { value: true });
34
+ exports2.SWARMCRAFT_ASSISTANT_ACTIONS = exports2.SWARMCRAFT_DIAGNOSTIC_WORKFLOWS = exports2.SWARMCRAFT_ASSISTANT_WORKFLOW_POLICY = void 0;
35
+ exports2.getSwarmCraftAssistantAction = getSwarmCraftAssistantAction;
36
+ exports2.getStageAssistantActions = getStageAssistantActions;
37
+ exports2.renderAssistantActionAdapterMetadata = renderAssistantActionAdapterMetadata;
38
+ exports2.listAssistantActionAdapterMetadata = listAssistantActionAdapterMetadata;
39
+ exports2.findMissingAssistantActionAdapters = findMissingAssistantActionAdapters;
40
+ exports2.SWARMCRAFT_ASSISTANT_WORKFLOW_POLICY = {
41
+ roleAgents: "optional-secondary",
42
+ diagnostics: "internal-support-or-advanced-only",
43
+ copilotCommandStyle: "slash-command"
44
+ };
45
+ exports2.SWARMCRAFT_DIAGNOSTIC_WORKFLOWS = [
46
+ "packet-sync-triage",
47
+ "repo-seed-audit"
48
+ ];
49
+ exports2.SWARMCRAFT_ASSISTANT_ACTIONS = [
50
+ {
51
+ key: "plan",
52
+ kind: "planning",
53
+ laneBound: false,
54
+ description: "Create a new plan or ticket from inside the repo, or check an existing plan for stale or incoherent scope.",
55
+ packetEffect: "Creates or revises planning artifacts; may create a provisional todo packet for sync promotion.",
56
+ copilotPromptPath: ".github/prompts/plan.prompt.md",
57
+ copilotSkillPath: ".github/skills/swarmcraft-plan/SKILL.md",
58
+ copilotInvocation: "/plan",
59
+ codexSkillPath: ".agents/skills/swarmcraft-plan/SKILL.md",
60
+ codexInvocation: "$swarmcraft-plan"
61
+ },
62
+ {
63
+ key: "do",
64
+ kind: "stage",
65
+ stageKey: "doing",
66
+ laneBound: true,
67
+ description: "Implement scoped packet work.",
68
+ packetEffect: "Existing doing packet may move to checking.",
69
+ copilotPromptPath: ".github/prompts/do.prompt.md",
70
+ copilotSkillPath: ".github/skills/swarmcraft-do/SKILL.md",
71
+ copilotInvocation: "/do ticket=<packet-path>",
72
+ codexSkillPath: ".agents/skills/swarmcraft-do/SKILL.md",
73
+ codexInvocation: "$swarmcraft-do ticket=<packet-path>"
74
+ },
75
+ {
76
+ key: "check",
77
+ kind: "stage",
78
+ stageKey: "checking",
79
+ laneBound: true,
80
+ description: "Validate implementation evidence.",
81
+ packetEffect: "Existing checking packet may move to reviewing or back to doing.",
82
+ copilotPromptPath: ".github/prompts/check.prompt.md",
83
+ copilotSkillPath: ".github/skills/swarmcraft-check/SKILL.md",
84
+ copilotInvocation: "/check ticket=<packet-path>",
85
+ codexSkillPath: ".agents/skills/swarmcraft-check/SKILL.md",
86
+ codexInvocation: "$swarmcraft-check ticket=<packet-path>"
87
+ },
88
+ {
89
+ key: "review",
90
+ kind: "stage",
91
+ stageKey: "reviewing",
92
+ laneBound: true,
93
+ description: "Record human approval decisions.",
94
+ packetEffect: "Existing reviewing packet remains ready for extension-owned done movement.",
95
+ copilotPromptPath: ".github/prompts/review.prompt.md",
96
+ copilotSkillPath: ".github/skills/swarmcraft-review/SKILL.md",
97
+ copilotInvocation: "/review ticket=<packet-path>",
98
+ codexSkillPath: ".agents/skills/swarmcraft-review/SKILL.md",
99
+ codexInvocation: "$swarmcraft-review ticket=<packet-path>"
100
+ },
101
+ {
102
+ key: "test",
103
+ kind: "testing",
104
+ laneBound: false,
105
+ description: "Add or run system testing coverage.",
106
+ packetEffect: "Records test evidence on an existing packet or creates a testing-focused todo packet.",
107
+ copilotPromptPath: ".github/prompts/test.prompt.md",
108
+ copilotSkillPath: ".github/skills/swarmcraft-test/SKILL.md",
109
+ copilotInvocation: "/test",
110
+ codexSkillPath: ".agents/skills/swarmcraft-test/SKILL.md",
111
+ codexInvocation: "$swarmcraft-test"
112
+ }
113
+ ];
114
+ function getSwarmCraftAssistantAction(actionKey) {
115
+ const action = exports2.SWARMCRAFT_ASSISTANT_ACTIONS.find((candidate) => candidate.key === actionKey);
116
+ if (!action) {
117
+ throw new Error(`Unknown SwarmCraft assistant action: ${actionKey}`);
118
+ }
119
+ return action;
120
+ }
121
+ function getStageAssistantActions() {
122
+ return exports2.SWARMCRAFT_ASSISTANT_ACTIONS.filter((action) => action.kind === "stage");
123
+ }
124
+ function renderAssistantActionAdapterMetadata(provider, action) {
125
+ if (provider === "copilot") {
126
+ return {
127
+ provider,
128
+ action: action.key,
129
+ relativePath: action.copilotPromptPath,
130
+ invocation: action.copilotInvocation,
131
+ skillPath: action.copilotSkillPath,
132
+ promptPath: action.copilotPromptPath
133
+ };
134
+ }
135
+ return {
136
+ provider,
137
+ action: action.key,
138
+ relativePath: action.codexSkillPath,
139
+ invocation: action.codexInvocation,
140
+ skillPath: action.codexSkillPath
141
+ };
142
+ }
143
+ function listAssistantActionAdapterMetadata(expectedProviders = ["copilot", "codex"], expectedActions = exports2.SWARMCRAFT_ASSISTANT_ACTIONS) {
144
+ return expectedProviders.flatMap((provider) => expectedActions.map((action) => renderAssistantActionAdapterMetadata(provider, action)));
145
+ }
146
+ function findMissingAssistantActionAdapters(expectedProviders, adapters, expectedActions = exports2.SWARMCRAFT_ASSISTANT_ACTIONS) {
147
+ const missing = [];
148
+ for (const provider of expectedProviders) {
149
+ const providerAdapters = adapters.filter((adapter) => adapter.provider === provider);
150
+ for (const action of expectedActions) {
151
+ const hasAdapter = providerAdapters.some((adapter) => adapter.action === action.key);
152
+ if (!hasAdapter) {
153
+ missing.push(`${provider} is missing ${action.key} action adapter`);
154
+ }
155
+ }
156
+ }
157
+ return missing;
158
+ }
159
+ }
160
+ });
161
+
162
+ // ../../packages/packet-workflow/dist/agentProviders.js
163
+ var require_agentProviders = __commonJS({
164
+ "../../packages/packet-workflow/dist/agentProviders.js"(exports2) {
165
+ "use strict";
166
+ Object.defineProperty(exports2, "__esModule", { value: true });
167
+ exports2.EXTERNAL_AGENT_PROVIDER_DEFAULTS = exports2.DEFAULT_EXTERNAL_AGENT_PROVIDER = exports2.EXTERNAL_AGENT_PROVIDERS = void 0;
168
+ exports2.parseExternalAgentProvider = parseExternalAgentProvider2;
169
+ exports2.resolveExternalAgentProviderDefault = resolveExternalAgentProviderDefault2;
170
+ exports2.applyExternalAgentProviderDefault = applyExternalAgentProviderDefault;
171
+ exports2.resolveExternalAgentSandboxMode = resolveExternalAgentSandboxMode2;
172
+ exports2.resolveExternalAgentApprovalPosture = resolveExternalAgentApprovalPosture2;
173
+ exports2.EXTERNAL_AGENT_PROVIDERS = ["codex", "copilot", "custom"];
174
+ exports2.DEFAULT_EXTERNAL_AGENT_PROVIDER = "custom";
175
+ exports2.EXTERNAL_AGENT_PROVIDER_DEFAULTS = {
176
+ codex: {
177
+ command: "codex exec --sandbox workspace-write {command}",
178
+ sandboxMode: "workspace-write",
179
+ approvalPosture: "codex-config"
180
+ },
181
+ copilot: {
182
+ command: "copilot --allow-all-tools --no-ask-user -p {command}",
183
+ sandboxMode: "local-cli-default",
184
+ approvalPosture: "allow-all-tools,no-ask-user"
185
+ }
186
+ };
187
+ function parseExternalAgentProvider2(rawValue) {
188
+ if (exports2.EXTERNAL_AGENT_PROVIDERS.includes(rawValue)) {
189
+ return rawValue;
190
+ }
191
+ throw new Error("--agent-provider must be codex, copilot, or custom.");
192
+ }
193
+ function resolveExternalAgentProviderDefault2(provider) {
194
+ return exports2.EXTERNAL_AGENT_PROVIDER_DEFAULTS[provider] ?? null;
195
+ }
196
+ function applyExternalAgentProviderDefault(parsed) {
197
+ if (parsed.agentMode !== "externalCommand" || parsed.agentCommand) {
198
+ return;
199
+ }
200
+ const providerDefault = resolveExternalAgentProviderDefault2(parsed.agentProvider);
201
+ if (providerDefault) {
202
+ parsed.agentCommand = providerDefault.command;
203
+ parsed.agentCommandSource = "provider-default";
204
+ }
205
+ }
206
+ function resolveExternalAgentSandboxMode2(parsedArgs) {
207
+ if (parsedArgs.agentMode !== "externalCommand") {
208
+ return null;
209
+ }
210
+ const providerDefault = resolveExternalAgentProviderDefault2(parsedArgs.agentProvider);
211
+ if (parsedArgs.agentCommandSource === "provider-default" && providerDefault) {
212
+ return providerDefault.sandboxMode;
213
+ }
214
+ if (parsedArgs.agentProvider === "codex") {
215
+ const match = parsedArgs.agentCommand?.match(/--sandbox\s+([^\s]+)/);
216
+ return match ? match[1] : "codex-config";
217
+ }
218
+ if (parsedArgs.agentProvider === "copilot") {
219
+ return "local-cli-default";
220
+ }
221
+ return null;
222
+ }
223
+ function resolveExternalAgentApprovalPosture2(parsedArgs) {
224
+ if (parsedArgs.agentMode !== "externalCommand") {
225
+ return null;
226
+ }
227
+ const providerDefault = resolveExternalAgentProviderDefault2(parsedArgs.agentProvider);
228
+ if (parsedArgs.agentCommandSource === "provider-default" && providerDefault) {
229
+ return providerDefault.approvalPosture;
230
+ }
231
+ const command = parsedArgs.agentCommand ?? "";
232
+ if (parsedArgs.agentProvider === "codex") {
233
+ return command.includes("--dangerously-bypass-approvals-and-sandbox") ? "bypass-approvals-and-sandbox" : "codex-config";
234
+ }
235
+ if (parsedArgs.agentProvider === "copilot") {
236
+ return command.includes("--allow-all") || command.includes("--yolo") ? "allow-all" : "copilot-config";
237
+ }
238
+ return null;
239
+ }
240
+ }
241
+ });
242
+
243
+ // ../../packages/packet-workflow/dist/manifest.js
244
+ var require_manifest = __commonJS({
245
+ "../../packages/packet-workflow/dist/manifest.js"(exports2) {
246
+ "use strict";
247
+ Object.defineProperty(exports2, "__esModule", { value: true });
248
+ exports2.buildPreviousDoneTicketMap = buildPreviousDoneTicketMap;
249
+ exports2.countCompletedStages = countCompletedStages;
250
+ exports2.resolveWorkflowRunStatus = resolveWorkflowRunStatus;
251
+ exports2.summarizeWorkflowRunDurations = summarizeWorkflowRunDurations2;
252
+ exports2.computeElapsedMs = computeElapsedMs2;
253
+ exports2.sumNumbers = sumNumbers;
254
+ exports2.averageNumber = averageNumber;
255
+ function buildPreviousDoneTicketMap(previousManifest) {
256
+ const tickets = Array.isArray(previousManifest?.tickets) ? previousManifest.tickets : [];
257
+ return new Map(tickets.filter((ticket) => Boolean(ticket?.ticketId) && ticket.outcome === "done").map((ticket) => [ticket.ticketId, ticket]));
258
+ }
259
+ function countCompletedStages(ticketOutcome) {
260
+ const stages = Array.isArray(ticketOutcome?.stages) ? ticketOutcome.stages : [];
261
+ return stages.filter((stage) => stage?.result && stage.result !== "pending").length;
262
+ }
263
+ function resolveWorkflowRunStatus(manifest, options = {}) {
264
+ const tickets = Array.isArray(manifest.tickets) ? manifest.tickets : [];
265
+ if (tickets.some((ticket) => String(ticket.outcome ?? "").startsWith("blocked"))) {
266
+ return "blocked";
267
+ }
268
+ if (options.reviewing && tickets.some((ticket) => ticket.outcome === "manual-review-required")) {
269
+ return "manual-review-required";
270
+ }
271
+ return "success";
272
+ }
273
+ function summarizeWorkflowRunDurations2(manifest) {
274
+ const tickets = Array.isArray(manifest.tickets) ? manifest.tickets : [];
275
+ const ticketDurations = tickets.map((ticket) => computeElapsedMs2(ticket.startedAt, ticket.finishedAt)).filter((value) => value !== null);
276
+ const stageDurations = tickets.flatMap((ticket) => Array.isArray(ticket.stages) ? ticket.stages : []).map((stage) => computeElapsedMs2(stage.startedAt, stage.finishedAt)).filter((value) => value !== null);
277
+ return {
278
+ elapsedMs: computeElapsedMs2(manifest.generatedAt, manifest.finishedAt),
279
+ ticketCount: tickets.length,
280
+ totalTicketMs: sumNumbers(ticketDurations),
281
+ totalStageMs: sumNumbers(stageDurations),
282
+ averageTicketMs: averageNumber(ticketDurations),
283
+ averageStageMs: averageNumber(stageDurations)
284
+ };
285
+ }
286
+ function computeElapsedMs2(startedAt, finishedAt) {
287
+ if (!startedAt || !finishedAt) {
288
+ return null;
289
+ }
290
+ const elapsedMs = Date.parse(finishedAt) - Date.parse(startedAt);
291
+ return Number.isFinite(elapsedMs) ? Math.max(0, elapsedMs) : null;
292
+ }
293
+ function sumNumbers(values) {
294
+ return values.reduce((total, value) => total + Number(value || 0), 0);
295
+ }
296
+ function averageNumber(values) {
297
+ if (values.length === 0) {
298
+ return null;
299
+ }
300
+ return Math.round(sumNumbers(values) / values.length);
301
+ }
302
+ }
303
+ });
304
+
305
+ // ../../packages/packet-workflow/dist/packetFile.js
306
+ var require_packetFile = __commonJS({
307
+ "../../packages/packet-workflow/dist/packetFile.js"(exports2) {
308
+ "use strict";
309
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
310
+ return mod && mod.__esModule ? mod : { "default": mod };
311
+ };
312
+ Object.defineProperty(exports2, "__esModule", { value: true });
313
+ exports2.PacketFileContractError = exports2.PROVISIONAL_TICKET_ID_PREFIX = exports2.PACKET_FILE_ROOT = exports2.WORKFLOW_STATES = exports2.CHECKLIST_STAGES = void 0;
314
+ exports2.renderPacketFile = renderPacketFile2;
315
+ exports2.renderProvisionalPacketFile = renderProvisionalPacketFile;
316
+ exports2.renderChecklistSection = renderChecklistSection;
317
+ exports2.resolvePacketFilePath = resolvePacketFilePath3;
318
+ exports2.parsePacketFile = parsePacketFile3;
319
+ exports2.rewritePacketFileMetadata = rewritePacketFileMetadata3;
320
+ exports2.rewriteProvisionalPacketFileMetadata = rewriteProvisionalPacketFileMetadata;
321
+ exports2.rewritePacketFile = rewritePacketFile;
322
+ exports2.markChecklistStageComplete = markChecklistStageComplete;
323
+ exports2.appendAgentUpdateLines = appendAgentUpdateLines;
324
+ exports2.composeTicketNotes = composeTicketNotes2;
325
+ exports2.ensurePacketFileIdentity = ensurePacketFileIdentity2;
326
+ exports2.ensurePacketMatches = ensurePacketMatches;
327
+ exports2.isProvisionalPacketFile = isProvisionalPacketFile;
328
+ exports2.assertProvisionalPacketFile = assertProvisionalPacketFile;
329
+ exports2.findChecklistShapeProblem = findChecklistShapeProblem2;
330
+ exports2.assertChecklistShape = assertChecklistShape;
331
+ exports2.listChecklistItemsForStage = listChecklistItemsForStage2;
332
+ exports2.allChecklistItemsComplete = allChecklistItemsComplete2;
333
+ exports2.splitStoredTicketNotes = splitStoredTicketNotes;
334
+ exports2.normalizeSectionText = normalizeSectionText;
335
+ exports2.previewText = previewText;
336
+ exports2.slugify = slugify;
337
+ var node_path_1 = __importDefault(require("node:path"));
338
+ exports2.CHECKLIST_STAGES = ["doing", "checking", "reviewing"];
339
+ exports2.WORKFLOW_STATES = ["todo", "doing", "checking", "reviewing", "done"];
340
+ exports2.PACKET_FILE_ROOT = ".swarmcraft/projects/";
341
+ exports2.PROVISIONAL_TICKET_ID_PREFIX = "provisional:";
342
+ var PacketFileContractError2 = class extends Error {
343
+ code;
344
+ constructor(code, message) {
345
+ super(message);
346
+ this.name = "PacketFileContractError";
347
+ this.code = code;
348
+ }
349
+ };
350
+ exports2.PacketFileContractError = PacketFileContractError2;
351
+ function renderPacketFile2(project, ticket, syncedAt, existingContents = null) {
352
+ const storedSections = existingContents ? parsePacketFile3(existingContents).sections : splitStoredTicketNotes(ticket.notes ?? null);
353
+ const goal = ticket.summary?.trim() ? ticket.summary.trim() : "Describe the outcome in one short paragraph.";
354
+ return [
355
+ "---",
356
+ "swarmcraftVersion: 1",
357
+ `projectId: ${project.id}`,
358
+ `ticketId: ${ticket.id}`,
359
+ `title: ${escapeFrontmatterValue(ticket.title ?? "")}`,
360
+ `lane: ${ticket.workflowState}`,
361
+ `syncRevision: ${ticket.revision}`,
362
+ `lastSyncedAt: ${syncedAt}`,
363
+ "---",
364
+ "",
365
+ "## Goal",
366
+ "",
367
+ goal,
368
+ "",
369
+ "## Doing Checklist",
370
+ "",
371
+ renderChecklistSection(ticket, "doing"),
372
+ "",
373
+ "## Checking Checklist",
374
+ "",
375
+ renderChecklistSection(ticket, "checking"),
376
+ "",
377
+ "## Reviewing Checklist",
378
+ "",
379
+ renderChecklistSection(ticket, "reviewing"),
380
+ "",
381
+ "## Notes",
382
+ "",
383
+ storedSections.notes ?? "",
384
+ "",
385
+ "## Agent Update",
386
+ "",
387
+ storedSections.agentUpdate || "<!-- Short structured summary of what changed, what is blocked, and what still needs review. -->",
388
+ ""
389
+ ].join("\n");
390
+ }
391
+ function renderProvisionalPacketFile(input2) {
392
+ const title = input2.title.trim();
393
+ const provisionalTicketId = input2.provisionalTicketId?.trim() || `${exports2.PROVISIONAL_TICKET_ID_PREFIX}${slugify(title)}`;
394
+ return [
395
+ "---",
396
+ "swarmcraftVersion: 1",
397
+ `projectId: ${input2.projectId}`,
398
+ `ticketId: ${provisionalTicketId}`,
399
+ `title: ${escapeFrontmatterValue(title)}`,
400
+ "lane: todo",
401
+ "syncRevision: 0",
402
+ "lastSyncedAt: null",
403
+ "provisional: true",
404
+ "---",
405
+ "",
406
+ "## Goal",
407
+ "",
408
+ input2.goal.trim() || "Describe the outcome in one short paragraph.",
409
+ "",
410
+ "## Doing Checklist",
411
+ "",
412
+ renderProvisionalChecklist(input2.checklists.doing),
413
+ "",
414
+ "## Checking Checklist",
415
+ "",
416
+ renderProvisionalChecklist(input2.checklists.checking),
417
+ "",
418
+ "## Reviewing Checklist",
419
+ "",
420
+ renderProvisionalChecklist(input2.checklists.reviewing),
421
+ "",
422
+ "## Notes",
423
+ "",
424
+ input2.notes?.trim() ?? "",
425
+ "",
426
+ "## Agent Update",
427
+ "",
428
+ input2.agentUpdate?.trim() || "<!-- Short structured summary of what changed, what is blocked, and what still needs review. -->",
429
+ ""
430
+ ].join("\n");
431
+ }
432
+ function renderChecklistSection(ticket, checklistStage) {
433
+ const checklistItems = listChecklistItemsForStage2(ticket.checklistItems, checklistStage);
434
+ if (checklistItems.length === 0) {
435
+ return `<!-- No ${checklistStage} checklist items yet. Add or sync them from SwarmCraft. -->`;
436
+ }
437
+ return checklistItems.map((item) => `- [${item.completed ? "x" : " "}] ${item.body}`).join("\n");
438
+ }
439
+ function renderProvisionalChecklist(items) {
440
+ const normalizedItems = (items ?? []).map((item) => item.trim()).filter(Boolean);
441
+ if (normalizedItems.length === 0) {
442
+ return "<!-- Add checklist items before syncing this provisional packet. -->";
443
+ }
444
+ return normalizedItems.map((item) => `- [ ] ${item}`).join("\n");
445
+ }
446
+ function resolvePacketFilePath3(project, ticket, packetLink = ticket.packetLink) {
447
+ if (packetLink) {
448
+ return packetLink.packetFilePath;
449
+ }
450
+ return node_path_1.default.posix.join(".swarmcraft", "projects", slugify(project.title || project.projectTitle || project.id), `${ticket.recommendedOrder}-${slugify(ticket.title || "ticket")}.md`);
451
+ }
452
+ function parsePacketFile3(contents) {
453
+ const { frontmatter, body } = parsePacketFileDocument(contents);
454
+ const sections = parseSections(body);
455
+ const requiredSections = ["Goal", "Notes", "Agent Update"];
456
+ for (const section of requiredSections) {
457
+ if (!(section in sections)) {
458
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", `The packet file is missing the required ${section} section.`);
459
+ }
460
+ }
461
+ const lane = parseLane(frontmatter.lane);
462
+ const syncRevision = Number.parseInt(frontmatter.syncRevision ?? "", 10);
463
+ if (!Number.isInteger(syncRevision) || syncRevision < 0) {
464
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "The packet file is missing a valid syncRevision frontmatter value.");
465
+ }
466
+ const swarmcraftVersion = Number.parseInt(frontmatter.swarmcraftVersion ?? "", 10);
467
+ if (!Number.isInteger(swarmcraftVersion) || swarmcraftVersion !== 1) {
468
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "The packet file must declare swarmcraftVersion: 1.");
469
+ }
470
+ return {
471
+ frontmatter: {
472
+ swarmcraftVersion,
473
+ projectId: requireFrontmatterValue(frontmatter.projectId, "projectId"),
474
+ ticketId: requireFrontmatterValue(frontmatter.ticketId, "ticketId"),
475
+ title: frontmatter.title ?? null,
476
+ lane,
477
+ syncRevision,
478
+ lastSyncedAt: parseNullableFrontmatterValue(frontmatter.lastSyncedAt),
479
+ provisional: parseBooleanFrontmatterValue(frontmatter.provisional)
480
+ },
481
+ sections: {
482
+ goal: normalizeSectionText(sections.Goal ?? ""),
483
+ checklists: parseChecklistSections(sections),
484
+ notes: normalizeSectionText(sections.Notes ?? ""),
485
+ agentUpdate: normalizeSectionText(sections["Agent Update"] ?? "")
486
+ }
487
+ };
488
+ }
489
+ function rewritePacketFileMetadata3(contents, metadata) {
490
+ const { frontmatterLines, body } = parsePacketFileDocument(contents);
491
+ const updatedFrontmatter = new Map(frontmatterLines.map((line) => {
492
+ const separatorIndex = line.indexOf(":");
493
+ return [line.slice(0, separatorIndex).trim(), line.slice(separatorIndex + 1).trim()];
494
+ }));
495
+ updatedFrontmatter.set("lane", metadata.lane);
496
+ updatedFrontmatter.set("syncRevision", String(metadata.syncRevision));
497
+ updatedFrontmatter.set("lastSyncedAt", metadata.lastSyncedAt);
498
+ const orderedKeys = ["swarmcraftVersion", "projectId", "ticketId", "title", "lane", "syncRevision", "lastSyncedAt", "provisional"];
499
+ const rewrittenFrontmatter = orderedKeys.filter((key) => updatedFrontmatter.has(key)).map((key) => `${key}: ${updatedFrontmatter.get(key)}`).join("\n");
500
+ return `---
501
+ ${rewrittenFrontmatter}
502
+ ---
503
+ ${body.startsWith("\n") ? body : `
504
+ ${body}`}`;
505
+ }
506
+ function rewriteProvisionalPacketFileMetadata(contents, metadata) {
507
+ const { frontmatterLines, body } = parsePacketFileDocument(contents);
508
+ const updatedFrontmatter = new Map(frontmatterLines.map((line) => {
509
+ const separatorIndex = line.indexOf(":");
510
+ return [line.slice(0, separatorIndex).trim(), line.slice(separatorIndex + 1).trim()];
511
+ }));
512
+ updatedFrontmatter.set("ticketId", metadata.ticketId);
513
+ updatedFrontmatter.set("title", escapeFrontmatterValue(metadata.title));
514
+ updatedFrontmatter.set("lane", metadata.lane);
515
+ updatedFrontmatter.set("syncRevision", String(metadata.syncRevision));
516
+ updatedFrontmatter.set("lastSyncedAt", metadata.lastSyncedAt);
517
+ updatedFrontmatter.delete("provisional");
518
+ const orderedKeys = ["swarmcraftVersion", "projectId", "ticketId", "title", "lane", "syncRevision", "lastSyncedAt"];
519
+ const rewrittenFrontmatter = orderedKeys.filter((key) => updatedFrontmatter.has(key)).map((key) => `${key}: ${updatedFrontmatter.get(key)}`).join("\n");
520
+ return `---
521
+ ${rewrittenFrontmatter}
522
+ ---
523
+ ${body.startsWith("\n") ? body : `
524
+ ${body}`}`;
525
+ }
526
+ function rewritePacketFile(input2) {
527
+ let rewritten = rewritePacketFileMetadata3(input2.contents, {
528
+ lane: input2.lane,
529
+ syncRevision: parsePacketFile3(input2.contents).frontmatter.syncRevision,
530
+ lastSyncedAt: input2.syncedAt ?? (/* @__PURE__ */ new Date()).toISOString()
531
+ });
532
+ rewritten = markChecklistStageComplete(rewritten, input2.completeStage);
533
+ return appendAgentUpdateLines(rewritten, input2.agentUpdateLines);
534
+ }
535
+ function markChecklistStageComplete(contents, checklistStage) {
536
+ const heading = checklistSectionHeading(checklistStage);
537
+ const sectionPattern = new RegExp(`(## ${escapeRegExp(heading)}\\n\\n)([\\s\\S]*?)(?=\\n## |$)`);
538
+ return contents.replace(sectionPattern, (_match, prefix, body) => {
539
+ const updatedBody = body.split("\n").map((line) => line.replace(/^- \[ \] /, "- [x] ")).join("\n");
540
+ return `${prefix}${updatedBody}`;
541
+ });
542
+ }
543
+ function appendAgentUpdateLines(contents, lines) {
544
+ if (lines.length === 0) {
545
+ return contents;
546
+ }
547
+ const sectionPattern = /(## Agent Update\n\n)([\s\S]*?)$/;
548
+ return contents.replace(sectionPattern, (_match, prefix, body) => {
549
+ const normalizedBody = normalizeSectionText(body);
550
+ return `${prefix}${[normalizedBody, ...lines].filter(Boolean).join("\n")}
551
+ `;
552
+ });
553
+ }
554
+ function composeTicketNotes2(notes, agentUpdate) {
555
+ const normalizedNotes = normalizeSectionText(notes);
556
+ const normalizedAgentUpdate = normalizeSectionText(agentUpdate);
557
+ if (!normalizedNotes && !normalizedAgentUpdate) {
558
+ return null;
559
+ }
560
+ if (normalizedNotes && !normalizedAgentUpdate) {
561
+ return normalizedNotes;
562
+ }
563
+ if (!normalizedNotes && normalizedAgentUpdate) {
564
+ return ["## Agent Update", "", normalizedAgentUpdate].join("\n");
565
+ }
566
+ return ["## Notes", "", normalizedNotes, "", "## Agent Update", "", normalizedAgentUpdate].join("\n");
567
+ }
568
+ function ensurePacketFileIdentity2(contents, projectId, ticketId) {
569
+ const { frontmatter } = parsePacketFileDocument(contents);
570
+ if (frontmatter.projectId !== projectId || frontmatter.ticketId !== ticketId) {
571
+ throw new PacketFileContractError2("PACKET_FILE_MISMATCH", `The existing packet file is linked to ${frontmatter.ticketId ?? "another ticket"} and cannot be reused for ${ticketId}.`);
572
+ }
573
+ }
574
+ function ensurePacketMatches(packet, projectId, ticketId) {
575
+ if (packet.frontmatter.projectId !== projectId || packet.frontmatter.ticketId !== ticketId) {
576
+ throw new PacketFileContractError2("PACKET_FILE_MISMATCH", `The packet file belongs to ${packet.frontmatter.ticketId} and cannot sync into ${ticketId}.`);
577
+ }
578
+ }
579
+ function isProvisionalPacketFile(packet) {
580
+ return packet.frontmatter.provisional && packet.frontmatter.ticketId.startsWith(exports2.PROVISIONAL_TICKET_ID_PREFIX) && packet.frontmatter.lane === "todo" && packet.frontmatter.syncRevision === 0;
581
+ }
582
+ function assertProvisionalPacketFile(packet) {
583
+ if (!isProvisionalPacketFile(packet)) {
584
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "Provisional packets must use provisional: true, ticketId: provisional:<slug>, lane: todo, and syncRevision: 0.");
585
+ }
586
+ const title = packet.frontmatter.title?.trim();
587
+ if (!title) {
588
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "Provisional packets must include a title frontmatter value.");
589
+ }
590
+ if (!packet.sections.goal.trim()) {
591
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "Provisional packets must include a Goal section.");
592
+ }
593
+ for (const checklistStage of exports2.CHECKLIST_STAGES) {
594
+ for (const checklistItem of packet.sections.checklists[checklistStage]) {
595
+ if (checklistItem.completed) {
596
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "Provisional packet checklist items must start unchecked.");
597
+ }
598
+ }
599
+ }
600
+ }
601
+ function findChecklistShapeProblem2(currentChecklistItems, parsedChecklistItemsByStage) {
602
+ for (const checklistStage of exports2.CHECKLIST_STAGES) {
603
+ const orderedChecklistItems = listChecklistItemsForStage2(currentChecklistItems, checklistStage);
604
+ const parsedChecklistItems = parsedChecklistItemsByStage[checklistStage];
605
+ if (orderedChecklistItems.length !== parsedChecklistItems.length) {
606
+ return {
607
+ code: "length",
608
+ checklistStage,
609
+ message: "Checklist item additions, removals, or reordering are not supported from the packet file yet."
610
+ };
611
+ }
612
+ for (const [index, checklistItem] of orderedChecklistItems.entries()) {
613
+ if (checklistItem.body.trim() !== parsedChecklistItems[index]?.body.trim()) {
614
+ return {
615
+ code: "body",
616
+ checklistStage,
617
+ message: "Checklist item text edits are not supported from the packet file yet. Only checkbox completion can sync back to SwarmCraft."
618
+ };
619
+ }
620
+ }
621
+ }
622
+ return null;
623
+ }
624
+ function assertChecklistShape(currentChecklistItems, parsedChecklistItemsByStage) {
625
+ const problem = findChecklistShapeProblem2(currentChecklistItems, parsedChecklistItemsByStage);
626
+ if (problem) {
627
+ throw new PacketFileContractError2("PACKET_FILE_UNSUPPORTED_CHECKLIST", problem.message);
628
+ }
629
+ }
630
+ function listChecklistItemsForStage2(checklistItems, checklistStage) {
631
+ return checklistItems.filter((item) => item.checklistStage === checklistStage).slice().sort((left, right) => Number(left.itemOrder ?? 0) - Number(right.itemOrder ?? 0));
632
+ }
633
+ function allChecklistItemsComplete2(ticket, checklistStage) {
634
+ const items = listChecklistItemsForStage2(ticket.checklistItems, checklistStage);
635
+ return items.length === 0 || items.every((item) => item.completed);
636
+ }
637
+ function splitStoredTicketNotes(storedNotes) {
638
+ if (!storedNotes?.trim()) {
639
+ return { notes: "", agentUpdate: "" };
640
+ }
641
+ if (!storedNotes.includes("##")) {
642
+ return { notes: storedNotes.trim(), agentUpdate: "" };
643
+ }
644
+ const sections = parseSections(storedNotes);
645
+ return {
646
+ notes: normalizeSectionText(sections.Notes ?? storedNotes),
647
+ agentUpdate: normalizeSectionText(sections["Agent Update"] ?? "")
648
+ };
649
+ }
650
+ function normalizeSectionText(value) {
651
+ return String(value ?? "").split("\n").map((line) => line.trimEnd()).filter((line) => !isHtmlComment(line.trim())).join("\n").trim();
652
+ }
653
+ function previewText(value) {
654
+ const normalized = normalizeSectionText(value).replace(/\s+/g, " ").trim();
655
+ if (!normalized) {
656
+ return null;
657
+ }
658
+ return normalized.length > 240 ? `${normalized.slice(0, 237)}...` : normalized;
659
+ }
660
+ function slugify(value) {
661
+ return String(value).normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "packet";
662
+ }
663
+ function parsePacketFileDocument(contents) {
664
+ const match = contents.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
665
+ if (!match) {
666
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "The packet file is missing SwarmCraft frontmatter.");
667
+ }
668
+ const frontmatterBlock = match[1] ?? "";
669
+ return {
670
+ frontmatter: parseFrontmatterEntries(frontmatterBlock),
671
+ frontmatterLines: frontmatterBlock.split("\n").map((line) => line.trim()).filter(Boolean),
672
+ body: match[2] ?? ""
673
+ };
674
+ }
675
+ function parseFrontmatterEntries(frontmatterBlock) {
676
+ const entries = frontmatterBlock.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
677
+ const separatorIndex = line.indexOf(":");
678
+ if (separatorIndex < 0) {
679
+ return null;
680
+ }
681
+ const key = line.slice(0, separatorIndex).trim();
682
+ const value = parseFrontmatterValue(line.slice(separatorIndex + 1).trim());
683
+ return [key, value];
684
+ }).filter((entry) => entry !== null);
685
+ return Object.fromEntries(entries);
686
+ }
687
+ function parseFrontmatterValue(value) {
688
+ if (value.startsWith('"') && value.endsWith('"')) {
689
+ try {
690
+ return JSON.parse(value);
691
+ } catch {
692
+ return value.replace(/^"|"$/g, "");
693
+ }
694
+ }
695
+ return value;
696
+ }
697
+ function parseNullableFrontmatterValue(value) {
698
+ if (!value || value === "null") {
699
+ return null;
700
+ }
701
+ return value;
702
+ }
703
+ function parseBooleanFrontmatterValue(value) {
704
+ return value === "true";
705
+ }
706
+ function parseSections(body) {
707
+ const sections = {};
708
+ let currentSection = null;
709
+ const sectionLines = /* @__PURE__ */ new Map();
710
+ for (const line of body.split("\n")) {
711
+ const headingMatch = line.match(/^##\s+(.+?)\s*$/);
712
+ if (headingMatch) {
713
+ currentSection = headingMatch[1];
714
+ sectionLines.set(currentSection, []);
715
+ continue;
716
+ }
717
+ if (currentSection) {
718
+ sectionLines.get(currentSection)?.push(line);
719
+ }
720
+ }
721
+ for (const [section, lines] of sectionLines.entries()) {
722
+ sections[section] = lines.join("\n").trim();
723
+ }
724
+ return sections;
725
+ }
726
+ function parseChecklistSections(sections) {
727
+ const hasStagedChecklistSections = exports2.CHECKLIST_STAGES.some((checklistStage) => checklistSectionHeading(checklistStage) in sections);
728
+ if (!hasStagedChecklistSections && "Checklist" in sections) {
729
+ return {
730
+ doing: parseChecklistSection(sections.Checklist ?? ""),
731
+ checking: [],
732
+ reviewing: []
733
+ };
734
+ }
735
+ return {
736
+ doing: parseChecklistSection(sections[checklistSectionHeading("doing")] ?? ""),
737
+ checking: parseChecklistSection(sections[checklistSectionHeading("checking")] ?? ""),
738
+ reviewing: parseChecklistSection(sections[checklistSectionHeading("reviewing")] ?? "")
739
+ };
740
+ }
741
+ function parseChecklistSection(contents) {
742
+ const entries = [];
743
+ for (const rawLine of contents.split("\n")) {
744
+ const line = rawLine.trim();
745
+ if (!line || isHtmlComment(line)) {
746
+ continue;
747
+ }
748
+ const match = line.match(/^- \[([ xX])\] (.+)$/);
749
+ if (!match) {
750
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "Checklist entries must use the markdown checkbox form '- [ ] item'.");
751
+ }
752
+ entries.push({
753
+ completed: match[1].toLowerCase() === "x",
754
+ body: match[2].trim()
755
+ });
756
+ }
757
+ return entries;
758
+ }
759
+ function parseLane(value) {
760
+ if (exports2.WORKFLOW_STATES.includes(value)) {
761
+ return value;
762
+ }
763
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", "The packet file lane frontmatter must be one of todo, doing, checking, reviewing, or done.");
764
+ }
765
+ function requireFrontmatterValue(value, key) {
766
+ if (!value) {
767
+ throw new PacketFileContractError2("PACKET_FILE_MALFORMED", `The packet file is missing the required ${key} frontmatter value.`);
768
+ }
769
+ return value;
770
+ }
771
+ function checklistSectionHeading(checklistStage) {
772
+ if (checklistStage === "doing") {
773
+ return "Doing Checklist";
774
+ }
775
+ if (checklistStage === "checking") {
776
+ return "Checking Checklist";
777
+ }
778
+ return "Reviewing Checklist";
779
+ }
780
+ function isHtmlComment(value) {
781
+ return /^<!--.*-->$/.test(value.trim());
782
+ }
783
+ function escapeRegExp(value) {
784
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
785
+ }
786
+ function escapeFrontmatterValue(value) {
787
+ return JSON.stringify(value ?? "");
788
+ }
789
+ }
790
+ });
791
+
792
+ // ../../packages/packet-workflow/dist/workflowContract.js
793
+ var require_workflowContract = __commonJS({
794
+ "../../packages/packet-workflow/dist/workflowContract.js"(exports2) {
795
+ "use strict";
796
+ Object.defineProperty(exports2, "__esModule", { value: true });
797
+ exports2.SWARMCRAFT_STAGE_CONTRACTS = exports2.STAGE_COMMAND_TICKET_HINT = exports2.PACKET_SECTIONS = void 0;
798
+ exports2.getSwarmCraftStageContract = getSwarmCraftStageContract;
799
+ exports2.renderStageCommandLine = renderStageCommandLine;
800
+ exports2.renderNumberedLines = renderNumberedLines;
801
+ exports2.renderBullets = renderBullets;
802
+ exports2.findMissingStageCommandAdapters = findMissingStageCommandAdapters;
803
+ exports2.PACKET_SECTIONS = [
804
+ "## Goal",
805
+ "## Doing Checklist",
806
+ "## Checking Checklist",
807
+ "## Reviewing Checklist",
808
+ "## Notes",
809
+ "## Agent Update"
810
+ ];
811
+ exports2.STAGE_COMMAND_TICKET_HINT = "ticket=.swarmcraft/projects/<project-slug>/<ticket>.md";
812
+ exports2.SWARMCRAFT_STAGE_CONTRACTS = [
813
+ {
814
+ key: "doing",
815
+ command: "\\do",
816
+ commandDescription: "doing-lane implementation",
817
+ promptTitle: "Do Ticket",
818
+ promptDescription: "Implements a linked SwarmCraft ticket packet using the doing-stage workflow",
819
+ promptScope: "execution contract for the current ticket",
820
+ promptAction: "implementing code",
821
+ agentTitle: "SwarmCraft Implementor",
822
+ agentPurpose: "Implement the current SwarmCraft-scoped ticket from its packet and keep the packet aligned with the code.",
823
+ agentDescription: "Use when implementing a SwarmCraft packet, doing-lane ticket, scoped code change, or packet-driven repo update",
824
+ agentArgumentHint: "packet=... [scope=...]",
825
+ laneInstructionsTitle: "Doing Instructions",
826
+ checklistName: "Doing",
827
+ noteHeading: "### Implementation Notes",
828
+ laneInstructions: [
829
+ "Use the linked planning packet as the source of truth for scope and status.",
830
+ "Implement only the work needed for the current ticket.",
831
+ "Add or update `### Implementation Notes` under `## Notes` with what changed, important decisions, files touched, validation run, and what remains open.",
832
+ "Mark every completed Doing checklist item as done as soon as repository state and validation support it.",
833
+ "Update the packet checklist and `## Agent Update` as work progresses.",
834
+ "When all Doing checklist items are complete and there are no unresolved blockers, questions, or validation gaps, set packet frontmatter `lane: checking` so packet sync moves the ticket forward.",
835
+ "If `SWARMCRAFT_DRIVER_AUTO_COMMIT=true`, do not create a git commit; the headless build driver commits after packet sync. Otherwise, create a local git commit for the scoped ticket changes once the Doing work is complete.",
836
+ "Leave the ticket in doing only when implementation work remains blocked, incomplete, or unproven, and record the reason in the packet.",
837
+ "Keep unrelated files untouched unless the packet explicitly requires adjacent work.",
838
+ "Prefer focused tests or narrow validation for the touched slice before moving the ticket forward."
839
+ ],
840
+ promptRequirements: [
841
+ "Treat `${input:ticket}` as the execution contract for the current ticket.",
842
+ "Read the packet frontmatter, goal, doing checklist, notes, and agent update before editing code.",
843
+ "Implement only the smallest scoped change needed to advance the packet.",
844
+ "Keep unrelated files untouched unless the packet explicitly requires adjacent work.",
845
+ "Update packet checklist items only when the repository state actually supports them.",
846
+ "Add or update `### Implementation Notes` under `## Notes` with what changed, important decisions, files touched, validation run, and what remains open.",
847
+ "Mark every completed Doing checklist item as done once code and validation support it.",
848
+ "Update `## Agent Update` with a concise implementation summary for the checking agent.",
849
+ "If all Doing checklist items are complete and no blockers, questions, or validation gaps remain, set packet frontmatter `lane: checking` so packet sync moves the ticket forward.",
850
+ "If `SWARMCRAFT_DRIVER_AUTO_COMMIT=true`, leave the git commit to the headless build driver. Otherwise, stage and commit only the scoped ticket changes, including the packet file, using `Complete <ticket-id>: <ticket-title>`.",
851
+ "If implementation is incomplete or unproven, keep `lane: doing` and record the blocker or remaining work in the packet."
852
+ ],
853
+ agentWorkflow: [
854
+ "Restate the packet goal and choose the smallest implementation slice.",
855
+ "Inspect only the nearest controlling code path and one cheap disconfirming check before the first edit.",
856
+ "Implement the smallest plausible change.",
857
+ "Run focused validation immediately after the first substantive edit.",
858
+ "Add or update `### Implementation Notes` under `## Notes` with what changed, important decisions, files touched, validation run, and what remains open.",
859
+ "Mark every completed Doing checklist item as done once the repo state and validation support it.",
860
+ "Update `## Agent Update` with a concise implementation summary for the checking agent.",
861
+ "If all Doing checklist items are complete and no blockers, questions, or validation gaps remain, set packet frontmatter `lane: checking`.",
862
+ "If `SWARMCRAFT_DRIVER_AUTO_COMMIT=true`, stop after packet updates so the driver can sync and commit. Otherwise, stage and commit only the scoped ticket changes, including the packet file, before finishing.",
863
+ "If any Doing item remains incomplete or unproven, keep `lane: doing` and record the blocker or remaining work in the packet."
864
+ ],
865
+ outputItems: [
866
+ "What changed",
867
+ "Validation run",
868
+ "Packet updates made, including `### Implementation Notes`, completed Doing checklist items, and any lane change",
869
+ "Commit created, driver-managed commit noted, or commit blocker",
870
+ "Remaining risks or next step"
871
+ ],
872
+ stageSummary: "Doing: implement the scoped work, add `### Implementation Notes`, mark completed Doing checklist items, set `lane: checking`, and ensure the completed work is committed by either the agent or the headless driver.",
873
+ completionRule: "Set the packet frontmatter `lane` to `checking` so packet sync moves the ticket forward."
874
+ },
875
+ {
876
+ key: "checking",
877
+ command: "\\check",
878
+ commandDescription: "checking-lane machine judgment",
879
+ promptTitle: "Check Ticket",
880
+ promptDescription: "Validates a linked SwarmCraft ticket packet using the checking-stage workflow",
881
+ promptScope: "source of truth for the checking scope",
882
+ promptAction: "checking implementation evidence",
883
+ agentTitle: "SwarmCraft Checker",
884
+ agentPurpose: "Validate a SwarmCraft packet against the repo state, focused checks, and acceptance criteria before it moves forward.",
885
+ agentDescription: "Use when validating a SwarmCraft packet, checking-lane ticket, focused test pass, or packet readiness before review",
886
+ agentArgumentHint: "packet=... [validation=...]",
887
+ laneInstructionsTitle: "Checking Instructions",
888
+ checklistName: "Checking",
889
+ noteHeading: "### Checking Feedback",
890
+ laneInstructions: [
891
+ "Validate the implementation against the packet checklist and acceptance criteria.",
892
+ "Treat checking as a judge lane: accept the work toward human review or reject it back to doing with clear feedback.",
893
+ "Do not fix implementation defects during checking unless the user explicitly asks.",
894
+ "Run the narrowest tests, lint, or typecheck that can falsify the change.",
895
+ "Confirm the packet notes and agent update match the actual code and board state.",
896
+ "Mark every proven Checking checklist item as done once validation and repository state support it.",
897
+ "On rejection, add `### Checking Feedback` under `## Notes`, summarize the rejection in `## Agent Update`, leave failed or unproven checklist items unchecked, and set packet frontmatter `lane: doing`.",
898
+ "On acceptance, record validation evidence, complete only proven checking checklist items, update `## Agent Update`, and set packet frontmatter `lane: reviewing`.",
899
+ "Leave the ticket in checking only when validation cannot reach a clear accept or reject decision."
900
+ ],
901
+ promptRequirements: [
902
+ "Treat `${input:ticket}` as the source of truth for the checking scope.",
903
+ "Read the packet goal, checking checklist, notes, agent update, and any implementation evidence before changing files.",
904
+ "Act as a judge for the implementation. Do not fix implementation defects during checking unless the user explicitly asks.",
905
+ "Run the narrowest validation that can disconfirm the implementation.",
906
+ "Mark every proven Checking checklist item as done once validation and repository state support it.",
907
+ "If validation fails, leave failed or unproven checking checklist items unchecked and add a `### Checking Feedback` entry under `## Notes` with the failed item, evidence, validation result, and required fix.",
908
+ "On rejection, update `## Agent Update` with a concise rejection summary and set the packet frontmatter `lane` to `doing` so packet sync moves the ticket back for implementation.",
909
+ "If all Checking checklist items pass and no blockers, questions, or validation gaps remain, update the checking checklist, notes, and agent update to match the evidence.",
910
+ "On acceptance, set the packet frontmatter `lane` to `reviewing` so packet sync moves the ticket forward for human review.",
911
+ "Leave the ticket in checking only when validation could not reach a clear accept or reject decision, and record why in the packet."
912
+ ],
913
+ agentWorkflow: [
914
+ "List the acceptance criteria or packet checklist items that need validation.",
915
+ "Run the smallest test, typecheck, lint, or targeted command that can disconfirm the change.",
916
+ "Mark every proven Checking checklist item as done once validation and repo state support it.",
917
+ "If validation fails or any Checking item is unproven, add `### Checking Feedback` under `## Notes`, summarize rejection in `## Agent Update`, leave failed or unproven items unchecked, and set packet frontmatter `lane: doing`.",
918
+ "If all Checking checklist items pass and no blockers, questions, or validation gaps remain, update packet notes and `## Agent Update`, then set packet frontmatter `lane: reviewing`.",
919
+ "Leave the ticket in checking only when validation cannot reach a clear accept or reject decision, and record why in the packet."
920
+ ],
921
+ outputItems: [
922
+ "Validation performed",
923
+ "Pass or fail result",
924
+ "Packet updates made, including completed Checking checklist items and any lane change",
925
+ "Rejection feedback, review promotion, or unresolved validation blocker"
926
+ ],
927
+ stageSummary: "Checking: judge the result against checklist, tests, and acceptance criteria; accept forward to reviewing or reject back to doing with `### Checking Feedback`.",
928
+ completionRule: "Set the packet frontmatter `lane` to `reviewing` so packet sync moves the ticket forward for human review."
929
+ },
930
+ {
931
+ key: "reviewing",
932
+ command: "\\review",
933
+ commandDescription: "reviewing-lane human approval",
934
+ promptTitle: "Review Ticket",
935
+ promptDescription: "Guides human approval of a linked SwarmCraft ticket packet using the reviewing-stage workflow",
936
+ promptScope: "source of truth for the reviewing scope",
937
+ promptAction: "asking for human review",
938
+ agentTitle: "SwarmCraft Reviewer",
939
+ agentPurpose: "Guide the human review of a SwarmCraft packet and record explicit user approval before any Reviewing checklist item is marked complete.",
940
+ agentDescription: "Use when guiding human approval of a SwarmCraft packet, prompting for reviewing checklist confirmation, and recording review decisions without expanding scope",
941
+ agentArgumentHint: "packet=...",
942
+ laneInstructionsTitle: "Reviewing Instructions",
943
+ checklistName: "Reviewing",
944
+ noteHeading: "### Review Notes",
945
+ laneInstructions: [
946
+ "Guide human approval; do not act as another checking pass unless the user explicitly asks.",
947
+ "Confirm the packet is current, concise, and ready to present to the human reviewer.",
948
+ "Ask the user to confirm each Reviewing checklist item before marking it complete.",
949
+ "Use existing repository evidence or validation only to explain what the user should inspect before approving; do not infer approval from evidence alone.",
950
+ "Add or update `### Review Notes` under `## Notes` with user approvals, rejected review items, risks, and open questions.",
951
+ "Mark a Reviewing checklist item as done only after explicit user approval for that item.",
952
+ "If all Reviewing checklist items are explicitly approved and no unresolved risk remains, state in `## Agent Update` that the packet is ready for the extension's Move to Done action.",
953
+ "Do not set packet frontmatter `lane: done`; the SwarmCraft extension owns the final done transition.",
954
+ "Call out risks, open questions, and follow-up work in the Agent Update section.",
955
+ "Leave the implementation state reproducible from the repo and the packet alone.",
956
+ "Do not hide unfinished work behind verbal handoff; record it in the packet instead."
957
+ ],
958
+ promptRequirements: [
959
+ "Treat `${input:ticket}` as the source of truth for the reviewing scope.",
960
+ "Read the packet goal, reviewing checklist, notes, agent update, and validation evidence before asking for approval.",
961
+ "Prompt the user for each reviewing checklist item one at a time.",
962
+ "When possible, explain what repository evidence, validation result, or behavior the user should inspect before approving the item.",
963
+ "Ask the user to confirm whether each review item is complete and approved.",
964
+ "Record confirmed approvals in the packet by updating the reviewing checklist and adding or updating `### Review Notes` under `## Notes`.",
965
+ "Mark a Reviewing checklist item as done only after the user explicitly confirms that item is approved.",
966
+ "Do not infer approval from repository evidence, prior validation, or your own assessment; evidence is only context for the user's decision.",
967
+ "Leave unapproved, unanswered, or uncertain items unchecked and record the reason under `### Review Notes`.",
968
+ "Update `## Agent Update` with a concise human-review summary, including approvals, rejected items, and any remaining risk.",
969
+ "If all Reviewing checklist items are explicitly approved and no unresolved risk remains, state that the packet is ready for the extension's Move to Done action.",
970
+ "Do not set packet frontmatter `lane: done`. The SwarmCraft extension owns the board transition after review approval."
971
+ ],
972
+ agentWorkflow: [
973
+ "Read the packet goal, reviewing checklist, notes, agent update, and existing validation evidence so you can frame the review questions.",
974
+ "Ask the user to confirm each Reviewing checklist item. Prefer one clear question at a time unless the user asks for a grouped review.",
975
+ "For each question, summarize the relevant existing evidence or risk the user should consider before approving.",
976
+ "Mark a Reviewing checklist item as done only after the user explicitly confirms that item is approved.",
977
+ "Leave rejected, unanswered, or uncertain Reviewing items unchecked and record the user's reason under `### Review Notes`.",
978
+ "Update `## Agent Update` with a concise human-review summary based on the user's answers.",
979
+ "If all Reviewing checklist items are explicitly approved and no unresolved risk remains, state that the packet is ready for the extension's Move to Done action without changing `lane` to `done`.",
980
+ "If any Reviewing item remains unapproved or uncertain, keep `lane: reviewing` and record the remaining approval or risk in the packet."
981
+ ],
982
+ outputItems: [
983
+ "Review-readiness assessment",
984
+ "Packet edits made, including `### Review Notes` and completed Reviewing checklist items",
985
+ "Risks or open questions",
986
+ "Recommended next step"
987
+ ],
988
+ stageSummary: "Reviewing: ask the user to confirm each reviewing item, record `### Review Notes`, mark items only after explicit human approval, and leave the board move to done for the extension.",
989
+ completionRule: "Do not set packet frontmatter `lane: done`; state that the packet is ready for the extension's Move to Done action."
990
+ }
991
+ ];
992
+ function getSwarmCraftStageContract(stageKey) {
993
+ const stage = exports2.SWARMCRAFT_STAGE_CONTRACTS.find((candidate) => candidate.key === stageKey);
994
+ if (!stage) {
995
+ throw new Error(`Unknown SwarmCraft workflow stage: ${stageKey}`);
996
+ }
997
+ return stage;
998
+ }
999
+ function renderStageCommandLine(stage) {
1000
+ return `- \`${stage.command} ${exports2.STAGE_COMMAND_TICKET_HINT}\` for ${stage.commandDescription}`;
1001
+ }
1002
+ function renderNumberedLines(lines, startAt = 1) {
1003
+ return lines.map((line, index) => `${index + startAt}. ${line}`);
1004
+ }
1005
+ function renderBullets(lines) {
1006
+ return lines.map((line) => `- ${line}`);
1007
+ }
1008
+ function findMissingStageCommandAdapters(expectedProviders, adapters) {
1009
+ const missing = [];
1010
+ for (const provider of expectedProviders) {
1011
+ const providerAdapters = adapters.filter((adapter) => adapter.provider === provider);
1012
+ for (const stage of exports2.SWARMCRAFT_STAGE_CONTRACTS) {
1013
+ const hasAdapter = providerAdapters.some((adapter) => adapter.stage === stage.key);
1014
+ if (!hasAdapter) {
1015
+ missing.push(`${provider} is missing ${stage.command} adapter`);
1016
+ }
1017
+ }
1018
+ }
1019
+ return missing;
1020
+ }
1021
+ }
1022
+ });
1023
+
1024
+ // ../../packages/packet-workflow/dist/stageCommands.js
1025
+ var require_stageCommands = __commonJS({
1026
+ "../../packages/packet-workflow/dist/stageCommands.js"(exports2) {
1027
+ "use strict";
1028
+ Object.defineProperty(exports2, "__esModule", { value: true });
1029
+ exports2.DEFAULT_SWARMCRAFT_AGENT_PROVIDER = exports2.SWARMCRAFT_AGENT_PROVIDERS = void 0;
1030
+ exports2.buildPacketStageCommand = buildPacketStageCommand2;
1031
+ exports2.buildAssistantActionCommand = buildAssistantActionCommand;
1032
+ exports2.formatTicketArgument = formatTicketArgument;
1033
+ var assistantActions_js_1 = require_assistantActions();
1034
+ var workflowContract_js_1 = require_workflowContract();
1035
+ exports2.SWARMCRAFT_AGENT_PROVIDERS = ["copilot", "codex"];
1036
+ exports2.DEFAULT_SWARMCRAFT_AGENT_PROVIDER = "copilot";
1037
+ var COMMAND_BY_WORKFLOW_STATE = Object.fromEntries(workflowContract_js_1.SWARMCRAFT_STAGE_CONTRACTS.map((stage) => [
1038
+ stage.key,
1039
+ {
1040
+ actionKey: toStageName(stage.command),
1041
+ stageName: toStageName(stage.command)
1042
+ }
1043
+ ]));
1044
+ function buildPacketStageCommand2(input2) {
1045
+ const commandParts = COMMAND_BY_WORKFLOW_STATE[input2.workflowState];
1046
+ if (!commandParts) {
1047
+ return null;
1048
+ }
1049
+ return buildAssistantActionCommand({
1050
+ actionKey: commandParts.actionKey,
1051
+ relativePacketFilePath: input2.relativePacketFilePath,
1052
+ agentProvider: input2.agentProvider
1053
+ });
1054
+ }
1055
+ function buildAssistantActionCommand(input2) {
1056
+ const action = (0, assistantActions_js_1.getSwarmCraftAssistantAction)(input2.actionKey);
1057
+ const agentProvider = input2.agentProvider ?? exports2.DEFAULT_SWARMCRAFT_AGENT_PROVIDER;
1058
+ const invocation = agentProvider === "codex" ? action.codexInvocation : action.copilotInvocation;
1059
+ const command = input2.relativePacketFilePath ? invocation.replace("<packet-path>", formatTicketArgument(input2.relativePacketFilePath)) : invocation;
1060
+ const args = [];
1061
+ if (input2.relativePacketFilePath && command === invocation) {
1062
+ const packetArgumentName = input2.actionKey === "test" ? "ticket" : "scope";
1063
+ args.push(`${packetArgumentName}=${formatTicketArgument(input2.relativePacketFilePath)}`);
1064
+ }
1065
+ if (input2.scope?.trim()) {
1066
+ args.push(`scope=${formatTicketArgument(input2.scope.trim())}`);
1067
+ }
1068
+ return [command, ...args].join(" ");
1069
+ }
1070
+ function formatTicketArgument(relativePacketFilePath) {
1071
+ if (!/\s/.test(relativePacketFilePath)) {
1072
+ return relativePacketFilePath;
1073
+ }
1074
+ return `"${relativePacketFilePath.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
1075
+ }
1076
+ function toStageName(command) {
1077
+ return command.slice(1);
1078
+ }
1079
+ }
1080
+ });
1081
+
1082
+ // ../../packages/packet-workflow/dist/index.js
1083
+ var require_dist = __commonJS({
1084
+ "../../packages/packet-workflow/dist/index.js"(exports2) {
1085
+ "use strict";
1086
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
1087
+ if (k2 === void 0) k2 = k;
1088
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1089
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1090
+ desc = { enumerable: true, get: function() {
1091
+ return m[k];
1092
+ } };
1093
+ }
1094
+ Object.defineProperty(o, k2, desc);
1095
+ }) : (function(o, m, k, k2) {
1096
+ if (k2 === void 0) k2 = k;
1097
+ o[k2] = m[k];
1098
+ }));
1099
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
1100
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
1101
+ };
1102
+ Object.defineProperty(exports2, "__esModule", { value: true });
1103
+ __exportStar(require_assistantActions(), exports2);
1104
+ __exportStar(require_agentProviders(), exports2);
1105
+ __exportStar(require_manifest(), exports2);
1106
+ __exportStar(require_packetFile(), exports2);
1107
+ __exportStar(require_stageCommands(), exports2);
1108
+ __exportStar(require_workflowContract(), exports2);
1109
+ }
1110
+ });
1111
+
1112
+ // ../../packages/repo-seed/dist/projectSeedModels.js
1113
+ var require_projectSeedModels = __commonJS({
1114
+ "../../packages/repo-seed/dist/projectSeedModels.js"(exports2) {
1115
+ "use strict";
1116
+ Object.defineProperty(exports2, "__esModule", { value: true });
1117
+ }
1118
+ });
1119
+
1120
+ // ../../packages/repo-seed/dist/templates/renderCopilotAgents.js
1121
+ var require_renderCopilotAgents = __commonJS({
1122
+ "../../packages/repo-seed/dist/templates/renderCopilotAgents.js"(exports2) {
1123
+ "use strict";
1124
+ Object.defineProperty(exports2, "__esModule", { value: true });
1125
+ exports2.renderPacketInstructionsFile = renderPacketInstructionsFile;
1126
+ exports2.renderImplementorAgentFile = renderImplementorAgentFile;
1127
+ exports2.renderCheckerAgentFile = renderCheckerAgentFile;
1128
+ exports2.renderReviewerAgentFile = renderReviewerAgentFile;
1129
+ var packet_workflow_1 = require_dist();
1130
+ function renderPacketInstructionsFile() {
1131
+ return [
1132
+ "---",
1133
+ 'description: "Auto-applied SwarmCraft packet rules for planning packets under .swarmcraft/projects and related workflow guidance files"',
1134
+ 'applyTo: ".swarmcraft/**/*.md"',
1135
+ "---",
1136
+ "",
1137
+ "# SwarmCraft Packet Instructions",
1138
+ "",
1139
+ "Use SwarmCraft packet files as the source of truth for scoped ticket work and status updates.",
1140
+ "",
1141
+ "## Packet Contract",
1142
+ "",
1143
+ "* Preserve packet identity and sync fields such as `projectId`, `ticketId`, and `syncRevision` unless SwarmCraft itself rewrites them.",
1144
+ "* Edit packet frontmatter `lane` only when a SwarmCraft stage prompt or lane guidance explicitly tells you to request an adjacent workflow move.",
1145
+ `* Preserve the staged packet structure: ${packet_workflow_1.PACKET_SECTIONS.map((section) => `\`${section}\``).join(", ")}.`,
1146
+ "* Treat checklist text as board-owned scope; mark items complete only when the repo state actually supports it.",
1147
+ "* Reviewing checklist items require explicit human approval before they are marked complete; repository evidence can inform the question but cannot replace the human confirmation.",
1148
+ "* When all checklist items for the current lane are complete and no unresolved blocker or question remains, set packet frontmatter `lane` to the next adjacent workflow lane unless the reviewing-to-done transition is owned by the SwarmCraft extension.",
1149
+ "* Keep `## Notes` factual and implementation-specific. Use `### Implementation Notes`, `### Checking Feedback`, and `### Review Notes` for stage-specific packet comments.",
1150
+ "* Keep `## Agent Update` short and structured around what changed, what was validated, and what remains blocked or risky.",
1151
+ "",
1152
+ "## Workflow Expectations",
1153
+ "",
1154
+ "* Read `.swarmcraft/AGENTS.md`, `.swarmcraft/project.instructions.md`, and `.swarmcraft/project.context.md` before making substantive ticket changes when those files exist.",
1155
+ "* Use the lane-specific guidance in `.swarmcraft/agents/` for the current workflow stage.",
1156
+ "* Keep packet notes and agent update aligned with the actual code, validation status, and ticket state.",
1157
+ "* Prefer small, reviewable edits and the narrowest validation that can falsify the change.",
1158
+ "* If the packet and repo diverge, reconcile them explicitly instead of hiding the mismatch in chat only.",
1159
+ ""
1160
+ ].join("\n");
1161
+ }
1162
+ function renderImplementorAgentFile() {
1163
+ const stage = (0, packet_workflow_1.getSwarmCraftStageContract)("doing");
1164
+ return [
1165
+ "---",
1166
+ `name: "${stage.agentTitle}"`,
1167
+ `description: "${stage.agentDescription}"`,
1168
+ "tools: [read, edit, search, execute, todo]",
1169
+ `argument-hint: "${stage.agentArgumentHint}"`,
1170
+ "agents: []",
1171
+ "---",
1172
+ "",
1173
+ `# ${stage.agentTitle}`,
1174
+ "",
1175
+ stage.agentPurpose,
1176
+ "",
1177
+ "## Purpose",
1178
+ "",
1179
+ "* Execute the current packet without inventing extra scope.",
1180
+ "* Keep packet checklist progress, notes, and agent update consistent with the repo.",
1181
+ "* Stop at the smallest validated change that satisfies the ticket.",
1182
+ "",
1183
+ "## Required Context",
1184
+ "",
1185
+ "1. Read `AGENTS.md` and the nearest scoped `AGENTS.md` files for touched code.",
1186
+ "2. Read `.swarmcraft/AGENTS.md`, `.swarmcraft/project.instructions.md`, and `.swarmcraft/project.context.md` when present.",
1187
+ "3. Read the linked packet under `.swarmcraft/projects/` before editing code.",
1188
+ "4. Read `.swarmcraft/agents/doing.instructions.md` when present.",
1189
+ "",
1190
+ "## Constraints",
1191
+ "",
1192
+ "* Do not expand the scope beyond the packet unless the packet itself requires adjacent work.",
1193
+ "* Do not rewrite packet identity fields or staged checklist text.",
1194
+ "* Do not mark checklist items complete until code and validation actually support them.",
1195
+ "* Do not ask whether to update completed Doing checklist items or move to checking when the evidence is complete; update the packet directly.",
1196
+ "* Prefer the narrowest tests or checks that can falsify the change.",
1197
+ "",
1198
+ "## Workflow",
1199
+ "",
1200
+ ...(0, packet_workflow_1.renderNumberedLines)(stage.agentWorkflow),
1201
+ "",
1202
+ "## Output Format",
1203
+ "",
1204
+ "Return:",
1205
+ "",
1206
+ ...(0, packet_workflow_1.renderBullets)(stage.outputItems),
1207
+ ""
1208
+ ].join("\n");
1209
+ }
1210
+ function renderCheckerAgentFile() {
1211
+ const stage = (0, packet_workflow_1.getSwarmCraftStageContract)("checking");
1212
+ return [
1213
+ "---",
1214
+ `name: "${stage.agentTitle}"`,
1215
+ `description: "${stage.agentDescription}"`,
1216
+ "tools: [read, edit, search, execute, todo]",
1217
+ `argument-hint: "${stage.agentArgumentHint}"`,
1218
+ "agents: []",
1219
+ "---",
1220
+ "",
1221
+ `# ${stage.agentTitle}`,
1222
+ "",
1223
+ stage.agentPurpose,
1224
+ "",
1225
+ "## Purpose",
1226
+ "",
1227
+ "* Falsify the implementation with the narrowest meaningful validation.",
1228
+ "* Act as a machine judge: accept the work toward human review or reject it back to doing.",
1229
+ "* Confirm packet checklist progress and notes still match the repo.",
1230
+ "* Surface regressions, gaps, and incomplete acceptance criteria as packet feedback for the implementor.",
1231
+ "",
1232
+ "## Required Context",
1233
+ "",
1234
+ "1. Read `AGENTS.md` and the nearest scoped `AGENTS.md` files for any validated code.",
1235
+ "2. Read `.swarmcraft/AGENTS.md`, `.swarmcraft/project.instructions.md`, and `.swarmcraft/project.context.md` when present.",
1236
+ "3. Read the linked packet under `.swarmcraft/projects/` before validating.",
1237
+ "4. Read `.swarmcraft/agents/checking.instructions.md` when present.",
1238
+ "",
1239
+ "## Constraints",
1240
+ "",
1241
+ "* Do not repair implementation defects during checking unless the user explicitly asks.",
1242
+ "* Do not broaden validation scope unless the current check exposes a nearby defect.",
1243
+ "* Do not claim success without naming the concrete validation that passed.",
1244
+ "* Do not move unresolved risk out of the packet and into chat only.",
1245
+ "* Do not rewrite packet identity fields or staged checklist text.",
1246
+ "* Do not ask whether to update completed Checking checklist items or move to reviewing when the evidence is complete; update the packet directly.",
1247
+ "",
1248
+ "## Workflow",
1249
+ "",
1250
+ ...(0, packet_workflow_1.renderNumberedLines)(stage.agentWorkflow),
1251
+ "",
1252
+ "## Output Format",
1253
+ "",
1254
+ "Return:",
1255
+ "",
1256
+ ...(0, packet_workflow_1.renderBullets)(stage.outputItems),
1257
+ ""
1258
+ ].join("\n");
1259
+ }
1260
+ function renderReviewerAgentFile() {
1261
+ const stage = (0, packet_workflow_1.getSwarmCraftStageContract)("reviewing");
1262
+ return [
1263
+ "---",
1264
+ `name: "${stage.agentTitle}"`,
1265
+ `description: "${stage.agentDescription}"`,
1266
+ "tools: [read, edit, search, todo]",
1267
+ `argument-hint: "${stage.agentArgumentHint}"`,
1268
+ "agents: []",
1269
+ "---",
1270
+ "",
1271
+ `# ${stage.agentTitle}`,
1272
+ "",
1273
+ stage.agentPurpose,
1274
+ "",
1275
+ "## Purpose",
1276
+ "",
1277
+ "* Prompt the user for each Reviewing checklist decision.",
1278
+ "* Record the user's approval, rejection, uncertainty, and requested follow-up in the packet.",
1279
+ "* Call out risks, missing evidence, and follow-up work explicitly.",
1280
+ "",
1281
+ "## Required Context",
1282
+ "",
1283
+ "1. Read `AGENTS.md` and the nearest scoped `AGENTS.md` files for the touched surface.",
1284
+ "2. Read `.swarmcraft/AGENTS.md`, `.swarmcraft/project.instructions.md`, and `.swarmcraft/project.context.md` when present.",
1285
+ "3. Read the linked packet under `.swarmcraft/projects/` before editing the handoff.",
1286
+ "4. Read `.swarmcraft/agents/reviewing.instructions.md` when present.",
1287
+ "",
1288
+ "## Constraints",
1289
+ "",
1290
+ "* Do not hide unfinished work behind optimistic summaries.",
1291
+ "* Do not rewrite the packet into a changelog; keep it concise and review-oriented.",
1292
+ "* Do not claim review readiness if risks or validation gaps remain unresolved.",
1293
+ "* Do not mark Reviewing checklist items complete from repository evidence alone; every checked item requires explicit human approval in the current review interaction.",
1294
+ "* Do not act as the checking agent. Avoid fresh validation unless the user asks for it; use existing evidence only to help the user decide.",
1295
+ "* Do not set packet frontmatter `lane: done`; the SwarmCraft extension owns the final done transition.",
1296
+ "* Do not rewrite packet identity fields or staged checklist text.",
1297
+ "",
1298
+ "## Workflow",
1299
+ "",
1300
+ ...(0, packet_workflow_1.renderNumberedLines)(stage.agentWorkflow),
1301
+ "",
1302
+ "## Output Format",
1303
+ "",
1304
+ "Return:",
1305
+ "",
1306
+ ...(0, packet_workflow_1.renderBullets)(stage.outputItems),
1307
+ ""
1308
+ ].join("\n");
1309
+ }
1310
+ }
1311
+ });
1312
+
1313
+ // ../../packages/repo-seed/dist/templates/renderCodexAgents.js
1314
+ var require_renderCodexAgents = __commonJS({
1315
+ "../../packages/repo-seed/dist/templates/renderCodexAgents.js"(exports2) {
1316
+ "use strict";
1317
+ Object.defineProperty(exports2, "__esModule", { value: true });
1318
+ exports2.renderCodexImplementorAgentFile = renderCodexImplementorAgentFile;
1319
+ exports2.renderCodexCheckerAgentFile = renderCodexCheckerAgentFile;
1320
+ exports2.renderCodexReviewerAgentFile = renderCodexReviewerAgentFile;
1321
+ exports2.renderCodexConfigExampleFile = renderCodexConfigExampleFile;
1322
+ var packet_workflow_1 = require_dist();
1323
+ function renderCodexImplementorAgentFile() {
1324
+ return renderCodexStageAgentFile("doing", "swarmcraft-implementor", "medium");
1325
+ }
1326
+ function renderCodexCheckerAgentFile() {
1327
+ return renderCodexStageAgentFile("checking", "swarmcraft-checker", "medium");
1328
+ }
1329
+ function renderCodexReviewerAgentFile() {
1330
+ return renderCodexStageAgentFile("reviewing", "swarmcraft-reviewer", "low");
1331
+ }
1332
+ function renderCodexConfigExampleFile() {
1333
+ return [
1334
+ "# Example project-scoped Codex config for a SwarmCraft-seeded repository.",
1335
+ "#",
1336
+ "# This file documents optional local setup. It is not loaded automatically.",
1337
+ "# To use it, copy the relevant sections into `.codex/config.toml` or your",
1338
+ "# personal `~/.codex/config.toml`, then adjust local paths and environment variables.",
1339
+ "#",
1340
+ "# Do not commit `.codex/config.toml` if it contains local paths, credentials,",
1341
+ "# tokens, private keys, or machine-specific settings.",
1342
+ "",
1343
+ "# Keep subagent fan-out modest. SwarmCraft's default workflow is one ticket",
1344
+ "# stage at a time: do, check, then review.",
1345
+ "[agents]",
1346
+ "max_threads = 3",
1347
+ "max_depth = 1",
1348
+ "",
1349
+ "# Optional first MCP server for OpenAI or Codex documentation questions.",
1350
+ "# Tool posture: read-only documentation lookup.",
1351
+ "# Secret handling: no secret required.",
1352
+ "#",
1353
+ "# [mcp_servers.openaiDeveloperDocs]",
1354
+ '# url = "https://developers.openai.com/mcp"',
1355
+ "# enabled = true",
1356
+ '# default_tools_approval_mode = "auto"',
1357
+ "",
1358
+ "# Optional browser automation for local UI verification.",
1359
+ "# Tool posture: can open pages, inspect browser state, and drive browser actions.",
1360
+ "# Approval posture: prompt by default because browser tools can interact with",
1361
+ "# local apps and external pages.",
1362
+ "#",
1363
+ "# [mcp_servers.playwright]",
1364
+ '# command = "npx"',
1365
+ '# args = ["-y", "@playwright/mcp"]',
1366
+ "# enabled = true",
1367
+ '# default_tools_approval_mode = "prompt"',
1368
+ "# tool_timeout_sec = 120",
1369
+ ""
1370
+ ].join("\n");
1371
+ }
1372
+ function renderCodexStageAgentFile(stageKey, name, reasoningEffort) {
1373
+ const stage = (0, packet_workflow_1.getSwarmCraftStageContract)(stageKey);
1374
+ const instructions = [
1375
+ `You are the ${stage.agentTitle}.`,
1376
+ "",
1377
+ stage.agentPurpose,
1378
+ "",
1379
+ "Follow this workflow:",
1380
+ ...(0, packet_workflow_1.renderNumberedLines)([
1381
+ "Read `AGENTS.md` and the nearest scoped `AGENTS.md` files for touched code.",
1382
+ "Read `.swarmcraft/AGENTS.md`, `.swarmcraft/project.instructions.md`, and `.swarmcraft/project.context.md` when present.",
1383
+ "Read the linked packet under `.swarmcraft/projects/` before changing files.",
1384
+ `Read \`.swarmcraft/agents/${stage.key}.instructions.md\` when present.`,
1385
+ ...stage.agentWorkflow
1386
+ ]),
1387
+ "",
1388
+ "Output expectations:",
1389
+ ...stage.outputItems.map((item) => `- ${item}`),
1390
+ "",
1391
+ "Stage completion rule:",
1392
+ stage.completionRule,
1393
+ "",
1394
+ "Do not rewrite packet identity fields, board-owned checklist text, unrelated local changes, or workflow history."
1395
+ ].join("\n");
1396
+ return [
1397
+ `name = "${name}"`,
1398
+ `description = "${escapeTomlString(stage.agentDescription)}"`,
1399
+ `model_reasoning_effort = "${reasoningEffort}"`,
1400
+ "",
1401
+ 'developer_instructions = """',
1402
+ instructions,
1403
+ '"""',
1404
+ ""
1405
+ ].join("\n");
1406
+ }
1407
+ function escapeTomlString(value) {
1408
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
1409
+ }
1410
+ }
1411
+ });
1412
+
1413
+ // ../../packages/repo-seed/dist/templates/renderAssistantActionSkills.js
1414
+ var require_renderAssistantActionSkills = __commonJS({
1415
+ "../../packages/repo-seed/dist/templates/renderAssistantActionSkills.js"(exports2) {
1416
+ "use strict";
1417
+ Object.defineProperty(exports2, "__esModule", { value: true });
1418
+ exports2.renderSwarmCraftActionSkillFile = renderSwarmCraftActionSkillFile;
1419
+ var packet_workflow_1 = require_dist();
1420
+ function renderSwarmCraftActionSkillFile(actionKey) {
1421
+ const action = (0, packet_workflow_1.getSwarmCraftAssistantAction)(actionKey);
1422
+ if (action.kind === "stage") {
1423
+ return renderStageActionSkillFile(action);
1424
+ }
1425
+ if (action.kind === "planning") {
1426
+ return renderPlanActionSkillFile(action);
1427
+ }
1428
+ return renderTestActionSkillFile(action);
1429
+ }
1430
+ function renderStageActionSkillFile(action) {
1431
+ if (!action.stageKey) {
1432
+ throw new Error(`Stage action ${action.key} is missing a stage key.`);
1433
+ }
1434
+ const stage = (0, packet_workflow_1.getSwarmCraftStageContract)(action.stageKey);
1435
+ return [
1436
+ "---",
1437
+ `name: swarmcraft-${action.key}`,
1438
+ `description: ${JSON.stringify(`${action.description} Use when working a SwarmCraft ${stage.key}-lane packet through the ${action.key} action from .swarmcraft/projects/.`)}`,
1439
+ "---",
1440
+ "",
1441
+ `# SwarmCraft ${capitalize(action.key)}`,
1442
+ "",
1443
+ `Use this skill for the \`${action.key}\` action on a linked SwarmCraft packet in the \`${stage.key}\` lane.`,
1444
+ "",
1445
+ "## Required Context",
1446
+ "",
1447
+ ...(0, packet_workflow_1.renderBullets)([
1448
+ "`AGENTS.md` and the nearest scoped `AGENTS.md` files for touched code",
1449
+ "`.swarmcraft/AGENTS.md`",
1450
+ "`.swarmcraft/project.instructions.md`",
1451
+ "`.swarmcraft/project.context.md`",
1452
+ `the linked packet under \`.swarmcraft/projects/\``,
1453
+ `\`.swarmcraft/agents/${stage.key}.instructions.md\``
1454
+ ]),
1455
+ "",
1456
+ "## Packet Contract",
1457
+ "",
1458
+ ...(0, packet_workflow_1.renderBullets)([
1459
+ `Preserve the staged packet structure: ${packet_workflow_1.PACKET_SECTIONS.map((section) => `\`${section}\``).join(", ")}.`,
1460
+ "Treat checklist text and ordering as board-owned scope.",
1461
+ "Mark checklist items complete only when repository state and validation support them.",
1462
+ "Keep `## Notes` factual and stage-specific.",
1463
+ "Keep `## Agent Update` short and useful for the next agent or reviewer.",
1464
+ "Preserve packet identity and sync fields unless SwarmCraft tooling rewrites them."
1465
+ ]),
1466
+ "",
1467
+ "## Workflow",
1468
+ "",
1469
+ ...(0, packet_workflow_1.renderNumberedLines)(stage.agentWorkflow),
1470
+ "",
1471
+ "## Completion Rule",
1472
+ "",
1473
+ stage.completionRule,
1474
+ "",
1475
+ "## Output",
1476
+ "",
1477
+ ...(0, packet_workflow_1.renderBullets)(stage.outputItems),
1478
+ ""
1479
+ ].join("\n");
1480
+ }
1481
+ function renderPlanActionSkillFile(action) {
1482
+ return [
1483
+ "---",
1484
+ `name: swarmcraft-${action.key}`,
1485
+ `description: ${JSON.stringify("Use when the user asks to plan SwarmCraft work, create or revise a plan, check whether an existing plan is stale or coherent, turn repo context into one provisional ticket packet, or review scope for duplicate work, dependency drift, or mismatch with repository reality.")}`,
1486
+ "---",
1487
+ "",
1488
+ "# SwarmCraft Plan",
1489
+ "",
1490
+ "Use this skill to create a narrow plan, check whether an existing plan is still coherent, revise a stale plan when asked, or draft one provisional SwarmCraft ticket packet from repo context.",
1491
+ "",
1492
+ "## Required Context",
1493
+ "",
1494
+ ...(0, packet_workflow_1.renderBullets)([
1495
+ "`AGENTS.md` and the nearest scoped `AGENTS.md` files for touched code",
1496
+ "`.swarmcraft/AGENTS.md`",
1497
+ "`.swarmcraft/project.instructions.md`",
1498
+ "`.swarmcraft/project.context.md`",
1499
+ "nearby existing packets under `.swarmcraft/projects/`",
1500
+ "the existing plan or requested scope when the user provides one"
1501
+ ]),
1502
+ "",
1503
+ "Do not draft new scope until the project instructions, project context, and nearby packets have been checked or clearly do not exist.",
1504
+ "",
1505
+ "## Plan Review",
1506
+ "",
1507
+ ...(0, packet_workflow_1.renderNumberedLines)([
1508
+ "Compare the requested plan against current repository structure, project context, and nearby packets.",
1509
+ "Identify stale assumptions, incoherent scope, duplicate work, outdated dependencies, and mismatches with current files.",
1510
+ "State whether the plan is current, stale, incoherent, duplicated, blocked by missing context, or ready for packet drafting.",
1511
+ "Recommend the narrowest revision when a plan is stale instead of silently rewriting it.",
1512
+ "Do not modify an existing plan or board-linked packet unless the user explicitly asks for that revision.",
1513
+ "When asked to revise, keep the change limited to the stale or incoherent portion and preserve still-valid decisions."
1514
+ ]),
1515
+ "",
1516
+ "## New Packet Drafting",
1517
+ "",
1518
+ "When the user wants new SwarmCraft board work, create one focused provisional packet instead of a broad backlog dump.",
1519
+ "",
1520
+ "Use this frontmatter shape:",
1521
+ "",
1522
+ "```yaml",
1523
+ "swarmcraftVersion: 1",
1524
+ "projectId: <project-id>",
1525
+ "ticketId: provisional:<short-slug>",
1526
+ 'title: "<focused ticket title>"',
1527
+ "lane: todo",
1528
+ "syncRevision: 0",
1529
+ "lastSyncedAt: null",
1530
+ "provisional: true",
1531
+ "```",
1532
+ "",
1533
+ "If the project id is not available from an existing packet or SwarmCraft-provided context, ask for it or leave a plan draft instead of inventing one.",
1534
+ "",
1535
+ "A provisional packet must include:",
1536
+ "",
1537
+ ...(0, packet_workflow_1.renderBullets)([
1538
+ "`## Goal` with one clear outcome",
1539
+ "`## Doing Checklist` with implementation tasks",
1540
+ "`## Checking Checklist` with validation tasks",
1541
+ "`## Reviewing Checklist` with human approval prompts",
1542
+ "`## Notes` for planning facts and assumptions",
1543
+ "`## Agent Update` for a concise handoff"
1544
+ ]),
1545
+ "",
1546
+ "Checklist items in a provisional packet must start unchecked. Use manual Sync Packet in the SwarmCraft extension to promote a valid provisional packet into a board ticket.",
1547
+ "",
1548
+ "Before calling a provisional packet sync-ready, validate that:",
1549
+ "",
1550
+ ...(0, packet_workflow_1.renderBullets)([
1551
+ "`projectId` is present and comes from an existing packet or SwarmCraft-provided context",
1552
+ "`ticketId` starts with `provisional:`",
1553
+ "`lane` is `todo`",
1554
+ "`syncRevision` is `0`",
1555
+ "`lastSyncedAt` is `null`",
1556
+ "`provisional` is `true`",
1557
+ "all six required packet sections are present",
1558
+ "all checklist items are unchecked",
1559
+ "the packet describes one focused ticket, not a backlog"
1560
+ ]),
1561
+ "",
1562
+ "## Output",
1563
+ "",
1564
+ ...(0, packet_workflow_1.renderBullets)([
1565
+ "plan status: current, stale, incoherent, or ready for packet drafting",
1566
+ "stale assumptions or duplicate scope found",
1567
+ "files or packets consulted",
1568
+ "new provisional packet path when one was created",
1569
+ "remaining decision needed before sync"
1570
+ ]),
1571
+ ""
1572
+ ].join("\n");
1573
+ }
1574
+ function renderTestActionSkillFile(action) {
1575
+ return [
1576
+ "---",
1577
+ `name: swarmcraft-${action.key}`,
1578
+ `description: ${JSON.stringify("Use when the user asks to add, run, or document system testing, end-to-end testing, acceptance testing, API checks, coverage improvement, existing-packet test evidence, or a testing-focused provisional SwarmCraft packet.")}`,
1579
+ "---",
1580
+ "",
1581
+ "# SwarmCraft Test",
1582
+ "",
1583
+ "Use this skill to improve testing evidence without adding a new workflow lane or silently switching into implementation work.",
1584
+ "",
1585
+ "## Required Context",
1586
+ "",
1587
+ ...(0, packet_workflow_1.renderBullets)([
1588
+ "`AGENTS.md` and the nearest scoped `AGENTS.md` files for touched code",
1589
+ "`.swarmcraft/AGENTS.md`",
1590
+ "`.swarmcraft/project.instructions.md`",
1591
+ "`.swarmcraft/project.context.md`",
1592
+ "the linked packet when the test work belongs to existing ticket scope",
1593
+ "nearby tests, fixtures, API routes, UI flows, and acceptance criteria"
1594
+ ]),
1595
+ "",
1596
+ "## Existing Packet Mode",
1597
+ "",
1598
+ ...(0, packet_workflow_1.renderNumberedLines)([
1599
+ "Read the packet goal, checklists, notes, and agent update before changing tests.",
1600
+ "Add or run tests that exercise the user-facing or system boundary implied by the packet.",
1601
+ "Record commands run, flows exercised, evidence captured, pass or fail result, and remaining coverage gaps under `## Notes`.",
1602
+ "Use an existing subsection under `## Notes` when one fits; otherwise add a concise `### Test Evidence` subsection without adding a new top-level packet section.",
1603
+ "Update `## Agent Update` with a concise testing handoff.",
1604
+ "Do not change packet lanes as part of test work unless the user explicitly switches into `do`, `check`, or `review` work.",
1605
+ "Do not fix implementation defects in test mode; report the defect and ask before switching into implementation."
1606
+ ]),
1607
+ "",
1608
+ "## New Testing Scope",
1609
+ "",
1610
+ "When requested testing work is new scope, draft one testing-focused provisional packet with the same frontmatter shape as `swarmcraft-plan`: `ticketId: provisional:<slug>`, `lane: todo`, `syncRevision: 0`, `lastSyncedAt: null`, and `provisional: true`.",
1611
+ "",
1612
+ "The provisional packet must describe one testing outcome, include `## Goal`, `## Doing Checklist`, `## Checking Checklist`, `## Reviewing Checklist`, `## Notes`, and `## Agent Update`, and keep every checklist item unchecked until real evidence exists.",
1613
+ "",
1614
+ "Use the checklist sections this way:",
1615
+ "",
1616
+ ...(0, packet_workflow_1.renderBullets)(packet_workflow_1.CHECKLIST_STAGES.map((stage) => `\`${stage}\`: include testing work that can be verified for that stage without creating a new lane.`)),
1617
+ "",
1618
+ "## Validation Preference",
1619
+ "",
1620
+ ...(0, packet_workflow_1.renderBullets)([
1621
+ "Prefer full-system evidence for user-facing workflows.",
1622
+ "Use browser flows when web UI behavior matters.",
1623
+ "Use API or service checks when server behavior matters.",
1624
+ "Keep implementation fixes out of this skill unless the user explicitly asks to switch into implementation."
1625
+ ]),
1626
+ "",
1627
+ "## Output",
1628
+ "",
1629
+ ...(0, packet_workflow_1.renderBullets)([
1630
+ "tests added or commands run",
1631
+ "flows exercised and evidence captured",
1632
+ "pass or fail result",
1633
+ "coverage gaps that remain",
1634
+ "packet notes or provisional packet path updated"
1635
+ ]),
1636
+ ""
1637
+ ].join("\n");
1638
+ }
1639
+ function capitalize(value) {
1640
+ return `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
1641
+ }
1642
+ }
1643
+ });
1644
+
1645
+ // ../../packages/repo-seed/dist/templates/renderCodexSkills.js
1646
+ var require_renderCodexSkills = __commonJS({
1647
+ "../../packages/repo-seed/dist/templates/renderCodexSkills.js"(exports2) {
1648
+ "use strict";
1649
+ Object.defineProperty(exports2, "__esModule", { value: true });
1650
+ exports2.renderCodexSwarmCraftPlanSkillFile = renderCodexSwarmCraftPlanSkillFile;
1651
+ exports2.renderCodexSwarmCraftDoSkillFile = renderCodexSwarmCraftDoSkillFile;
1652
+ exports2.renderCodexSwarmCraftCheckSkillFile = renderCodexSwarmCraftCheckSkillFile;
1653
+ exports2.renderCodexSwarmCraftReviewSkillFile = renderCodexSwarmCraftReviewSkillFile;
1654
+ exports2.renderCodexSwarmCraftTestSkillFile = renderCodexSwarmCraftTestSkillFile;
1655
+ exports2.renderCodexPacketWorkflowSkillFile = renderCodexPacketWorkflowSkillFile;
1656
+ exports2.renderCodexPacketSyncTriageSkillFile = renderCodexPacketSyncTriageSkillFile;
1657
+ exports2.renderCodexRepoSeedAuditSkillFile = renderCodexRepoSeedAuditSkillFile;
1658
+ var packet_workflow_1 = require_dist();
1659
+ var renderAssistantActionSkills_1 = require_renderAssistantActionSkills();
1660
+ function renderCodexSwarmCraftPlanSkillFile() {
1661
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("plan");
1662
+ }
1663
+ function renderCodexSwarmCraftDoSkillFile() {
1664
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("do");
1665
+ }
1666
+ function renderCodexSwarmCraftCheckSkillFile() {
1667
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("check");
1668
+ }
1669
+ function renderCodexSwarmCraftReviewSkillFile() {
1670
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("review");
1671
+ }
1672
+ function renderCodexSwarmCraftTestSkillFile() {
1673
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("test");
1674
+ }
1675
+ function renderCodexPacketWorkflowSkillFile() {
1676
+ return [
1677
+ "---",
1678
+ "name: packet-workflow",
1679
+ "description: Legacy compatibility helper for repositories that still have the old broad SwarmCraft packet workflow skill. Prefer the action-specific swarmcraft-do, swarmcraft-check, swarmcraft-review, swarmcraft-plan, and swarmcraft-test skills for new work.",
1680
+ "---",
1681
+ "",
1682
+ "# Legacy Packet Workflow",
1683
+ "",
1684
+ "This skill is a compatibility bridge for older seeded repositories. New SwarmCraft seed output uses action-specific skills instead.",
1685
+ "",
1686
+ "Use the action-specific skills when available:",
1687
+ "",
1688
+ "- `swarmcraft-plan` for planning, stale-plan review, or provisional packet drafting",
1689
+ "- `swarmcraft-do` for doing-lane implementation",
1690
+ "- `swarmcraft-check` for checking-lane validation",
1691
+ "- `swarmcraft-review` for reviewing-lane human approval support",
1692
+ "- `swarmcraft-test` for system testing and testing-focused packet work",
1693
+ "",
1694
+ "If only this legacy skill exists, infer the intended action from the user's requested lane or stage, read the linked packet under `.swarmcraft/projects/`, and follow the matching lane guidance under `.swarmcraft/agents/`.",
1695
+ "",
1696
+ "## Guardrails",
1697
+ "",
1698
+ "- Do not expose this skill as the normal user-facing command in new seed output.",
1699
+ "- Preserve packet identity and sync fields unless SwarmCraft tooling rewrites them.",
1700
+ "- Keep `do`, `check`, and `review` lane behavior aligned with the action-specific skills.",
1701
+ "- Leave review-to-done movement to the SwarmCraft extension.",
1702
+ "",
1703
+ "## Output",
1704
+ "",
1705
+ "Report which action-specific workflow you followed and whether the repository should be reseeded to replace this compatibility helper.",
1706
+ ""
1707
+ ].join("\n");
1708
+ }
1709
+ function renderCodexPacketSyncTriageSkillFile() {
1710
+ return [
1711
+ "---",
1712
+ "name: packet-sync-triage",
1713
+ "description: Use when a SwarmCraft packet cannot sync cleanly, packet and board state disagree, or revision, lane, checklist, notes, or identity drift needs diagnosis.",
1714
+ "---",
1715
+ "",
1716
+ "# Packet Sync Triage",
1717
+ "",
1718
+ "Use this skill when packet-backed work cannot be synchronized confidently between the repository and SwarmCraft.",
1719
+ "",
1720
+ "## Triage Procedure",
1721
+ "",
1722
+ "1. Read `.swarmcraft/AGENTS.md`, the packet, and the lane-specific guidance.",
1723
+ "2. Confirm packet identity fields such as `projectId` and `ticketId` match the intended ticket.",
1724
+ "3. Compare packet `syncRevision` with the current board revision when available.",
1725
+ "4. Compare packet lane with board lane and allow only same-lane or adjacent-lane recovery.",
1726
+ "5. Confirm checklist text and order still match the expected packet contract.",
1727
+ "6. Decide whether the board, packet, or repository evidence is authoritative for the repair.",
1728
+ "7. Record the repair path in packet notes or `## Agent Update` when the packet remains valid.",
1729
+ "",
1730
+ "## Recovery Choices",
1731
+ "",
1732
+ "- refresh packet from board state",
1733
+ "- preserve packet text and manually reconcile before syncing",
1734
+ "- restore packet identity or linkage",
1735
+ "- stop lane transition and keep the ticket in its current lane",
1736
+ "",
1737
+ "## Output",
1738
+ "",
1739
+ "Report the mismatch category, evidence, chosen recovery path, and whether the packet is still safe to use.",
1740
+ ""
1741
+ ].join("\n");
1742
+ }
1743
+ function renderCodexRepoSeedAuditSkillFile() {
1744
+ return [
1745
+ "---",
1746
+ "name: repo-seed-audit",
1747
+ "description: Use when auditing whether SwarmCraft repository seed outputs are present, aligned, and internally consistent across shared, Copilot, and Codex guidance files.",
1748
+ "---",
1749
+ "",
1750
+ "# Repo Seed Audit",
1751
+ "",
1752
+ "Use this skill to check that a seeded SwarmCraft workspace has coherent guidance across shared, Copilot, and Codex surfaces.",
1753
+ "",
1754
+ "## Expected Seed Surface",
1755
+ "",
1756
+ "- `.swarmcraft/AGENTS.md`",
1757
+ "- `.swarmcraft/project.instructions.md`",
1758
+ "- `.swarmcraft/project.context.md`",
1759
+ "- `.swarmcraft/project.seed-summary.md`",
1760
+ "- `.swarmcraft/agents/doing.instructions.md`",
1761
+ "- `.swarmcraft/agents/checking.instructions.md`",
1762
+ "- `.swarmcraft/agents/reviewing.instructions.md`",
1763
+ "- `.github/instructions/swarmcraft/swarmcraft-packets.instructions.md`",
1764
+ "- `.github/agents/swarmcraft-implementor.agent.md`",
1765
+ "- `.github/agents/swarmcraft-checker.agent.md`",
1766
+ "- `.github/agents/swarmcraft-reviewer.agent.md`",
1767
+ ...packet_workflow_1.SWARMCRAFT_ASSISTANT_ACTIONS.flatMap((action) => [
1768
+ `- \`${action.copilotPromptPath}\``,
1769
+ `- \`${action.copilotSkillPath}\``,
1770
+ `- \`${action.codexSkillPath}\``
1771
+ ]),
1772
+ "- `.codex/agents/swarmcraft-implementor.toml`",
1773
+ "- `.codex/agents/swarmcraft-checker.toml`",
1774
+ "- `.codex/agents/swarmcraft-reviewer.toml`",
1775
+ "- `.codex/config.example.toml`",
1776
+ "",
1777
+ "## Audit Procedure",
1778
+ "",
1779
+ "1. Compare the declared seed surface with files present in the workspace.",
1780
+ "2. Check for missing files, stale references, contradictory guidance, and path drift.",
1781
+ "3. Confirm `plan`, `do`, `check`, `review`, and `test` are represented across Copilot prompts, Copilot skills, and Codex skills.",
1782
+ "4. Confirm provider-specific files point back to `.swarmcraft` packets as the source of truth.",
1783
+ "5. Recommend the smallest correction that restores alignment.",
1784
+ "",
1785
+ "## Output",
1786
+ "",
1787
+ "Report expected files, actual files, drift found, and the narrowest correction for each issue.",
1788
+ ""
1789
+ ].join("\n");
1790
+ }
1791
+ }
1792
+ });
1793
+
1794
+ // ../../packages/repo-seed/dist/templates/renderCopilotSkills.js
1795
+ var require_renderCopilotSkills = __commonJS({
1796
+ "../../packages/repo-seed/dist/templates/renderCopilotSkills.js"(exports2) {
1797
+ "use strict";
1798
+ Object.defineProperty(exports2, "__esModule", { value: true });
1799
+ exports2.renderSwarmCraftPlanSkillFile = renderSwarmCraftPlanSkillFile;
1800
+ exports2.renderSwarmCraftDoSkillFile = renderSwarmCraftDoSkillFile;
1801
+ exports2.renderSwarmCraftCheckSkillFile = renderSwarmCraftCheckSkillFile;
1802
+ exports2.renderSwarmCraftReviewSkillFile = renderSwarmCraftReviewSkillFile;
1803
+ exports2.renderSwarmCraftTestSkillFile = renderSwarmCraftTestSkillFile;
1804
+ exports2.renderPacketWorkflowSkillFile = renderPacketWorkflowSkillFile;
1805
+ exports2.renderPacketSyncTriageSkillFile = renderPacketSyncTriageSkillFile;
1806
+ exports2.renderRepoSeedAuditSkillFile = renderRepoSeedAuditSkillFile;
1807
+ var packet_workflow_1 = require_dist();
1808
+ var renderAssistantActionSkills_1 = require_renderAssistantActionSkills();
1809
+ function renderSwarmCraftPlanSkillFile() {
1810
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("plan");
1811
+ }
1812
+ function renderSwarmCraftDoSkillFile() {
1813
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("do");
1814
+ }
1815
+ function renderSwarmCraftCheckSkillFile() {
1816
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("check");
1817
+ }
1818
+ function renderSwarmCraftReviewSkillFile() {
1819
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("review");
1820
+ }
1821
+ function renderSwarmCraftTestSkillFile() {
1822
+ return (0, renderAssistantActionSkills_1.renderSwarmCraftActionSkillFile)("test");
1823
+ }
1824
+ function renderPacketWorkflowSkillFile() {
1825
+ const doing = (0, packet_workflow_1.getSwarmCraftStageContract)("doing");
1826
+ const checking = (0, packet_workflow_1.getSwarmCraftStageContract)("checking");
1827
+ const reviewing = (0, packet_workflow_1.getSwarmCraftStageContract)("reviewing");
1828
+ return [
1829
+ "---",
1830
+ "name: packet-workflow",
1831
+ "description: Use when working a SwarmCraft ticket through its repo packet, reconciling packet and repo state, or preparing packet-backed work for sync and review. This skill explains how to use the packet as the execution contract without replacing the packet editing rules enforced by the instruction files.",
1832
+ 'argument-hint: "[packet=.swarmcraft/projects/.../ticket.md] [mode=implement|sync|review]"',
1833
+ "---",
1834
+ "",
1835
+ "## Packet Workflow",
1836
+ "",
1837
+ "Use this skill when a SwarmCraft task is driven by a packet file under `.swarmcraft/projects/`.",
1838
+ "",
1839
+ "Do not use this skill to override repository rules. Packet editing rules remain defined by `.github/instructions/swarmcraft/swarmcraft-packets.instructions.md`. Treat this skill as the execution playbook that sits on top of those rules.",
1840
+ "",
1841
+ "## When To Use This Skill",
1842
+ "",
1843
+ "Use this skill when you need to:",
1844
+ "",
1845
+ "* implement a doing-lane ticket from its packet",
1846
+ "* validate or complete checking-lane work from the packet contract",
1847
+ "* prepare a reviewing-lane handoff from packet state and repo evidence",
1848
+ "* reconcile packet, repo, and board state when they drift",
1849
+ "* decide what validation is still required before the ticket can move forward",
1850
+ "",
1851
+ "Do not use this skill when the task is a general repository change with no packet, or when you only need the packet editing guardrails and no workflow guidance.",
1852
+ "",
1853
+ "## Required Inputs",
1854
+ "",
1855
+ "Gather these inputs before making substantive changes:",
1856
+ "",
1857
+ "* the packet file path when one already exists",
1858
+ "* the current lane, if known",
1859
+ "* the code or files implicated by the packet goal and checklist",
1860
+ "",
1861
+ "When they exist, read these guidance files before making substantive changes:",
1862
+ "",
1863
+ "* `.swarmcraft/AGENTS.md`",
1864
+ "* `.swarmcraft/project.instructions.md`",
1865
+ "* `.swarmcraft/project.context.md`",
1866
+ "* the lane-specific guidance under `.swarmcraft/agents/`",
1867
+ "",
1868
+ "## Workflow",
1869
+ "",
1870
+ "### Step 1: Establish the packet contract",
1871
+ "",
1872
+ "1. Read the packet frontmatter and confirm the packet is the intended work item.",
1873
+ "2. Read `## Goal`, all checklist sections, `## Notes`, and `## Agent Update` before planning edits.",
1874
+ "3. Treat incomplete checklist items as the currently declared scope unless the packet itself is clearly stale.",
1875
+ "4. If the packet and repository already disagree, surface the mismatch explicitly and reconcile it instead of silently working around it.",
1876
+ "",
1877
+ "### Step 2: Convert the packet into a narrow execution slice",
1878
+ "",
1879
+ "1. Identify the smallest code path that can satisfy the packet goal or the next unchecked checklist item.",
1880
+ "2. Prefer the owning implementation surface over broad repo exploration.",
1881
+ "3. Form one falsifiable local hypothesis about the change you need to make.",
1882
+ "4. Choose the cheapest focused validation that could disconfirm that hypothesis.",
1883
+ "",
1884
+ "### Step 3: Implement against the packet",
1885
+ "",
1886
+ "1. Make the smallest change that advances the packet goal.",
1887
+ "2. Keep packet-backed scope tight. Avoid opportunistic refactors unless the packet or failing validation forces them.",
1888
+ "3. After the first substantive edit, run the focused validation before widening scope.",
1889
+ "4. If validation fails, repair the same slice first instead of opening a second change area.",
1890
+ "",
1891
+ "### Step 4: Keep the packet current",
1892
+ "",
1893
+ "Update the packet as work progresses:",
1894
+ "",
1895
+ "* mark checklist items complete only when the repository state actually supports them",
1896
+ "* mark every completed checklist item for the current lane once the repo state and validation support it",
1897
+ "* record material implementation facts in `### Implementation Notes` under `## Notes`",
1898
+ "* keep `## Agent Update` short and structured around what changed, what was validated, and what remains blocked or risky",
1899
+ "",
1900
+ "Use these standard note headings under `## Notes` when they apply:",
1901
+ "",
1902
+ ...(0, packet_workflow_1.renderBullets)(packet_workflow_1.SWARMCRAFT_STAGE_CONTRACTS.map((stage) => `${stage.noteHeading} for ${stage.commandDescription}, evidence, decisions, and remaining work`)),
1903
+ "",
1904
+ "Do not leave important execution knowledge only in chat.",
1905
+ "",
1906
+ "### Step 5: Reconcile sync-sensitive state",
1907
+ "",
1908
+ "When packet synchronization or ticket movement is part of the task:",
1909
+ "",
1910
+ "1. Preserve packet identity and sync metadata unless SwarmCraft tooling is the thing rewriting it.",
1911
+ "2. Watch for packet-to-board mismatch signals such as stale revision, wrong lane, or wrong ticket identity.",
1912
+ "3. If the packet appears stale, refresh or reconcile before applying more repo edits.",
1913
+ "4. Do not hide drift by editing around it. State clearly whether the packet, the repo, or the board needs correction.",
1914
+ "",
1915
+ "### Step 6: Close the current lane cleanly",
1916
+ "",
1917
+ 'Use the lane to decide what "done for now" means:',
1918
+ "",
1919
+ ...(0, packet_workflow_1.renderBullets)(packet_workflow_1.SWARMCRAFT_STAGE_CONTRACTS.map((stage) => stage.stageSummary)),
1920
+ "",
1921
+ "Move work forward only when packet state, repository state, and validation evidence agree. When all checklist items for the current lane are complete and no unresolved blocker, question, or validation gap remains, set the packet frontmatter `lane` to the next adjacent workflow lane instead of asking whether to do it. The only exception is reviewing-to-done: Reviewing checklist items require explicit human approval, and the final Move to Done action belongs to the SwarmCraft extension.",
1922
+ "",
1923
+ "## Doing Completion Loop",
1924
+ "",
1925
+ "When doing work is incomplete or unproven:",
1926
+ "",
1927
+ "1. Leave incomplete or unproven Doing checklist items unchecked.",
1928
+ `2. Record the blocker, missing evidence, or remaining work in \`${doing.noteHeading}\` under \`## Notes\`.`,
1929
+ "3. Update `## Agent Update` with the current state and keep packet frontmatter `lane: doing`.",
1930
+ "",
1931
+ "When doing work is complete:",
1932
+ "",
1933
+ "1. Mark every completed Doing checklist item complete once the repo state and validation support it.",
1934
+ `2. Record implementation facts and validation evidence in \`${doing.noteHeading}\` under \`## Notes\`.`,
1935
+ "3. Update `## Agent Update` with a concise implementation summary for the checking agent.",
1936
+ `4. ${doing.completionRule}`,
1937
+ "",
1938
+ "## Checking Judge Loop",
1939
+ "",
1940
+ "Checking is a machine-in-the-loop judgment lane. The checking agent should decide whether the implementation is accepted for human review or rejected back to doing.",
1941
+ "",
1942
+ "When checking rejects the implementation:",
1943
+ "",
1944
+ "1. Leave failed or unproven checking checklist items unchecked.",
1945
+ `2. Add or update \`${checking.noteHeading}\` under \`## Notes\` with the failed checklist item, evidence, validation result, and required fix.`,
1946
+ "3. Update `## Agent Update` with a concise rejection summary.",
1947
+ "4. Set the packet frontmatter `lane` to `doing` so packet sync moves the ticket back for implementation.",
1948
+ "",
1949
+ "When checking accepts the implementation:",
1950
+ "",
1951
+ "1. Mark only proven checking checklist items complete.",
1952
+ "2. Record the validation evidence in `## Notes` and summarize acceptance in `## Agent Update`.",
1953
+ `3. ${checking.completionRule}`,
1954
+ "",
1955
+ "Do not repair implementation defects during checking unless the user explicitly asks. The default checking job is judgment and feedback, not implementation.",
1956
+ "",
1957
+ "## Reviewing Approval Loop",
1958
+ "",
1959
+ "Reviewing is a human approval lane. The reviewing agent should prompt the user for approval decisions, record those decisions in the packet, and leave the final done transition to the SwarmCraft extension.",
1960
+ "",
1961
+ "Do not treat Reviewing like Checking. Existing repository evidence and validation results are inputs for the user's decision, not substitutes for explicit human approval.",
1962
+ "",
1963
+ "When review is incomplete or uncertain:",
1964
+ "",
1965
+ "1. Leave unapproved or uncertain Reviewing checklist items unchecked.",
1966
+ `2. Record the reason under \`${reviewing.noteHeading}\` in \`## Notes\`.`,
1967
+ "3. Update `## Agent Update` with the remaining approval, risk, or open question and keep packet frontmatter `lane: reviewing`.",
1968
+ "",
1969
+ "When review is fully approved:",
1970
+ "",
1971
+ "1. Mark a Reviewing checklist item complete only after the user explicitly confirms that item is approved.",
1972
+ `2. Record approvals and any relevant review evidence the user considered under \`${reviewing.noteHeading}\` in \`## Notes\`.`,
1973
+ "3. Update `## Agent Update` with a concise review-ready summary.",
1974
+ `4. ${reviewing.completionRule}`,
1975
+ "",
1976
+ "## Output Expectations",
1977
+ "",
1978
+ "When you use this skill, produce outcomes that leave the repo and packet aligned:",
1979
+ "",
1980
+ "* code changes are scoped to the packet",
1981
+ "* validation is concrete and recorded",
1982
+ "* checklist state reflects reality",
1983
+ "* notes and agent update capture the important facts another reviewer would need",
1984
+ "* completed lane checklist items and lane movement are reflected in the packet whenever evidence supports them",
1985
+ "",
1986
+ "## Example Invocations",
1987
+ "",
1988
+ "* `/packet-workflow packet=.swarmcraft/projects/acme/2-auth.md mode=implement`",
1989
+ "* `/packet-workflow packet=.swarmcraft/projects/acme/2-auth.md mode=sync`",
1990
+ "* `/packet-workflow packet=.swarmcraft/projects/acme/2-auth.md mode=review`",
1991
+ ""
1992
+ ].join("\n");
1993
+ }
1994
+ function renderPacketSyncTriageSkillFile() {
1995
+ return [
1996
+ "---",
1997
+ "name: packet-sync-triage",
1998
+ "description: Use when a SwarmCraft packet cannot sync cleanly, the packet and board appear to disagree, or you need a disciplined recovery path for revision, lane, checklist, or packet identity mismatches.",
1999
+ 'argument-hint: "[packet=.swarmcraft/projects/.../ticket.md] [issue=revision|lane|identity|checklist|notes]"',
2000
+ "---",
2001
+ "",
2002
+ "## Packet Sync Triage",
2003
+ "",
2004
+ "Use this skill when packet-backed work cannot be synchronized confidently between the repository and SwarmCraft.",
2005
+ "",
2006
+ "This skill is for diagnosis and recovery procedure inside the target repository. It does not assume access to the SwarmCraft extension source unless that source also exists in the current workspace, and it does not replace the packet editing rules in `.github/instructions/swarmcraft/swarmcraft-packets.instructions.md`.",
2007
+ "",
2008
+ "## When To Use This Skill",
2009
+ "",
2010
+ "Use this skill when you need to:",
2011
+ "",
2012
+ "* diagnose a failed packet sync",
2013
+ "* determine whether the packet file is stale",
2014
+ "* reconcile packet identity mismatches",
2015
+ "* explain an unsupported lane transition",
2016
+ "* verify whether checklist shape or notes content can sync safely",
2017
+ "* decide whether the packet, board, or repository should be treated as the source needing repair",
2018
+ "",
2019
+ "Do not use this skill for ordinary ticket implementation when no sync problem exists.",
2020
+ "",
2021
+ "## Required Inputs",
2022
+ "",
2023
+ "Gather as many of these as possible before changing anything:",
2024
+ "",
2025
+ "* the packet file path",
2026
+ "* the current packet contents",
2027
+ "* the current board ticket state, including lane and revision",
2028
+ "* the current repository state implicated by the packet",
2029
+ "* the last observed sync or move error, if available",
2030
+ "",
2031
+ "Read these files when they exist:",
2032
+ "",
2033
+ "* `.swarmcraft/AGENTS.md`",
2034
+ "* `.swarmcraft/project.instructions.md`",
2035
+ "* `.swarmcraft/project.context.md`",
2036
+ "* `.swarmcraft/agents/<lane>.instructions.md`",
2037
+ "",
2038
+ "## Triage Procedure",
2039
+ "",
2040
+ "### Step 1: Confirm packet identity first",
2041
+ "",
2042
+ "1. Read the packet frontmatter.",
2043
+ "2. Confirm `projectId` and `ticketId` match the intended ticket.",
2044
+ "3. If identity does not match, stop treating the file as the packet for the current ticket.",
2045
+ "4. State explicitly whether the wrong file was opened, the link is stale, or the packet link metadata needs repair.",
2046
+ "",
2047
+ "### Step 2: Check sync revision before anything else",
2048
+ "",
2049
+ "1. Compare the packet `syncRevision` with the current board ticket revision.",
2050
+ "2. If the packet revision is stale, do not continue making new packet-driven mutations as though the packet were current.",
2051
+ "3. Identify whether the packet needs to be refreshed from the board, or whether unsynced local edits must be reconciled first.",
2052
+ "",
2053
+ "### Step 3: Validate lane movement",
2054
+ "",
2055
+ "1. Compare the packet lane to the board lane.",
2056
+ "2. Treat same-lane sync as safe from a lane perspective.",
2057
+ "3. Treat adjacent-lane moves as the outer limit of supported automatic movement.",
2058
+ "4. If the requested move skips lanes or otherwise violates supported workflow movement, report that as the reason instead of forcing the transition.",
2059
+ "",
2060
+ "### Step 4: Validate checklist shape and notes intent",
2061
+ "",
2062
+ "1. Confirm the checklist stages still match the expected packet contract.",
2063
+ "2. Treat checklist text and order as board-owned structure unless SwarmCraft explicitly regenerated the packet.",
2064
+ "3. For notes and agent update, distinguish between factual execution updates and accidental drift.",
2065
+ "4. If the packet has been reshaped in a way that no longer maps cleanly to board checklist items, treat that as a contract issue, not as a syncable edit.",
2066
+ "",
2067
+ "### Step 5: Decide the direction of repair",
2068
+ "",
2069
+ "Use these recovery choices:",
2070
+ "",
2071
+ "* board is authoritative for identity, revision, and current linkage",
2072
+ "* packet is authoritative for in-progress execution notes only when it still matches the current ticket and revision contract",
2073
+ "* repository evidence is authoritative for whether checklist items are actually satisfied",
2074
+ "",
2075
+ "At the end of triage, name the repair path clearly:",
2076
+ "",
2077
+ "* refresh packet from board state",
2078
+ "* preserve packet text and manually reconcile before syncing",
2079
+ "* restore packet identity or linkage",
2080
+ "* stop lane transition and keep the ticket in its current lane",
2081
+ "",
2082
+ "### Step 6: Leave a clear audit trail",
2083
+ "",
2084
+ "When triage results in action:",
2085
+ "",
2086
+ "* explain what was wrong",
2087
+ "* explain what was treated as authoritative",
2088
+ "* explain what was changed or intentionally not changed",
2089
+ "* update packet notes or agent update when the packet remains valid and the triage result is part of the ticket history",
2090
+ "",
2091
+ "## Output Expectations",
2092
+ "",
2093
+ "When you use this skill, produce a short structured outcome covering:",
2094
+ "",
2095
+ "* the mismatch category",
2096
+ "* the evidence used to diagnose it",
2097
+ "* the chosen recovery path",
2098
+ "* whether the packet is still safe to use as the active execution contract",
2099
+ "",
2100
+ "## Example Invocations",
2101
+ "",
2102
+ "* `/packet-sync-triage packet=.swarmcraft/projects/acme/2-auth.md issue=revision`",
2103
+ "* `/packet-sync-triage packet=.swarmcraft/projects/acme/2-auth.md issue=lane`",
2104
+ "* `/packet-sync-triage packet=.swarmcraft/projects/acme/2-auth.md issue=identity`",
2105
+ ""
2106
+ ].join("\n");
2107
+ }
2108
+ function renderRepoSeedAuditSkillFile() {
2109
+ return [
2110
+ "---",
2111
+ "name: repo-seed-audit",
2112
+ "description: Use when auditing whether SwarmCraft repository seed outputs are present, aligned, and internally consistent across the local workspace files that SwarmCraft seeded into the target repository.",
2113
+ 'argument-hint: "[project=...] [scope=workspace|guidance|full]"',
2114
+ "---",
2115
+ "",
2116
+ "## Repo Seed Audit",
2117
+ "",
2118
+ "Use this skill when you need to verify that SwarmCraft project seeding is coherent across the repository.",
2119
+ "",
2120
+ "This skill is for consistency auditing inside the target repository after SwarmCraft files have been seeded. It does not assume access to the SwarmCraft product repository, extension source, or API source unless those files also exist in the current workspace.",
2121
+ "",
2122
+ "## When To Use This Skill",
2123
+ "",
2124
+ "Use this skill when you need to:",
2125
+ "",
2126
+ "* check whether a workspace has all expected SwarmCraft seed files",
2127
+ "* detect drift between seeded paths, descriptions, and rendered guidance",
2128
+ "* validate that a new seed artifact has been wired through all required surfaces",
2129
+ "* review whether root guidance, `.swarmcraft/` files, and `.github/` customizations still agree",
2130
+ "",
2131
+ "Do not use this skill for a normal packet editing task.",
2132
+ "",
2133
+ "## Required Inputs",
2134
+ "",
2135
+ "Gather these inputs when available:",
2136
+ "",
2137
+ "* the target project or workspace folder",
2138
+ "* the expected seeded file set",
2139
+ "* any local documentation that explains which SwarmCraft files should exist",
2140
+ "* the actual `.swarmcraft/` and `.github/` files present in the current workspace",
2141
+ "",
2142
+ "When they exist, use these repository anchors when auditing:",
2143
+ "",
2144
+ "* `.swarmcraft/AGENTS.md`",
2145
+ "* `.swarmcraft/project.instructions.md`",
2146
+ "* `.swarmcraft/project.context.md`",
2147
+ "* `.swarmcraft/project.seed-summary.md`",
2148
+ "* `.github/instructions/swarmcraft/swarmcraft-packets.instructions.md`",
2149
+ "* `.github/agents/`",
2150
+ "* `.github/skills/`",
2151
+ "",
2152
+ "Expected seeded guidance commonly includes:",
2153
+ "",
2154
+ "* `.swarmcraft/AGENTS.md`",
2155
+ "* `.swarmcraft/project.instructions.md`",
2156
+ "* `.swarmcraft/project.context.md`",
2157
+ "* `.swarmcraft/project.seed-summary.md`",
2158
+ "* `.swarmcraft/agents/doing.instructions.md`",
2159
+ "* `.swarmcraft/agents/checking.instructions.md`",
2160
+ "* `.swarmcraft/agents/reviewing.instructions.md`",
2161
+ "* `.github/instructions/swarmcraft/swarmcraft-packets.instructions.md`",
2162
+ "* `.github/agents/swarmcraft-implementor.agent.md`",
2163
+ "* `.github/agents/swarmcraft-checker.agent.md`",
2164
+ "* `.github/agents/swarmcraft-reviewer.agent.md`",
2165
+ ...packet_workflow_1.SWARMCRAFT_ASSISTANT_ACTIONS.flatMap((action) => [
2166
+ `* \`${action.copilotPromptPath}\``,
2167
+ `* \`${action.copilotSkillPath}\``,
2168
+ `* \`${action.codexSkillPath}\``
2169
+ ]),
2170
+ "* `.codex/agents/swarmcraft-implementor.toml`",
2171
+ "* `.codex/agents/swarmcraft-checker.toml`",
2172
+ "* `.codex/agents/swarmcraft-reviewer.toml`",
2173
+ "* `.codex/config.example.toml`",
2174
+ "",
2175
+ "## Audit Procedure",
2176
+ "",
2177
+ "### Step 1: Establish the expected seed surface",
2178
+ "",
2179
+ "1. Read the local SwarmCraft guidance files first.",
2180
+ "2. Record the canonical relative paths the seeded workspace appears to expect.",
2181
+ "3. Record any root-file pointer behavior such as guidance written into `AGENTS.md`.",
2182
+ "",
2183
+ "### Step 2: Compare local declarations and local reality",
2184
+ "",
2185
+ "1. Compare what the local guidance implies should exist with what actually exists in the workspace.",
2186
+ "2. Look for path drift, missing files, stale references, or contradictory descriptions.",
2187
+ '3. Treat a path mismatch as a real integration defect even if the workspace still "mostly works."',
2188
+ "",
2189
+ "### Step 3: Check rendered content ownership",
2190
+ "",
2191
+ "1. Identify which files look machine-seeded versus manually maintained.",
2192
+ "2. Confirm the guidance still matches the repository's current SwarmCraft workflow.",
2193
+ "3. Check whether any referenced file moved or was deleted without the surrounding guidance being updated.",
2194
+ "",
2195
+ "### Step 4: Verify repository reality",
2196
+ "",
2197
+ "1. Inspect whether the expected seeded files actually exist in the target workspace when the audit is against a real seeded project.",
2198
+ "2. Confirm that root guidance points to the deeper SwarmCraft files rather than contradicting them.",
2199
+ "3. Confirm that `.github` customizations live in the discovery paths expected by VS Code.",
2200
+ "",
2201
+ "### Step 5: Report drift precisely",
2202
+ "",
2203
+ "Classify findings clearly:",
2204
+ "",
2205
+ "* missing expected seed file",
2206
+ "* stale reference in local guidance",
2207
+ "* contradictory guidance between local files",
2208
+ "* path mismatch between local references and local files",
2209
+ "* stale managed content or seeded output",
2210
+ "* file exists in the repo but is no longer referenced by the local SwarmCraft guidance",
2211
+ "",
2212
+ "### Step 6: Recommend the narrowest correction",
2213
+ "",
2214
+ "For each finding, state the smallest correction that restores alignment:",
2215
+ "",
2216
+ "* add the missing file",
2217
+ "* update the local guidance to reference the right path",
2218
+ "* remove stale references that no longer match actual seeded outputs",
2219
+ "* regenerate or manually repair seeded guidance when it drifted",
2220
+ "",
2221
+ "## Output Expectations",
2222
+ "",
2223
+ "When you use this skill, produce a concise audit result covering:",
2224
+ "",
2225
+ "* the expected seed surface",
2226
+ "* the actual declared seed surface",
2227
+ "* any drift found",
2228
+ "* the narrowest corrective action for each mismatch",
2229
+ "",
2230
+ "## Example Invocations",
2231
+ "",
2232
+ "* `/repo-seed-audit scope=full`",
2233
+ "* `/repo-seed-audit project=acme scope=workspace`",
2234
+ "* `/repo-seed-audit scope=guidance`",
2235
+ ""
2236
+ ].join("\n");
2237
+ }
2238
+ }
2239
+ });
2240
+
2241
+ // ../../packages/repo-seed/dist/templates/renderCopilotPrompts.js
2242
+ var require_renderCopilotPrompts = __commonJS({
2243
+ "../../packages/repo-seed/dist/templates/renderCopilotPrompts.js"(exports2) {
2244
+ "use strict";
2245
+ Object.defineProperty(exports2, "__esModule", { value: true });
2246
+ exports2.renderPlanPromptFile = renderPlanPromptFile;
2247
+ exports2.renderDoPromptFile = renderDoPromptFile;
2248
+ exports2.renderCheckPromptFile = renderCheckPromptFile;
2249
+ exports2.renderReviewPromptFile = renderReviewPromptFile;
2250
+ exports2.renderTestPromptFile = renderTestPromptFile;
2251
+ var packet_workflow_1 = require_dist();
2252
+ function renderPlanPromptFile() {
2253
+ const action = (0, packet_workflow_1.getSwarmCraftAssistantAction)("plan");
2254
+ return renderLaneIndependentPromptFile(action, {
2255
+ title: "Plan Work",
2256
+ description: "Creates or checks a SwarmCraft plan and can draft a provisional todo packet for sync",
2257
+ inputName: "scope",
2258
+ inputDescription: "Planning request, existing plan path, or new ticket scope.",
2259
+ requirements: [
2260
+ "Follow the workflow in [SwarmCraft Plan](../skills/swarmcraft-plan/SKILL.md).",
2261
+ "Read SwarmCraft project context and nearby packets before drafting new scope.",
2262
+ "Report stale assumptions, incoherent scope, duplicate work, and dependency drift when checking an existing plan.",
2263
+ "Create only one focused provisional packet when new board work is requested.",
2264
+ "Do not modify existing board-linked packets or plans unless explicitly asked."
2265
+ ]
2266
+ });
2267
+ }
2268
+ function renderDoPromptFile() {
2269
+ return renderStagePromptFile("doing");
2270
+ }
2271
+ function renderCheckPromptFile() {
2272
+ return renderStagePromptFile("checking");
2273
+ }
2274
+ function renderReviewPromptFile() {
2275
+ return renderStagePromptFile("reviewing");
2276
+ }
2277
+ function renderTestPromptFile() {
2278
+ const action = (0, packet_workflow_1.getSwarmCraftAssistantAction)("test");
2279
+ return renderLaneIndependentPromptFile(action, {
2280
+ title: "Test Work",
2281
+ description: "Adds, runs, or documents system testing coverage for SwarmCraft packet work",
2282
+ inputName: "scope",
2283
+ inputDescription: "Existing packet path, testing request, or coverage gap.",
2284
+ requirements: [
2285
+ "Follow the workflow in [SwarmCraft Test](../skills/swarmcraft-test/SKILL.md).",
2286
+ "Prefer full-system evidence for user-facing workflows.",
2287
+ "Record commands run, flows exercised, evidence captured, pass or fail result, and coverage gaps.",
2288
+ "When working an existing packet, record test evidence under `## Notes` without adding a new lane.",
2289
+ "Keep implementation fixes out of test work unless explicitly asked."
2290
+ ]
2291
+ });
2292
+ }
2293
+ function renderStagePromptFile(stageKey) {
2294
+ const stage = (0, packet_workflow_1.getSwarmCraftStageContract)(stageKey);
2295
+ const action = (0, packet_workflow_1.getSwarmCraftAssistantAction)(stage.command.slice(1));
2296
+ const skillName = `SwarmCraft ${capitalize(action.key)}`;
2297
+ const skillRelativePath = `../skills/swarmcraft-${action.key}/SKILL.md`;
2298
+ const requirements = [
2299
+ `Follow the workflow in [${skillName}](${skillRelativePath}).`,
2300
+ ...stage.promptRequirements
2301
+ ];
2302
+ return [
2303
+ "---",
2304
+ `description: '${stage.promptDescription}'`,
2305
+ "argument-hint: 'ticket=.swarmcraft/projects/.../<ticket>.md'",
2306
+ "---",
2307
+ "",
2308
+ `#file:${action.copilotSkillPath}`,
2309
+ "",
2310
+ `# ${stage.promptTitle}`,
2311
+ "",
2312
+ "## Inputs",
2313
+ "",
2314
+ "* ${input:ticket}: (Required) Path to the linked SwarmCraft packet file.",
2315
+ "",
2316
+ "## Requirements",
2317
+ "",
2318
+ ...(0, packet_workflow_1.renderNumberedLines)(requirements),
2319
+ "",
2320
+ "Proceed with the user's request using `${input:ticket}` as the ticket packet.",
2321
+ ""
2322
+ ].join("\n");
2323
+ }
2324
+ function renderLaneIndependentPromptFile(action, input2) {
2325
+ return [
2326
+ "---",
2327
+ `description: '${input2.description}'`,
2328
+ `argument-hint: '${input2.inputName}=<request-or-path>'`,
2329
+ "---",
2330
+ "",
2331
+ `#file:${action.copilotSkillPath}`,
2332
+ "",
2333
+ `# ${input2.title}`,
2334
+ "",
2335
+ "## Inputs",
2336
+ "",
2337
+ `* \${input:${input2.inputName}}: ${input2.inputDescription}`,
2338
+ "",
2339
+ "## Requirements",
2340
+ "",
2341
+ ...(0, packet_workflow_1.renderNumberedLines)(input2.requirements),
2342
+ "",
2343
+ `Proceed with the user's request using \`\${input:${input2.inputName}}\` as the action scope.`,
2344
+ ""
2345
+ ].join("\n");
2346
+ }
2347
+ function capitalize(value) {
2348
+ return `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
2349
+ }
2350
+ }
2351
+ });
2352
+
2353
+ // ../../packages/repo-seed/dist/templates/renderProjectContext.js
2354
+ var require_renderProjectContext = __commonJS({
2355
+ "../../packages/repo-seed/dist/templates/renderProjectContext.js"(exports2) {
2356
+ "use strict";
2357
+ Object.defineProperty(exports2, "__esModule", { value: true });
2358
+ exports2.renderProjectInstructionsFile = renderProjectInstructionsFile;
2359
+ exports2.renderProjectContextFile = renderProjectContextFile;
2360
+ function renderProjectInstructionsFile(project) {
2361
+ const projectTitle = project.title?.trim() || project.id;
2362
+ const projectSummary = project.summary?.trim() || "Add the product and delivery context for this project here.";
2363
+ const primaryTargetProduct = project.primaryTargetProduct?.trim() || "Add the primary target product or surface here.";
2364
+ return [
2365
+ "# Project Instructions",
2366
+ "",
2367
+ "SwarmCraft seeds this file once and preserves later human edits.",
2368
+ "",
2369
+ "## Project",
2370
+ "",
2371
+ `- Title: ${projectTitle}`,
2372
+ `- Summary: ${projectSummary}`,
2373
+ `- Primary target product: ${primaryTargetProduct}`,
2374
+ "",
2375
+ "## Project-Specific Guidance",
2376
+ "",
2377
+ "Add architecture boundaries, style expectations, rollout constraints, and protected areas here.",
2378
+ "",
2379
+ "## Review Notes",
2380
+ "",
2381
+ "Document anything that agents should not change without explicit review.",
2382
+ ""
2383
+ ].join("\n");
2384
+ }
2385
+ function renderProjectContextFile(project) {
2386
+ const repoSeedContext = project.repoSeed?.projectContext;
2387
+ const actors = formatSummaryList(repoSeedContext?.actors, "Add the primary workflow actors here.");
2388
+ const ecosystemDependencies = formatSummaryList(repoSeedContext?.ecosystemDependencies, "Add the ecosystem dependencies here.");
2389
+ const constraints = formatSummaryList(repoSeedContext?.constraints, "Add the project constraints here.");
2390
+ const brandDirection = repoSeedContext?.brandDirection?.trim() || "Add the brand direction here.";
2391
+ const targetPlatform = repoSeedContext?.targetPlatform?.trim() || "Add the target platform here.";
2392
+ const deploymentEnvironment = repoSeedContext?.deploymentEnvironment?.trim() || "Add the deployment environment here.";
2393
+ const technologyPreference = renderTechnologyPreference(repoSeedContext?.technologyPreference, repoSeedContext?.preferredTechnologies ?? []);
2394
+ return [
2395
+ "# Project Context",
2396
+ "",
2397
+ "This file captures the richer project context that the engine-owned repo seed supplied during repository seeding.",
2398
+ "",
2399
+ "## Operating Context",
2400
+ "",
2401
+ `- Actors: ${actors}`,
2402
+ `- Ecosystem dependencies: ${ecosystemDependencies}`,
2403
+ `- Constraints: ${constraints}`,
2404
+ `- Brand direction: ${brandDirection}`,
2405
+ `- Target platform: ${targetPlatform}`,
2406
+ `- Deployment environment: ${deploymentEnvironment}`,
2407
+ `- Technology preference: ${technologyPreference}`,
2408
+ ""
2409
+ ].join("\n");
2410
+ }
2411
+ function formatSummaryList(values, fallback) {
2412
+ if (!values || values.length === 0) {
2413
+ return fallback;
2414
+ }
2415
+ return values.join(", ");
2416
+ }
2417
+ function renderTechnologyPreference(technologyPreference, preferredTechnologies) {
2418
+ if (technologyPreference === "PREFERRED") {
2419
+ return preferredTechnologies.length > 0 ? `Preferred (${preferredTechnologies.join(", ")})` : "Preferred";
2420
+ }
2421
+ if (technologyPreference === "DONT_CARE") {
2422
+ return "Don't care";
2423
+ }
2424
+ return "Unspecified";
2425
+ }
2426
+ }
2427
+ });
2428
+
2429
+ // ../../packages/repo-seed/dist/templates/renderProjectGuide.js
2430
+ var require_renderProjectGuide = __commonJS({
2431
+ "../../packages/repo-seed/dist/templates/renderProjectGuide.js"(exports2) {
2432
+ "use strict";
2433
+ Object.defineProperty(exports2, "__esModule", { value: true });
2434
+ exports2.MANAGED_SECTION_START = exports2.MANAGED_SECTION_END = void 0;
2435
+ exports2.renderSwarmCraftAgentsFile = renderSwarmCraftAgentsFile;
2436
+ exports2.renderProjectSeedSummaryFile = renderProjectSeedSummaryFile;
2437
+ exports2.renderRootAgentsManagedSection = renderRootAgentsManagedSection;
2438
+ var packet_workflow_1 = require_dist();
2439
+ var MANAGED_SECTION_START = "<!-- BEGIN SWARMCRAFT MANAGED SECTION -->";
2440
+ exports2.MANAGED_SECTION_START = MANAGED_SECTION_START;
2441
+ var MANAGED_SECTION_END = "<!-- END SWARMCRAFT MANAGED SECTION -->";
2442
+ exports2.MANAGED_SECTION_END = MANAGED_SECTION_END;
2443
+ function renderSwarmCraftAgentsFile(project) {
2444
+ const projectTitle = project.title?.trim() || project.id;
2445
+ return [
2446
+ "# SwarmCraft Agent Guide",
2447
+ "",
2448
+ `This repository uses SwarmCraft planning packets for ${projectTitle}.`,
2449
+ "Treat the linked packet under .swarmcraft/projects/ as the source of truth for scoped work.",
2450
+ "",
2451
+ "## Start Here",
2452
+ "",
2453
+ "1. If SwarmCraft copied an action command, run that command in your AI chat surface first.",
2454
+ "2. Read this file before editing code or moving ticket state.",
2455
+ "3. Open the linked packet under .swarmcraft/projects/<project-slug>/<recommended-order>-<ticket-slug>.md.",
2456
+ "4. Read .swarmcraft/project.instructions.md and .swarmcraft/project.context.md for project-specific context.",
2457
+ "5. Read the lane-specific guidance under .swarmcraft/agents/ for the current workflow stage.",
2458
+ "",
2459
+ "Primary assistant actions:",
2460
+ "",
2461
+ ...packet_workflow_1.SWARMCRAFT_ASSISTANT_ACTIONS.map((action) => `- \`${action.copilotInvocation}\` in Copilot or \`${action.codexInvocation}\` in Codex: ${action.description}`),
2462
+ "",
2463
+ "When copied from the VS Code extension, the exact command format follows the workspace's selected AI provider:",
2464
+ "",
2465
+ "- Copilot copies `/plan`, `/do`, `/check`, `/review`, and `/test` prompt commands for `.github/prompts`.",
2466
+ "- Codex copies `$swarmcraft-plan`, `$swarmcraft-do`, `$swarmcraft-check`, `$swarmcraft-review`, and `$swarmcraft-test` skill invocations for `.agents/skills`.",
2467
+ "",
2468
+ "## Packet Workflow",
2469
+ "",
2470
+ "- Use the packet Goal section to understand the intended outcome.",
2471
+ "- Treat the staged checklist sections as the definition of done for each workflow lane.",
2472
+ "- Mark completed checklist items in the packet as soon as repository state and validation support them.",
2473
+ "- Keep the Notes section current with implementation details and decisions.",
2474
+ "- Keep the Agent Update section current with status, blockers, and follow-up work.",
2475
+ "- When all current-lane checklist items are complete and no blockers or questions remain, set the packet frontmatter `lane` to the next adjacent lane, except review-to-done which is owned by the extension.",
2476
+ "- Keep the packet aligned with the actual code and board state before promoting the ticket.",
2477
+ "",
2478
+ "## Guardrails",
2479
+ "",
2480
+ "- Implement only the scoped ticket work unless the packet explicitly calls for adjacent changes.",
2481
+ "- Keep diffs small, reviewable, and easy to validate.",
2482
+ "- Do not rewrite packet identity fields or move packet files to a different path.",
2483
+ "- If the packet, repo, and board state diverge, reconcile them before moving the ticket forward.",
2484
+ "- Leave clear context for the next agent or reviewer in the packet instead of only in chat.",
2485
+ "",
2486
+ "## Lane Guidance",
2487
+ "",
2488
+ ...packet_workflow_1.SWARMCRAFT_STAGE_CONTRACTS.map((stage) => `- ${stage.stageSummary}`),
2489
+ "",
2490
+ "## Provider Adapters",
2491
+ "",
2492
+ "- .swarmcraft packets, project context, and lane instructions are the shared SwarmCraft contract.",
2493
+ "- Provider-specific files under .github, .agents, and .codex are adapters for the same `plan`, `do`, `check`, `review`, and `test` workflow.",
2494
+ "- SwarmCraft Implementor: execute the doing-lane packet work and keep the packet current.",
2495
+ "- SwarmCraft Checker: run focused validation and reconcile the packet with the repo state.",
2496
+ "- SwarmCraft Reviewer: prompt the human reviewer for approval decisions and record them without acting as another checking pass.",
2497
+ "",
2498
+ "## Seeded Files",
2499
+ "",
2500
+ "- .swarmcraft/project.instructions.md contains project-specific guidance and protected constraints.",
2501
+ "- .swarmcraft/project.context.md contains actors, dependencies, platforms, and rollout context.",
2502
+ "- .swarmcraft/project.seed-summary.md records the engine-owned repo context that was seeded.",
2503
+ "- .swarmcraft/agents/doing.instructions.md contains implementation-stage guidance.",
2504
+ "- .swarmcraft/agents/checking.instructions.md contains validation-stage guidance.",
2505
+ "- .swarmcraft/agents/reviewing.instructions.md contains review-stage guidance.",
2506
+ "- .github/instructions/swarmcraft/swarmcraft-packets.instructions.md auto-applies packet editing guardrails.",
2507
+ "- .github/agents/swarmcraft-implementor.agent.md provides the implementation agent in the Copilot agent picker.",
2508
+ "- .github/agents/swarmcraft-checker.agent.md provides the validation agent in the Copilot agent picker.",
2509
+ "- .github/agents/swarmcraft-reviewer.agent.md provides the review-prep agent in the Copilot agent picker.",
2510
+ "- .github/skills/swarmcraft-plan/SKILL.md provides the Copilot planning skill.",
2511
+ "- .github/skills/swarmcraft-do/SKILL.md provides the Copilot doing skill.",
2512
+ "- .github/skills/swarmcraft-check/SKILL.md provides the Copilot checking skill.",
2513
+ "- .github/skills/swarmcraft-review/SKILL.md provides the Copilot reviewing skill.",
2514
+ "- .github/skills/swarmcraft-test/SKILL.md provides the Copilot testing skill.",
2515
+ "- .github/prompts/plan.prompt.md provides the `/plan` command wrapper.",
2516
+ "- .github/prompts/do.prompt.md provides the `/do ticket=...` command wrapper.",
2517
+ "- .github/prompts/check.prompt.md provides the `/check ticket=...` command wrapper.",
2518
+ "- .github/prompts/review.prompt.md provides the `/review ticket=...` command wrapper.",
2519
+ "- .github/prompts/test.prompt.md provides the `/test` command wrapper.",
2520
+ "- .agents/skills/swarmcraft-plan/SKILL.md provides the Codex planning skill.",
2521
+ "- .agents/skills/swarmcraft-do/SKILL.md provides the Codex doing skill.",
2522
+ "- .agents/skills/swarmcraft-check/SKILL.md provides the Codex checking skill.",
2523
+ "- .agents/skills/swarmcraft-review/SKILL.md provides the Codex reviewing skill.",
2524
+ "- .agents/skills/swarmcraft-test/SKILL.md provides the Codex testing skill.",
2525
+ "- .codex/agents/swarmcraft-implementor.toml provides the optional Codex implementor project agent.",
2526
+ "- .codex/agents/swarmcraft-checker.toml provides the optional Codex checker project agent.",
2527
+ "- .codex/agents/swarmcraft-reviewer.toml provides the optional Codex reviewer project agent.",
2528
+ "- .codex/config.example.toml documents optional local Codex setup without committing secrets.",
2529
+ ""
2530
+ ].join("\n");
2531
+ }
2532
+ function renderProjectSeedSummaryFile(project) {
2533
+ const repoSeed = project.repoSeed;
2534
+ const workspaceInstructions = repoSeed?.workspaceInstructions ?? [];
2535
+ const suggestedStructures = repoSeed?.suggestedStructures ?? [];
2536
+ const syncPolicy = repoSeed?.syncPolicy;
2537
+ const seededGuidanceLines = workspaceInstructions.length > 0 ? workspaceInstructions.map((instruction) => `- ${instruction.relativePath}: ${instruction.purpose}`) : ["- Add the seeded workspace instruction files here."];
2538
+ const suggestedStructureLines = suggestedStructures.length > 0 ? suggestedStructures.map((structure) => `- ${structure.relativePath}: ${structure.reason}`) : ["- Add the suggested repository structure here."];
2539
+ const syncPolicyLines = syncPolicy ? [
2540
+ `- Lane sync: ${formatSyncPolicyState(syncPolicy.allowLaneSync, "Adjacent lane changes can sync from the packet back to SwarmCraft.", "Workflow lane changes remain board-authoritative.")}`,
2541
+ `- Checklist sync: ${formatSyncPolicyState(syncPolicy.allowChecklistSync, "Checklist completion can sync from the packet back to SwarmCraft.", "Checklist completion remains board-authoritative.")}`,
2542
+ `- Notes sync: ${formatSyncPolicyState(syncPolicy.allowNotesSync, "Packet Notes can sync back to SwarmCraft.", "Packet Notes are treated as local-only guidance.")}`,
2543
+ `- Agent update sync: ${formatSyncPolicyState(syncPolicy.allowAgentUpdateSync, "Packet Agent Update content can sync back to SwarmCraft.", "Packet Agent Update content is treated as local-only guidance.")}`
2544
+ ] : ["- Sync policy was not included in the current project detail payload."];
2545
+ return [
2546
+ "# Project Seed Summary",
2547
+ "",
2548
+ "This file captures the repo-facing slice of the engine-owned project seed that SwarmCraft used during initial repository seeding.",
2549
+ "",
2550
+ "## Seeded Guidance",
2551
+ "",
2552
+ ...seededGuidanceLines,
2553
+ "",
2554
+ "## Suggested Structure",
2555
+ "",
2556
+ ...suggestedStructureLines,
2557
+ "",
2558
+ "## Packet Sync Policy",
2559
+ "",
2560
+ ...syncPolicyLines,
2561
+ "",
2562
+ "## Surface Ownership",
2563
+ "",
2564
+ "- Engine-generated: .swarmcraft/AGENTS.md, .swarmcraft/project.context.md, .swarmcraft/project.seed-summary.md, and the lane guidance files are seeded from the engine-owned project seed.",
2565
+ "- Human-authored: .swarmcraft/project.instructions.md is preserved after the first seed and can be refined by the project team.",
2566
+ "- Repo-editable: packet checkbox completion, Notes, Agent Update, and adjacent lane moves are repo-editable only when the packet sync policy above allows them.",
2567
+ "- Board-authoritative: packet identity fields, board revision, ticket ordering, and checklist text or structure remain owned by SwarmCraft.",
2568
+ ""
2569
+ ].join("\n");
2570
+ }
2571
+ function formatSyncPolicyState(enabled, enabledText, disabledText) {
2572
+ return enabled ? enabledText : disabledText;
2573
+ }
2574
+ function renderRootAgentsManagedSection(project) {
2575
+ const projectTitle = project.title?.trim() || project.id;
2576
+ return [
2577
+ MANAGED_SECTION_START,
2578
+ "## SwarmCraft",
2579
+ "",
2580
+ `${projectTitle} uses SwarmCraft planning packets and agent guidance files under .swarmcraft/.`,
2581
+ "",
2582
+ "When working on a SwarmCraft-scoped ticket:",
2583
+ "- start with .swarmcraft/AGENTS.md",
2584
+ "- then open the linked packet under .swarmcraft/projects/",
2585
+ "- use the packet as the source of truth for scoped work and status updates",
2586
+ MANAGED_SECTION_END,
2587
+ ""
2588
+ ].join("\n");
2589
+ }
2590
+ }
2591
+ });
2592
+
2593
+ // ../../packages/repo-seed/dist/templates/renderWorkspaceInstructions.js
2594
+ var require_renderWorkspaceInstructions = __commonJS({
2595
+ "../../packages/repo-seed/dist/templates/renderWorkspaceInstructions.js"(exports2) {
2596
+ "use strict";
2597
+ Object.defineProperty(exports2, "__esModule", { value: true });
2598
+ exports2.renderDoingInstructionsFile = renderDoingInstructionsFile;
2599
+ exports2.renderCheckingInstructionsFile = renderCheckingInstructionsFile;
2600
+ exports2.renderReviewingInstructionsFile = renderReviewingInstructionsFile;
2601
+ var packet_workflow_1 = require_dist();
2602
+ function renderDoingInstructionsFile() {
2603
+ return renderLaneInstructionsFile("doing");
2604
+ }
2605
+ function renderCheckingInstructionsFile() {
2606
+ return renderLaneInstructionsFile("checking");
2607
+ }
2608
+ function renderReviewingInstructionsFile() {
2609
+ return renderLaneInstructionsFile("reviewing");
2610
+ }
2611
+ function renderLaneInstructionsFile(stageKey) {
2612
+ const stage = (0, packet_workflow_1.getSwarmCraftStageContract)(stageKey);
2613
+ return [
2614
+ `# ${stage.laneInstructionsTitle}`,
2615
+ "",
2616
+ ...(0, packet_workflow_1.renderBullets)(stage.laneInstructions),
2617
+ ""
2618
+ ].join("\n");
2619
+ }
2620
+ }
2621
+ });
2622
+
2623
+ // ../../packages/repo-seed/dist/seedProjectContext.js
2624
+ var require_seedProjectContext = __commonJS({
2625
+ "../../packages/repo-seed/dist/seedProjectContext.js"(exports2) {
2626
+ "use strict";
2627
+ Object.defineProperty(exports2, "__esModule", { value: true });
2628
+ exports2.CODEX_CONFIG_EXAMPLE_FILE_PATH = exports2.CODEX_REVIEWER_AGENT_FILE_PATH = exports2.CODEX_CHECKER_AGENT_FILE_PATH = exports2.CODEX_IMPLEMENTOR_AGENT_FILE_PATH = exports2.CODEX_TEST_SKILL_FILE_PATH = exports2.CODEX_REVIEW_SKILL_FILE_PATH = exports2.CODEX_CHECK_SKILL_FILE_PATH = exports2.CODEX_DO_SKILL_FILE_PATH = exports2.CODEX_PLAN_SKILL_FILE_PATH = exports2.TEST_PROMPT_FILE_PATH = exports2.REVIEW_PROMPT_FILE_PATH = exports2.CHECK_PROMPT_FILE_PATH = exports2.DO_PROMPT_FILE_PATH = exports2.PLAN_PROMPT_FILE_PATH = exports2.TEST_SKILL_FILE_PATH = exports2.REVIEW_SKILL_FILE_PATH = exports2.CHECK_SKILL_FILE_PATH = exports2.DO_SKILL_FILE_PATH = exports2.PLAN_SKILL_FILE_PATH = exports2.REVIEWER_AGENT_FILE_PATH = exports2.CHECKER_AGENT_FILE_PATH = exports2.IMPLEMENTOR_AGENT_FILE_PATH = exports2.PACKET_INSTRUCTIONS_FILE_PATH = exports2.REVIEWING_INSTRUCTIONS_FILE_PATH = exports2.CHECKING_INSTRUCTIONS_FILE_PATH = exports2.DOING_INSTRUCTIONS_FILE_PATH = exports2.PROJECT_SEED_SUMMARY_FILE_PATH = exports2.PROJECT_CONTEXT_FILE_PATH = exports2.PROJECT_INSTRUCTIONS_FILE_PATH = exports2.SWARMCRAFT_AGENTS_FILE_PATH = void 0;
2629
+ exports2.buildProjectSeedFiles = buildProjectSeedFiles;
2630
+ var renderCopilotAgents_1 = require_renderCopilotAgents();
2631
+ var renderCodexAgents_1 = require_renderCodexAgents();
2632
+ var renderCodexSkills_1 = require_renderCodexSkills();
2633
+ var renderCopilotSkills_1 = require_renderCopilotSkills();
2634
+ var renderCopilotPrompts_1 = require_renderCopilotPrompts();
2635
+ var renderProjectContext_1 = require_renderProjectContext();
2636
+ var renderProjectGuide_1 = require_renderProjectGuide();
2637
+ var renderWorkspaceInstructions_1 = require_renderWorkspaceInstructions();
2638
+ exports2.SWARMCRAFT_AGENTS_FILE_PATH = ".swarmcraft/AGENTS.md";
2639
+ exports2.PROJECT_INSTRUCTIONS_FILE_PATH = ".swarmcraft/project.instructions.md";
2640
+ exports2.PROJECT_CONTEXT_FILE_PATH = ".swarmcraft/project.context.md";
2641
+ exports2.PROJECT_SEED_SUMMARY_FILE_PATH = ".swarmcraft/project.seed-summary.md";
2642
+ exports2.DOING_INSTRUCTIONS_FILE_PATH = ".swarmcraft/agents/doing.instructions.md";
2643
+ exports2.CHECKING_INSTRUCTIONS_FILE_PATH = ".swarmcraft/agents/checking.instructions.md";
2644
+ exports2.REVIEWING_INSTRUCTIONS_FILE_PATH = ".swarmcraft/agents/reviewing.instructions.md";
2645
+ exports2.PACKET_INSTRUCTIONS_FILE_PATH = ".github/instructions/swarmcraft/swarmcraft-packets.instructions.md";
2646
+ exports2.IMPLEMENTOR_AGENT_FILE_PATH = ".github/agents/swarmcraft-implementor.agent.md";
2647
+ exports2.CHECKER_AGENT_FILE_PATH = ".github/agents/swarmcraft-checker.agent.md";
2648
+ exports2.REVIEWER_AGENT_FILE_PATH = ".github/agents/swarmcraft-reviewer.agent.md";
2649
+ exports2.PLAN_SKILL_FILE_PATH = ".github/skills/swarmcraft-plan/SKILL.md";
2650
+ exports2.DO_SKILL_FILE_PATH = ".github/skills/swarmcraft-do/SKILL.md";
2651
+ exports2.CHECK_SKILL_FILE_PATH = ".github/skills/swarmcraft-check/SKILL.md";
2652
+ exports2.REVIEW_SKILL_FILE_PATH = ".github/skills/swarmcraft-review/SKILL.md";
2653
+ exports2.TEST_SKILL_FILE_PATH = ".github/skills/swarmcraft-test/SKILL.md";
2654
+ exports2.PLAN_PROMPT_FILE_PATH = ".github/prompts/plan.prompt.md";
2655
+ exports2.DO_PROMPT_FILE_PATH = ".github/prompts/do.prompt.md";
2656
+ exports2.CHECK_PROMPT_FILE_PATH = ".github/prompts/check.prompt.md";
2657
+ exports2.REVIEW_PROMPT_FILE_PATH = ".github/prompts/review.prompt.md";
2658
+ exports2.TEST_PROMPT_FILE_PATH = ".github/prompts/test.prompt.md";
2659
+ exports2.CODEX_PLAN_SKILL_FILE_PATH = ".agents/skills/swarmcraft-plan/SKILL.md";
2660
+ exports2.CODEX_DO_SKILL_FILE_PATH = ".agents/skills/swarmcraft-do/SKILL.md";
2661
+ exports2.CODEX_CHECK_SKILL_FILE_PATH = ".agents/skills/swarmcraft-check/SKILL.md";
2662
+ exports2.CODEX_REVIEW_SKILL_FILE_PATH = ".agents/skills/swarmcraft-review/SKILL.md";
2663
+ exports2.CODEX_TEST_SKILL_FILE_PATH = ".agents/skills/swarmcraft-test/SKILL.md";
2664
+ exports2.CODEX_IMPLEMENTOR_AGENT_FILE_PATH = ".codex/agents/swarmcraft-implementor.toml";
2665
+ exports2.CODEX_CHECKER_AGENT_FILE_PATH = ".codex/agents/swarmcraft-checker.toml";
2666
+ exports2.CODEX_REVIEWER_AGENT_FILE_PATH = ".codex/agents/swarmcraft-reviewer.toml";
2667
+ exports2.CODEX_CONFIG_EXAMPLE_FILE_PATH = ".codex/config.example.toml";
2668
+ function buildProjectSeedFiles(project) {
2669
+ return [
2670
+ {
2671
+ relativePath: exports2.SWARMCRAFT_AGENTS_FILE_PATH,
2672
+ contents: (0, renderProjectGuide_1.renderSwarmCraftAgentsFile)(project)
2673
+ },
2674
+ {
2675
+ relativePath: exports2.PROJECT_INSTRUCTIONS_FILE_PATH,
2676
+ contents: (0, renderProjectContext_1.renderProjectInstructionsFile)(project)
2677
+ },
2678
+ {
2679
+ relativePath: exports2.PROJECT_CONTEXT_FILE_PATH,
2680
+ contents: (0, renderProjectContext_1.renderProjectContextFile)(project)
2681
+ },
2682
+ {
2683
+ relativePath: exports2.PROJECT_SEED_SUMMARY_FILE_PATH,
2684
+ contents: (0, renderProjectGuide_1.renderProjectSeedSummaryFile)(project)
2685
+ },
2686
+ {
2687
+ relativePath: exports2.DOING_INSTRUCTIONS_FILE_PATH,
2688
+ contents: (0, renderWorkspaceInstructions_1.renderDoingInstructionsFile)()
2689
+ },
2690
+ {
2691
+ relativePath: exports2.CHECKING_INSTRUCTIONS_FILE_PATH,
2692
+ contents: (0, renderWorkspaceInstructions_1.renderCheckingInstructionsFile)()
2693
+ },
2694
+ {
2695
+ relativePath: exports2.REVIEWING_INSTRUCTIONS_FILE_PATH,
2696
+ contents: (0, renderWorkspaceInstructions_1.renderReviewingInstructionsFile)()
2697
+ },
2698
+ {
2699
+ relativePath: exports2.PACKET_INSTRUCTIONS_FILE_PATH,
2700
+ contents: (0, renderCopilotAgents_1.renderPacketInstructionsFile)()
2701
+ },
2702
+ {
2703
+ relativePath: exports2.IMPLEMENTOR_AGENT_FILE_PATH,
2704
+ contents: (0, renderCopilotAgents_1.renderImplementorAgentFile)()
2705
+ },
2706
+ {
2707
+ relativePath: exports2.CHECKER_AGENT_FILE_PATH,
2708
+ contents: (0, renderCopilotAgents_1.renderCheckerAgentFile)()
2709
+ },
2710
+ {
2711
+ relativePath: exports2.REVIEWER_AGENT_FILE_PATH,
2712
+ contents: (0, renderCopilotAgents_1.renderReviewerAgentFile)()
2713
+ },
2714
+ {
2715
+ relativePath: exports2.PLAN_SKILL_FILE_PATH,
2716
+ contents: (0, renderCopilotSkills_1.renderSwarmCraftPlanSkillFile)()
2717
+ },
2718
+ {
2719
+ relativePath: exports2.DO_SKILL_FILE_PATH,
2720
+ contents: (0, renderCopilotSkills_1.renderSwarmCraftDoSkillFile)()
2721
+ },
2722
+ {
2723
+ relativePath: exports2.CHECK_SKILL_FILE_PATH,
2724
+ contents: (0, renderCopilotSkills_1.renderSwarmCraftCheckSkillFile)()
2725
+ },
2726
+ {
2727
+ relativePath: exports2.REVIEW_SKILL_FILE_PATH,
2728
+ contents: (0, renderCopilotSkills_1.renderSwarmCraftReviewSkillFile)()
2729
+ },
2730
+ {
2731
+ relativePath: exports2.TEST_SKILL_FILE_PATH,
2732
+ contents: (0, renderCopilotSkills_1.renderSwarmCraftTestSkillFile)()
2733
+ },
2734
+ {
2735
+ relativePath: exports2.PLAN_PROMPT_FILE_PATH,
2736
+ contents: (0, renderCopilotPrompts_1.renderPlanPromptFile)()
2737
+ },
2738
+ {
2739
+ relativePath: exports2.DO_PROMPT_FILE_PATH,
2740
+ contents: (0, renderCopilotPrompts_1.renderDoPromptFile)()
2741
+ },
2742
+ {
2743
+ relativePath: exports2.CHECK_PROMPT_FILE_PATH,
2744
+ contents: (0, renderCopilotPrompts_1.renderCheckPromptFile)()
2745
+ },
2746
+ {
2747
+ relativePath: exports2.REVIEW_PROMPT_FILE_PATH,
2748
+ contents: (0, renderCopilotPrompts_1.renderReviewPromptFile)()
2749
+ },
2750
+ {
2751
+ relativePath: exports2.TEST_PROMPT_FILE_PATH,
2752
+ contents: (0, renderCopilotPrompts_1.renderTestPromptFile)()
2753
+ },
2754
+ {
2755
+ relativePath: exports2.CODEX_PLAN_SKILL_FILE_PATH,
2756
+ contents: (0, renderCodexSkills_1.renderCodexSwarmCraftPlanSkillFile)()
2757
+ },
2758
+ {
2759
+ relativePath: exports2.CODEX_DO_SKILL_FILE_PATH,
2760
+ contents: (0, renderCodexSkills_1.renderCodexSwarmCraftDoSkillFile)()
2761
+ },
2762
+ {
2763
+ relativePath: exports2.CODEX_CHECK_SKILL_FILE_PATH,
2764
+ contents: (0, renderCodexSkills_1.renderCodexSwarmCraftCheckSkillFile)()
2765
+ },
2766
+ {
2767
+ relativePath: exports2.CODEX_REVIEW_SKILL_FILE_PATH,
2768
+ contents: (0, renderCodexSkills_1.renderCodexSwarmCraftReviewSkillFile)()
2769
+ },
2770
+ {
2771
+ relativePath: exports2.CODEX_TEST_SKILL_FILE_PATH,
2772
+ contents: (0, renderCodexSkills_1.renderCodexSwarmCraftTestSkillFile)()
2773
+ },
2774
+ {
2775
+ relativePath: exports2.CODEX_IMPLEMENTOR_AGENT_FILE_PATH,
2776
+ contents: (0, renderCodexAgents_1.renderCodexImplementorAgentFile)()
2777
+ },
2778
+ {
2779
+ relativePath: exports2.CODEX_CHECKER_AGENT_FILE_PATH,
2780
+ contents: (0, renderCodexAgents_1.renderCodexCheckerAgentFile)()
2781
+ },
2782
+ {
2783
+ relativePath: exports2.CODEX_REVIEWER_AGENT_FILE_PATH,
2784
+ contents: (0, renderCodexAgents_1.renderCodexReviewerAgentFile)()
2785
+ },
2786
+ {
2787
+ relativePath: exports2.CODEX_CONFIG_EXAMPLE_FILE_PATH,
2788
+ contents: (0, renderCodexAgents_1.renderCodexConfigExampleFile)()
2789
+ }
2790
+ ];
2791
+ }
2792
+ }
2793
+ });
2794
+
2795
+ // ../../packages/repo-seed/dist/seedProjectFiles.js
2796
+ var require_seedProjectFiles = __commonJS({
2797
+ "../../packages/repo-seed/dist/seedProjectFiles.js"(exports2) {
2798
+ "use strict";
2799
+ Object.defineProperty(exports2, "__esModule", { value: true });
2800
+ exports2.SWARMCRAFT_AGENTS_FILE_PATH = exports2.TEST_SKILL_FILE_PATH = exports2.TEST_PROMPT_FILE_PATH = exports2.REVIEWING_INSTRUCTIONS_FILE_PATH = exports2.REVIEW_SKILL_FILE_PATH = exports2.REVIEW_PROMPT_FILE_PATH = exports2.REVIEWER_AGENT_FILE_PATH = exports2.PROJECT_SEED_SUMMARY_FILE_PATH = exports2.PROJECT_INSTRUCTIONS_FILE_PATH = exports2.PROJECT_CONTEXT_FILE_PATH = exports2.PLAN_SKILL_FILE_PATH = exports2.PLAN_PROMPT_FILE_PATH = exports2.PACKET_INSTRUCTIONS_FILE_PATH = exports2.IMPLEMENTOR_AGENT_FILE_PATH = exports2.DO_SKILL_FILE_PATH = exports2.DOING_INSTRUCTIONS_FILE_PATH = exports2.DO_PROMPT_FILE_PATH = exports2.CODEX_TEST_SKILL_FILE_PATH = exports2.CODEX_REVIEWER_AGENT_FILE_PATH = exports2.CODEX_REVIEW_SKILL_FILE_PATH = exports2.CODEX_PLAN_SKILL_FILE_PATH = exports2.CODEX_IMPLEMENTOR_AGENT_FILE_PATH = exports2.CODEX_DO_SKILL_FILE_PATH = exports2.CODEX_CONFIG_EXAMPLE_FILE_PATH = exports2.CODEX_CHECKER_AGENT_FILE_PATH = exports2.CODEX_CHECK_SKILL_FILE_PATH = exports2.CHECK_SKILL_FILE_PATH = exports2.CHECKING_INSTRUCTIONS_FILE_PATH = exports2.CHECK_PROMPT_FILE_PATH = exports2.CHECKER_AGENT_FILE_PATH = exports2.ROOT_AGENTS_FILE_PATH = void 0;
2801
+ exports2.seedProjectFiles = seedProjectFiles2;
2802
+ var seedProjectContext_1 = require_seedProjectContext();
2803
+ Object.defineProperty(exports2, "CHECKER_AGENT_FILE_PATH", { enumerable: true, get: function() {
2804
+ return seedProjectContext_1.CHECKER_AGENT_FILE_PATH;
2805
+ } });
2806
+ Object.defineProperty(exports2, "CHECK_PROMPT_FILE_PATH", { enumerable: true, get: function() {
2807
+ return seedProjectContext_1.CHECK_PROMPT_FILE_PATH;
2808
+ } });
2809
+ Object.defineProperty(exports2, "CHECKING_INSTRUCTIONS_FILE_PATH", { enumerable: true, get: function() {
2810
+ return seedProjectContext_1.CHECKING_INSTRUCTIONS_FILE_PATH;
2811
+ } });
2812
+ Object.defineProperty(exports2, "CHECK_SKILL_FILE_PATH", { enumerable: true, get: function() {
2813
+ return seedProjectContext_1.CHECK_SKILL_FILE_PATH;
2814
+ } });
2815
+ Object.defineProperty(exports2, "CODEX_CHECK_SKILL_FILE_PATH", { enumerable: true, get: function() {
2816
+ return seedProjectContext_1.CODEX_CHECK_SKILL_FILE_PATH;
2817
+ } });
2818
+ Object.defineProperty(exports2, "CODEX_CHECKER_AGENT_FILE_PATH", { enumerable: true, get: function() {
2819
+ return seedProjectContext_1.CODEX_CHECKER_AGENT_FILE_PATH;
2820
+ } });
2821
+ Object.defineProperty(exports2, "CODEX_CONFIG_EXAMPLE_FILE_PATH", { enumerable: true, get: function() {
2822
+ return seedProjectContext_1.CODEX_CONFIG_EXAMPLE_FILE_PATH;
2823
+ } });
2824
+ Object.defineProperty(exports2, "CODEX_DO_SKILL_FILE_PATH", { enumerable: true, get: function() {
2825
+ return seedProjectContext_1.CODEX_DO_SKILL_FILE_PATH;
2826
+ } });
2827
+ Object.defineProperty(exports2, "CODEX_IMPLEMENTOR_AGENT_FILE_PATH", { enumerable: true, get: function() {
2828
+ return seedProjectContext_1.CODEX_IMPLEMENTOR_AGENT_FILE_PATH;
2829
+ } });
2830
+ Object.defineProperty(exports2, "CODEX_PLAN_SKILL_FILE_PATH", { enumerable: true, get: function() {
2831
+ return seedProjectContext_1.CODEX_PLAN_SKILL_FILE_PATH;
2832
+ } });
2833
+ Object.defineProperty(exports2, "CODEX_REVIEW_SKILL_FILE_PATH", { enumerable: true, get: function() {
2834
+ return seedProjectContext_1.CODEX_REVIEW_SKILL_FILE_PATH;
2835
+ } });
2836
+ Object.defineProperty(exports2, "CODEX_REVIEWER_AGENT_FILE_PATH", { enumerable: true, get: function() {
2837
+ return seedProjectContext_1.CODEX_REVIEWER_AGENT_FILE_PATH;
2838
+ } });
2839
+ Object.defineProperty(exports2, "CODEX_TEST_SKILL_FILE_PATH", { enumerable: true, get: function() {
2840
+ return seedProjectContext_1.CODEX_TEST_SKILL_FILE_PATH;
2841
+ } });
2842
+ Object.defineProperty(exports2, "DO_PROMPT_FILE_PATH", { enumerable: true, get: function() {
2843
+ return seedProjectContext_1.DO_PROMPT_FILE_PATH;
2844
+ } });
2845
+ Object.defineProperty(exports2, "DOING_INSTRUCTIONS_FILE_PATH", { enumerable: true, get: function() {
2846
+ return seedProjectContext_1.DOING_INSTRUCTIONS_FILE_PATH;
2847
+ } });
2848
+ Object.defineProperty(exports2, "DO_SKILL_FILE_PATH", { enumerable: true, get: function() {
2849
+ return seedProjectContext_1.DO_SKILL_FILE_PATH;
2850
+ } });
2851
+ Object.defineProperty(exports2, "IMPLEMENTOR_AGENT_FILE_PATH", { enumerable: true, get: function() {
2852
+ return seedProjectContext_1.IMPLEMENTOR_AGENT_FILE_PATH;
2853
+ } });
2854
+ Object.defineProperty(exports2, "PACKET_INSTRUCTIONS_FILE_PATH", { enumerable: true, get: function() {
2855
+ return seedProjectContext_1.PACKET_INSTRUCTIONS_FILE_PATH;
2856
+ } });
2857
+ Object.defineProperty(exports2, "PLAN_PROMPT_FILE_PATH", { enumerable: true, get: function() {
2858
+ return seedProjectContext_1.PLAN_PROMPT_FILE_PATH;
2859
+ } });
2860
+ Object.defineProperty(exports2, "PLAN_SKILL_FILE_PATH", { enumerable: true, get: function() {
2861
+ return seedProjectContext_1.PLAN_SKILL_FILE_PATH;
2862
+ } });
2863
+ Object.defineProperty(exports2, "PROJECT_CONTEXT_FILE_PATH", { enumerable: true, get: function() {
2864
+ return seedProjectContext_1.PROJECT_CONTEXT_FILE_PATH;
2865
+ } });
2866
+ Object.defineProperty(exports2, "PROJECT_INSTRUCTIONS_FILE_PATH", { enumerable: true, get: function() {
2867
+ return seedProjectContext_1.PROJECT_INSTRUCTIONS_FILE_PATH;
2868
+ } });
2869
+ Object.defineProperty(exports2, "PROJECT_SEED_SUMMARY_FILE_PATH", { enumerable: true, get: function() {
2870
+ return seedProjectContext_1.PROJECT_SEED_SUMMARY_FILE_PATH;
2871
+ } });
2872
+ Object.defineProperty(exports2, "REVIEWER_AGENT_FILE_PATH", { enumerable: true, get: function() {
2873
+ return seedProjectContext_1.REVIEWER_AGENT_FILE_PATH;
2874
+ } });
2875
+ Object.defineProperty(exports2, "REVIEW_PROMPT_FILE_PATH", { enumerable: true, get: function() {
2876
+ return seedProjectContext_1.REVIEW_PROMPT_FILE_PATH;
2877
+ } });
2878
+ Object.defineProperty(exports2, "REVIEW_SKILL_FILE_PATH", { enumerable: true, get: function() {
2879
+ return seedProjectContext_1.REVIEW_SKILL_FILE_PATH;
2880
+ } });
2881
+ Object.defineProperty(exports2, "REVIEWING_INSTRUCTIONS_FILE_PATH", { enumerable: true, get: function() {
2882
+ return seedProjectContext_1.REVIEWING_INSTRUCTIONS_FILE_PATH;
2883
+ } });
2884
+ Object.defineProperty(exports2, "SWARMCRAFT_AGENTS_FILE_PATH", { enumerable: true, get: function() {
2885
+ return seedProjectContext_1.SWARMCRAFT_AGENTS_FILE_PATH;
2886
+ } });
2887
+ Object.defineProperty(exports2, "TEST_PROMPT_FILE_PATH", { enumerable: true, get: function() {
2888
+ return seedProjectContext_1.TEST_PROMPT_FILE_PATH;
2889
+ } });
2890
+ Object.defineProperty(exports2, "TEST_SKILL_FILE_PATH", { enumerable: true, get: function() {
2891
+ return seedProjectContext_1.TEST_SKILL_FILE_PATH;
2892
+ } });
2893
+ var renderProjectGuide_1 = require_renderProjectGuide();
2894
+ exports2.ROOT_AGENTS_FILE_PATH = "AGENTS.md";
2895
+ async function seedProjectFiles2(project, dependencies) {
2896
+ const projectSeedFiles = (0, seedProjectContext_1.buildProjectSeedFiles)(project);
2897
+ for (const seedFile of projectSeedFiles) {
2898
+ if (await dependencies.fileExists(seedFile.relativePath)) {
2899
+ continue;
2900
+ }
2901
+ await dependencies.writeFile(seedFile.relativePath, seedFile.contents);
2902
+ }
2903
+ await upsertRootAgentsPointer(project, dependencies);
2904
+ }
2905
+ async function upsertRootAgentsPointer(project, dependencies) {
2906
+ const managedSection = (0, renderProjectGuide_1.renderRootAgentsManagedSection)(project);
2907
+ const existingContents = await readOptionalFile(exports2.ROOT_AGENTS_FILE_PATH, dependencies);
2908
+ const updatedContents = existingContents === null ? managedSection : upsertManagedSection(existingContents, managedSection);
2909
+ if (updatedContents === existingContents) {
2910
+ return;
2911
+ }
2912
+ await dependencies.writeFile(exports2.ROOT_AGENTS_FILE_PATH, updatedContents);
2913
+ }
2914
+ async function readOptionalFile(relativePath, dependencies) {
2915
+ if (!await dependencies.fileExists(relativePath)) {
2916
+ return null;
2917
+ }
2918
+ return dependencies.readFile(relativePath);
2919
+ }
2920
+ function upsertManagedSection(existingContents, managedSection) {
2921
+ const existingStartIndex = existingContents.indexOf(renderProjectGuide_1.MANAGED_SECTION_START);
2922
+ const existingEndIndex = existingContents.indexOf(renderProjectGuide_1.MANAGED_SECTION_END);
2923
+ if (existingStartIndex >= 0 && existingEndIndex >= 0 && existingEndIndex > existingStartIndex) {
2924
+ const replacementEndIndex = existingEndIndex + renderProjectGuide_1.MANAGED_SECTION_END.length;
2925
+ const updatedContents = `${existingContents.slice(0, existingStartIndex)}${managedSection}${existingContents.slice(replacementEndIndex)}`;
2926
+ return normalizeTrailingNewline(updatedContents);
2927
+ }
2928
+ const separator = existingContents.endsWith("\n\n") ? "" : existingContents.endsWith("\n") ? "\n" : "\n\n";
2929
+ return normalizeTrailingNewline(`${existingContents}${separator}${managedSection}`);
2930
+ }
2931
+ function normalizeTrailingNewline(contents) {
2932
+ return `${contents.replace(/\s*$/, "")}
2933
+ `;
2934
+ }
2935
+ }
2936
+ });
2937
+
2938
+ // ../../packages/repo-seed/dist/index.js
2939
+ var require_dist2 = __commonJS({
2940
+ "../../packages/repo-seed/dist/index.js"(exports2) {
2941
+ "use strict";
2942
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
2943
+ if (k2 === void 0) k2 = k;
2944
+ var desc = Object.getOwnPropertyDescriptor(m, k);
2945
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
2946
+ desc = { enumerable: true, get: function() {
2947
+ return m[k];
2948
+ } };
2949
+ }
2950
+ Object.defineProperty(o, k2, desc);
2951
+ }) : (function(o, m, k, k2) {
2952
+ if (k2 === void 0) k2 = k;
2953
+ o[k2] = m[k];
2954
+ }));
2955
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
2956
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
2957
+ };
2958
+ Object.defineProperty(exports2, "__esModule", { value: true });
2959
+ __exportStar(require_projectSeedModels(), exports2);
2960
+ __exportStar(require_seedProjectContext(), exports2);
2961
+ __exportStar(require_seedProjectFiles(), exports2);
2962
+ __exportStar(require_renderCodexAgents(), exports2);
2963
+ __exportStar(require_renderCodexSkills(), exports2);
2964
+ __exportStar(require_renderCopilotAgents(), exports2);
2965
+ __exportStar(require_renderCopilotPrompts(), exports2);
2966
+ __exportStar(require_renderCopilotSkills(), exports2);
2967
+ __exportStar(require_renderProjectContext(), exports2);
2968
+ __exportStar(require_renderProjectGuide(), exports2);
2969
+ __exportStar(require_renderWorkspaceInstructions(), exports2);
2970
+ }
2971
+ });
2972
+
2973
+ // src/main.ts
2974
+ var import_promises4 = require("node:fs/promises");
2975
+ var import_node_path5 = __toESM(require("node:path"), 1);
2976
+ var import_promises5 = require("node:readline/promises");
2977
+ var import_node_process = require("node:process");
2978
+ var import_packet_workflow3 = __toESM(require_dist(), 1);
2979
+
2980
+ // src/apiClient.ts
2981
+ var API_REQUEST_TIMEOUT_MS = 15e3;
2982
+ var CLIENT_SOURCE_HEADER = "X-SwarmCraft-Client";
2983
+ var REFRESH_TOKEN_COOKIE_NAME = "swarmcraft_refresh_token";
2984
+ var SwarmCraftApiError = class extends Error {
2985
+ status;
2986
+ code;
2987
+ method;
2988
+ url;
2989
+ requestId;
2990
+ constructor(status, code, message, method, url, requestId) {
2991
+ super(message);
2992
+ this.name = "SwarmCraftApiError";
2993
+ this.status = status;
2994
+ this.code = code;
2995
+ this.method = method;
2996
+ this.url = url;
2997
+ this.requestId = requestId;
2998
+ }
2999
+ };
3000
+ var SwarmCraftClient = class {
3001
+ apiBaseUrl;
3002
+ constructor(apiBaseUrl) {
3003
+ this.apiBaseUrl = apiBaseUrl.replace(/\/$/, "");
3004
+ }
3005
+ login(email, password) {
3006
+ return this.requestJson("/auth/login", {
3007
+ method: "POST",
3008
+ body: JSON.stringify({ email, password })
3009
+ });
3010
+ }
3011
+ refresh(refreshToken) {
3012
+ return this.requestJson("/auth/refresh", { method: "POST" }, void 0, refreshToken);
3013
+ }
3014
+ mfaChallenge(accessToken, code) {
3015
+ return this.requestJson(
3016
+ "/auth/mfa/challenge",
3017
+ {
3018
+ method: "POST",
3019
+ body: JSON.stringify({ code })
3020
+ },
3021
+ accessToken
3022
+ );
3023
+ }
3024
+ mfaRecovery(accessToken, recoveryCode) {
3025
+ return this.requestJson(
3026
+ "/auth/mfa/recovery",
3027
+ {
3028
+ method: "POST",
3029
+ body: JSON.stringify({ recoveryCode })
3030
+ },
3031
+ accessToken
3032
+ );
3033
+ }
3034
+ listProjects(accessToken) {
3035
+ return this.requestJson("/projects", { method: "GET" }, accessToken);
3036
+ }
3037
+ loadProject(projectId, accessToken) {
3038
+ return this.requestJson(`/projects/${encodeURIComponent(projectId)}`, { method: "GET" }, accessToken);
3039
+ }
3040
+ loadBoard(projectId, accessToken) {
3041
+ return this.requestJson(`/projects/${encodeURIComponent(projectId)}/board`, { method: "GET" }, accessToken);
3042
+ }
3043
+ upsertTicketPacketLink(projectId, ticketId, request, accessToken) {
3044
+ return this.requestJson(
3045
+ `/projects/${encodeURIComponent(projectId)}/tickets/${encodeURIComponent(ticketId)}/packet-link`,
3046
+ {
3047
+ method: "PUT",
3048
+ body: JSON.stringify(request)
3049
+ },
3050
+ accessToken
3051
+ );
3052
+ }
3053
+ moveTicket(projectId, ticketId, request, accessToken) {
3054
+ return this.requestJson(
3055
+ `/projects/${encodeURIComponent(projectId)}/tickets/${encodeURIComponent(ticketId)}/move`,
3056
+ {
3057
+ method: "POST",
3058
+ body: JSON.stringify(request)
3059
+ },
3060
+ accessToken
3061
+ );
3062
+ }
3063
+ updateTicketNotes(projectId, ticketId, request, accessToken) {
3064
+ return this.requestJson(
3065
+ `/projects/${encodeURIComponent(projectId)}/tickets/${encodeURIComponent(ticketId)}/notes`,
3066
+ {
3067
+ method: "PATCH",
3068
+ body: JSON.stringify(request)
3069
+ },
3070
+ accessToken
3071
+ );
3072
+ }
3073
+ updateChecklistItem(projectId, ticketId, itemId, request, accessToken) {
3074
+ return this.requestJson(
3075
+ `/projects/${encodeURIComponent(projectId)}/tickets/${encodeURIComponent(ticketId)}/checklist-items/${encodeURIComponent(itemId)}`,
3076
+ {
3077
+ method: "PATCH",
3078
+ body: JSON.stringify(request)
3079
+ },
3080
+ accessToken
3081
+ );
3082
+ }
3083
+ async requestJson(path6, init, accessToken, refreshToken) {
3084
+ const url = `${this.apiBaseUrl}${path6.startsWith("/") ? path6 : `/${path6}`}`;
3085
+ const method = (init.method ?? "GET").toUpperCase();
3086
+ const headers = new Headers(init.headers);
3087
+ const abortController = new AbortController();
3088
+ const timeoutHandle = setTimeout(() => abortController.abort(), API_REQUEST_TIMEOUT_MS);
3089
+ headers.set("Accept", "application/json");
3090
+ headers.set(CLIENT_SOURCE_HEADER, "CLI");
3091
+ if (init.body && !headers.has("Content-Type")) {
3092
+ headers.set("Content-Type", "application/json");
3093
+ }
3094
+ if (accessToken) {
3095
+ headers.set("Authorization", `Bearer ${accessToken}`);
3096
+ }
3097
+ if (refreshToken) {
3098
+ headers.set("Cookie", `${REFRESH_TOKEN_COOKIE_NAME}=${refreshToken}`);
3099
+ }
3100
+ let response;
3101
+ try {
3102
+ response = await fetch(url, {
3103
+ ...init,
3104
+ headers,
3105
+ signal: abortController.signal
3106
+ });
3107
+ } catch (error) {
3108
+ if (error instanceof Error && error.name === "AbortError") {
3109
+ throw new SwarmCraftApiError(0, "NETWORK_ERROR", `Request timed out after ${API_REQUEST_TIMEOUT_MS / 1e3} seconds.`, method, url);
3110
+ }
3111
+ throw new SwarmCraftApiError(0, "NETWORK_ERROR", error instanceof Error ? error.message : "Unable to reach SwarmCraft.", method, url);
3112
+ } finally {
3113
+ clearTimeout(timeoutHandle);
3114
+ }
3115
+ const rawBody = await response.text();
3116
+ const payload = parseJson(rawBody);
3117
+ if (!response.ok) {
3118
+ throw toApiError(response, payload, method, url);
3119
+ }
3120
+ return withRefreshToken(payload, extractRefreshToken(response.headers));
3121
+ }
3122
+ };
3123
+ function withRefreshToken(payload, refreshToken) {
3124
+ if (!payload || typeof payload !== "object" || Array.isArray(payload) || !refreshToken || "refreshToken" in payload) {
3125
+ return payload;
3126
+ }
3127
+ return {
3128
+ ...payload,
3129
+ refreshToken
3130
+ };
3131
+ }
3132
+ function extractRefreshToken(headers) {
3133
+ const extendedHeaders = headers;
3134
+ const setCookieHeaders = typeof extendedHeaders.getSetCookie === "function" ? extendedHeaders.getSetCookie() : headers.get("set-cookie") ? [headers.get("set-cookie")] : [];
3135
+ for (const setCookieHeader of setCookieHeaders) {
3136
+ const firstSegment = setCookieHeader.split(";")[0] ?? "";
3137
+ const separatorIndex = firstSegment.indexOf("=");
3138
+ if (separatorIndex < 0) {
3139
+ continue;
3140
+ }
3141
+ if (firstSegment.slice(0, separatorIndex).trim() === REFRESH_TOKEN_COOKIE_NAME) {
3142
+ return firstSegment.slice(separatorIndex + 1).trim();
3143
+ }
3144
+ }
3145
+ return null;
3146
+ }
3147
+ function parseJson(rawBody) {
3148
+ if (!rawBody) {
3149
+ return null;
3150
+ }
3151
+ try {
3152
+ return JSON.parse(rawBody);
3153
+ } catch {
3154
+ return rawBody;
3155
+ }
3156
+ }
3157
+ function toApiError(response, payload, method, url) {
3158
+ if (payload && typeof payload === "object" && "message" in payload) {
3159
+ const apiError = payload;
3160
+ return new SwarmCraftApiError(
3161
+ apiError.status ?? response.status,
3162
+ apiError.code ?? "UNKNOWN_ERROR",
3163
+ apiError.message ?? response.statusText,
3164
+ method,
3165
+ url,
3166
+ apiError.requestId
3167
+ );
3168
+ }
3169
+ return new SwarmCraftApiError(response.status, "UNKNOWN_ERROR", response.statusText || "Request failed.", method, url);
3170
+ }
3171
+
3172
+ // src/bootstrap.ts
3173
+ var import_node_path2 = __toESM(require("node:path"), 1);
3174
+ var import_packet_workflow = __toESM(require_dist(), 1);
3175
+ var import_repo_seed = __toESM(require_dist2(), 1);
3176
+
3177
+ // src/workspace.ts
3178
+ var import_promises = require("node:fs/promises");
3179
+ var import_node_path = __toESM(require("node:path"), 1);
3180
+ var import_node_child_process = require("node:child_process");
3181
+ var import_node_util = require("node:util");
3182
+ var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
3183
+ async function validateWorkspace(workspacePath) {
3184
+ const resolvedWorkspacePath = import_node_path.default.resolve(workspacePath);
3185
+ const workspaceStat = await (0, import_promises.stat)(resolvedWorkspacePath);
3186
+ if (!workspaceStat.isDirectory()) {
3187
+ throw new Error(`Workspace path is not a directory: ${resolvedWorkspacePath}`);
3188
+ }
3189
+ const gitRoot = (await runGit(["rev-parse", "--show-toplevel"], resolvedWorkspacePath)).trim();
3190
+ const unmergedFiles = (await runGit(["diff", "--name-only", "--diff-filter=U"], resolvedWorkspacePath)).split("\n").filter(Boolean);
3191
+ if (unmergedFiles.length > 0) {
3192
+ throw new Error(`Workspace has unresolved merge conflicts: ${unmergedFiles.join(", ")}`);
3193
+ }
3194
+ const dirtyFileCount = (await runGit(["status", "--porcelain"], resolvedWorkspacePath)).split("\n").filter(Boolean).length;
3195
+ return {
3196
+ workspacePath: resolvedWorkspacePath,
3197
+ workspaceFolderName: import_node_path.default.basename(resolvedWorkspacePath),
3198
+ gitRoot,
3199
+ dirtyFileCount,
3200
+ hasUnmergedFiles: false
3201
+ };
3202
+ }
3203
+ async function fileExists(absolutePath) {
3204
+ try {
3205
+ await (0, import_promises.access)(absolutePath);
3206
+ return true;
3207
+ } catch {
3208
+ return false;
3209
+ }
3210
+ }
3211
+ async function readWorkspaceFile(workspacePath, relativePath) {
3212
+ return (0, import_promises.readFile)(import_node_path.default.join(workspacePath, relativePath), "utf8");
3213
+ }
3214
+ async function writeWorkspaceFile(workspacePath, relativePath, contents) {
3215
+ const absolutePath = import_node_path.default.join(workspacePath, relativePath);
3216
+ await (0, import_promises.mkdir)(import_node_path.default.dirname(absolutePath), { recursive: true });
3217
+ await (0, import_promises.writeFile)(absolutePath, contents, "utf8");
3218
+ }
3219
+ async function runCommand(command, cwd, env = process.env) {
3220
+ return new Promise((resolve) => {
3221
+ const child = (0, import_node_child_process.spawn)(command, {
3222
+ cwd,
3223
+ env,
3224
+ shell: true,
3225
+ stdio: ["ignore", "pipe", "pipe"]
3226
+ });
3227
+ const stdoutChunks = [];
3228
+ const stderrChunks = [];
3229
+ child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
3230
+ child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
3231
+ child.on("close", (code) => {
3232
+ resolve({
3233
+ exitCode: code ?? 1,
3234
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
3235
+ stderr: Buffer.concat(stderrChunks).toString("utf8")
3236
+ });
3237
+ });
3238
+ });
3239
+ }
3240
+ async function gitAddAndCommit(workspacePath, message) {
3241
+ await runGit(["add", "."], workspacePath);
3242
+ const staged = (await runGit(["diff", "--cached", "--name-only"], workspacePath)).trim();
3243
+ if (!staged) {
3244
+ return false;
3245
+ }
3246
+ await runGit(["commit", "-m", message], workspacePath);
3247
+ return true;
3248
+ }
3249
+ async function runGit(args, cwd) {
3250
+ try {
3251
+ const result = await execFileAsync("git", args, { cwd });
3252
+ return result.stdout;
3253
+ } catch (error) {
3254
+ throw new Error(`Git command failed in ${cwd}: git ${args.join(" ")}`);
3255
+ }
3256
+ }
3257
+
3258
+ // src/bootstrap.ts
3259
+ async function runBootstrap(client, accessToken, options) {
3260
+ const workspace = await validateWorkspace(options.workspacePath);
3261
+ const project = await client.loadProject(options.projectId, accessToken);
3262
+ if (project.boardState !== "UNLOCKED") {
3263
+ throw new Error(`Project ${project.id} is ${project.boardState}; unlock the board before bootstrapping a workspace.`);
3264
+ }
3265
+ const board = await client.loadBoard(project.id, accessToken);
3266
+ const seedFilesWritten = await seedWorkspace(project, workspace.workspacePath);
3267
+ const selectedTickets = selectBootstrapTickets(board, options);
3268
+ const packetFilesCreated = [];
3269
+ const packetFilesRefreshed = [];
3270
+ const linkedPackets = [];
3271
+ const skippedTickets = [];
3272
+ const syncedAt = (/* @__PURE__ */ new Date()).toISOString();
3273
+ for (const ticket of selectedTickets) {
3274
+ if (ticket.packetLink && ticket.packetLink.workspaceFolder !== workspace.workspaceFolderName) {
3275
+ skippedTickets.push({
3276
+ ticketId: ticket.id,
3277
+ title: ticket.title,
3278
+ reason: `already linked to workspace ${ticket.packetLink.workspaceFolder}`
3279
+ });
3280
+ continue;
3281
+ }
3282
+ const relativePacketPath = (0, import_packet_workflow.resolvePacketFilePath)(project, ticket, ticket.packetLink);
3283
+ const absolutePacketPath = import_node_path2.default.join(workspace.workspacePath, relativePacketPath);
3284
+ let packetContents;
3285
+ if (await fileExists(absolutePacketPath)) {
3286
+ const existingContents = await readWorkspaceFile(workspace.workspacePath, relativePacketPath);
3287
+ try {
3288
+ (0, import_packet_workflow.ensurePacketFileIdentity)(existingContents, project.id, ticket.id);
3289
+ (0, import_packet_workflow.parsePacketFile)(existingContents);
3290
+ packetContents = (0, import_packet_workflow.rewritePacketFileMetadata)(existingContents, {
3291
+ lane: ticket.workflowState,
3292
+ syncRevision: ticket.revision,
3293
+ lastSyncedAt: syncedAt
3294
+ });
3295
+ } catch (error) {
3296
+ if (error instanceof import_packet_workflow.PacketFileContractError && error.code === "PACKET_FILE_MALFORMED") {
3297
+ skippedTickets.push({
3298
+ ticketId: ticket.id,
3299
+ title: ticket.title,
3300
+ reason: `existing packet is malformed at ${relativePacketPath}`
3301
+ });
3302
+ continue;
3303
+ }
3304
+ throw error;
3305
+ }
3306
+ if (packetContents !== existingContents) {
3307
+ await writeWorkspaceFile(workspace.workspacePath, relativePacketPath, packetContents);
3308
+ packetFilesRefreshed.push(relativePacketPath);
3309
+ }
3310
+ } else {
3311
+ packetContents = (0, import_packet_workflow.renderPacketFile)(project, ticket, syncedAt);
3312
+ await writeWorkspaceFile(workspace.workspacePath, relativePacketPath, packetContents);
3313
+ packetFilesCreated.push(relativePacketPath);
3314
+ }
3315
+ await client.upsertTicketPacketLink(project.id, ticket.id, {
3316
+ workspaceFolder: workspace.workspaceFolderName,
3317
+ packetFilePath: relativePacketPath,
3318
+ expectedRevision: ticket.revision,
3319
+ lastSyncedTicketRevision: ticket.revision,
3320
+ lastSyncedAt: syncedAt
3321
+ }, accessToken);
3322
+ linkedPackets.push(relativePacketPath);
3323
+ }
3324
+ return {
3325
+ projectTitle: project.title || project.projectTitle || project.id,
3326
+ workspacePath: workspace.workspacePath,
3327
+ dirtyFileCount: workspace.dirtyFileCount,
3328
+ seedFilesWritten,
3329
+ packetFilesCreated,
3330
+ packetFilesRefreshed,
3331
+ linkedPackets,
3332
+ skippedTickets,
3333
+ nextCommands: [
3334
+ `swarmcraft one-shot --project ${project.id} --workspace ${workspace.workspacePath} --agent-provider codex`,
3335
+ "Review generated files under .swarmcraft/, .github/, .agents/, and .codex/ before running agents."
3336
+ ]
3337
+ };
3338
+ }
3339
+ function selectBootstrapTickets(board, options) {
3340
+ const requestedTicketIds = new Set(options.ticketIds);
3341
+ const tickets = board.columns.flatMap((column) => column.tickets).filter((ticket) => ticket.workflowState !== "done").filter((ticket) => requestedTicketIds.size === 0 || requestedTicketIds.has(ticket.id)).sort((left, right) => {
3342
+ if (left.recommendedOrder !== right.recommendedOrder) {
3343
+ return left.recommendedOrder - right.recommendedOrder;
3344
+ }
3345
+ return left.columnOrder - right.columnOrder;
3346
+ });
3347
+ return options.ticketLimit === "all" ? tickets : tickets.slice(0, options.ticketLimit);
3348
+ }
3349
+ async function seedWorkspace(project, workspacePath) {
3350
+ const writtenPaths = [];
3351
+ await (0, import_repo_seed.seedProjectFiles)(project, {
3352
+ async fileExists(relativePath) {
3353
+ return fileExists(import_node_path2.default.join(workspacePath, relativePath));
3354
+ },
3355
+ async readFile(relativePath) {
3356
+ return readWorkspaceFile(workspacePath, relativePath);
3357
+ },
3358
+ async writeFile(relativePath, contents) {
3359
+ await writeWorkspaceFile(workspacePath, relativePath, contents);
3360
+ writtenPaths.push(relativePath);
3361
+ }
3362
+ });
3363
+ return writtenPaths;
3364
+ }
3365
+
3366
+ // src/oneShot.ts
3367
+ var import_promises2 = require("node:fs/promises");
3368
+ var import_node_path3 = __toESM(require("node:path"), 1);
3369
+ var import_packet_workflow2 = __toESM(require_dist(), 1);
3370
+ async function runOneShot(client, accessToken, options) {
3371
+ const workspace = await validateWorkspace(options.workspacePath);
3372
+ if (workspace.dirtyFileCount > 0 && !options.allowDirty) {
3373
+ throw new Error(`Workspace has ${workspace.dirtyFileCount} changed file(s). Commit, stash, or rerun with --allow-dirty before one-shot.`);
3374
+ }
3375
+ await runBootstrap(client, accessToken, {
3376
+ projectId: options.projectId,
3377
+ workspacePath: workspace.workspacePath,
3378
+ ticketIds: options.ticketIds,
3379
+ ticketLimit: options.ticketLimit
3380
+ });
3381
+ const project = await client.loadProject(options.projectId, accessToken);
3382
+ let board = await client.loadBoard(project.id, accessToken);
3383
+ const runId = options.resumeRunId ?? options.runId ?? createRunId();
3384
+ const manifestPath = resolveManifestPath(workspace.workspacePath, runId);
3385
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
3386
+ const manifest = await loadOrCreateManifest(manifestPath, {
3387
+ generator: "swarmcraft-cli",
3388
+ version: 1,
3389
+ runId,
3390
+ generatedAt: startedAt,
3391
+ finishedAt: null,
3392
+ status: "running",
3393
+ project: { id: project.id, title: project.title || project.projectTitle || project.id },
3394
+ workspacePath: workspace.workspacePath,
3395
+ options,
3396
+ tickets: [],
3397
+ durations: {
3398
+ elapsedMs: null,
3399
+ ticketCount: 0,
3400
+ totalTicketMs: 0,
3401
+ totalStageMs: 0,
3402
+ averageTicketMs: null,
3403
+ averageStageMs: null
3404
+ }
3405
+ });
3406
+ await persistManifest(manifestPath, manifest);
3407
+ let agentRequests = manifest.tickets.flatMap((ticket) => ticket.stages).length;
3408
+ const completedTicketIds = new Set(
3409
+ manifest.tickets.filter((ticket) => ["done", "manual-review-required"].includes(ticket.outcome)).map((ticket) => ticket.ticketId)
3410
+ );
3411
+ if (options.resumeRunId) {
3412
+ manifest.tickets = manifest.tickets.filter((ticket) => completedTicketIds.has(ticket.ticketId));
3413
+ await persistManifest(manifestPath, manifest);
3414
+ }
3415
+ for (const selectedTicket of selectTickets(board, options)) {
3416
+ if (completedTicketIds.has(selectedTicket.id)) {
3417
+ continue;
3418
+ }
3419
+ const ticketOutcome = {
3420
+ ticketId: selectedTicket.id,
3421
+ title: selectedTicket.title,
3422
+ packetPath: null,
3423
+ outcome: "running",
3424
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3425
+ finishedAt: null,
3426
+ elapsedMs: null,
3427
+ stages: []
3428
+ };
3429
+ manifest.tickets.push(ticketOutcome);
3430
+ await persistManifest(manifestPath, manifest);
3431
+ const result = await processTicket({
3432
+ client,
3433
+ accessToken,
3434
+ project,
3435
+ board,
3436
+ ticket: selectedTicket,
3437
+ workspacePath: workspace.workspacePath,
3438
+ options,
3439
+ ticketOutcome,
3440
+ manifestPath,
3441
+ manifest,
3442
+ getAgentRequests: () => agentRequests,
3443
+ incrementAgentRequests: () => {
3444
+ agentRequests += 1;
3445
+ }
3446
+ });
3447
+ board = result.board;
3448
+ ticketOutcome.outcome = result.outcome;
3449
+ ticketOutcome.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
3450
+ ticketOutcome.elapsedMs = (0, import_packet_workflow2.computeElapsedMs)(ticketOutcome.startedAt, ticketOutcome.finishedAt);
3451
+ if (result.outcome === "done" && options.commitPolicy === "done") {
3452
+ ticketOutcome.commitCreated = await gitAddAndCommit(workspace.workspacePath, `Complete ${selectedTicket.id}: ${selectedTicket.title}`);
3453
+ }
3454
+ await persistManifest(manifestPath, manifest);
3455
+ if (result.outcome.startsWith("blocked")) {
3456
+ break;
3457
+ }
3458
+ }
3459
+ manifest.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
3460
+ manifest.status = resolveManifestStatus(manifest);
3461
+ manifest.durations = (0, import_packet_workflow2.summarizeWorkflowRunDurations)(manifest);
3462
+ await persistManifest(manifestPath, manifest);
3463
+ return manifest;
3464
+ }
3465
+ async function processTicket(context) {
3466
+ let currentBoard = context.board;
3467
+ let currentTicket = requireTicket(currentBoard, context.ticket.id);
3468
+ if (currentTicket.workflowState === "todo") {
3469
+ currentBoard = await moveTicket(context.client, context.accessToken, context.project.id, currentTicket, "doing");
3470
+ currentTicket = requireTicket(currentBoard, context.ticket.id);
3471
+ }
3472
+ const packetPath = (0, import_packet_workflow2.resolvePacketFilePath)(context.project, currentTicket, currentTicket.packetLink);
3473
+ context.ticketOutcome.packetPath = packetPath;
3474
+ await refreshPacketMetadata(context.workspacePath, packetPath, currentTicket);
3475
+ if (currentTicket.workflowState !== "checking" && currentTicket.workflowState !== "reviewing") {
3476
+ const doResult = await runStageAndSync({ ...context, board: currentBoard, ticket: currentTicket, packetPath, stage: "do" });
3477
+ currentBoard = doResult.board;
3478
+ currentTicket = doResult.ticket;
3479
+ }
3480
+ if (!context.options.checking) {
3481
+ return moveAfterAcceptedChecking(context, currentBoard, currentTicket, packetPath);
3482
+ }
3483
+ if (currentTicket.workflowState === "doing") {
3484
+ currentBoard = await moveTicket(context.client, context.accessToken, context.project.id, currentTicket, "checking");
3485
+ currentTicket = requireTicket(currentBoard, currentTicket.id);
3486
+ await refreshPacketMetadata(context.workspacePath, packetPath, currentTicket);
3487
+ }
3488
+ for (let attempt = 1; attempt <= context.options.maxCheckingAttempts; attempt += 1) {
3489
+ const checkResult = await runStageAndSync({ ...context, board: currentBoard, ticket: currentTicket, packetPath, stage: "check" });
3490
+ currentBoard = checkResult.board;
3491
+ currentTicket = checkResult.ticket;
3492
+ if (currentTicket.workflowState === "doing") {
3493
+ if (attempt >= context.options.maxCheckingAttempts) {
3494
+ return { board: currentBoard, ticket: currentTicket, outcome: "blocked-checking-retries-exhausted" };
3495
+ }
3496
+ currentBoard = await moveTicket(context.client, context.accessToken, context.project.id, currentTicket, "checking");
3497
+ currentTicket = requireTicket(currentBoard, currentTicket.id);
3498
+ await refreshPacketMetadata(context.workspacePath, packetPath, currentTicket);
3499
+ continue;
3500
+ }
3501
+ const accepted = currentTicket.workflowState === "reviewing" || currentTicket.workflowState === "done" || (0, import_packet_workflow2.allChecklistItemsComplete)(currentTicket, "checking");
3502
+ if (accepted) {
3503
+ return moveAfterAcceptedChecking(context, currentBoard, currentTicket, packetPath);
3504
+ }
3505
+ }
3506
+ return { board: currentBoard, ticket: currentTicket, outcome: "blocked-checking-unresolved" };
3507
+ }
3508
+ async function runStageAndSync(context) {
3509
+ if (context.options.maxAgentRequests !== null && context.getAgentRequests() >= context.options.maxAgentRequests) {
3510
+ throw new Error(`Agent request budget exhausted before ${context.stage} for ${context.ticket.title}.`);
3511
+ }
3512
+ const stageCommand = (0, import_packet_workflow2.buildPacketStageCommand)({
3513
+ workflowState: context.stage === "do" ? "doing" : "checking",
3514
+ relativePacketFilePath: context.packetPath,
3515
+ agentProvider: context.options.agentProvider === "custom" ? "copilot" : context.options.agentProvider
3516
+ });
3517
+ if (!stageCommand) {
3518
+ throw new Error(`No stage command exists for ${context.stage}.`);
3519
+ }
3520
+ const command = renderAgentCommand(resolveAgentCommandTemplate(context.options), {
3521
+ command: stageCommand,
3522
+ stage: context.stage,
3523
+ ticket: context.packetPath,
3524
+ workspace: context.workspacePath
3525
+ });
3526
+ const stageOutcome = {
3527
+ stage: context.stage,
3528
+ command,
3529
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3530
+ finishedAt: null,
3531
+ elapsedMs: null,
3532
+ exitCode: null,
3533
+ result: "pending",
3534
+ laneBefore: context.ticket.workflowState,
3535
+ laneAfter: null,
3536
+ syncedChanges: 0,
3537
+ costUsd: null
3538
+ };
3539
+ context.ticketOutcome.stages.push(stageOutcome);
3540
+ await persistManifest(context.manifestPath, context.manifest);
3541
+ context.incrementAgentRequests();
3542
+ const costOutputPath = import_node_path3.default.join(import_node_path3.default.dirname(context.manifestPath), "agent-cost", `${String(context.getAgentRequests() + 1).padStart(4, "0")}-${context.stage}.json`);
3543
+ await (0, import_promises2.mkdir)(import_node_path3.default.dirname(costOutputPath), { recursive: true });
3544
+ const execution = await runCommand(command, context.workspacePath, await buildAgentEnvironment(context.options, {
3545
+ SWARMCRAFT_STAGE: context.stage,
3546
+ SWARMCRAFT_PACKET: context.packetPath,
3547
+ SWARMCRAFT_WORKSPACE: context.workspacePath,
3548
+ SWARMCRAFT_AGENT_PROVIDER: context.options.agentProvider,
3549
+ SWARMCRAFT_AGENT_COST_OUTPUT: costOutputPath
3550
+ }));
3551
+ stageOutcome.exitCode = execution.exitCode;
3552
+ if (execution.exitCode !== 0) {
3553
+ stageOutcome.result = "failed";
3554
+ stageOutcome.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
3555
+ stageOutcome.elapsedMs = (0, import_packet_workflow2.computeElapsedMs)(stageOutcome.startedAt, stageOutcome.finishedAt);
3556
+ await persistManifest(context.manifestPath, context.manifest);
3557
+ throw new Error(`Agent command failed during ${context.stage}: ${execution.stderr || execution.stdout || command}`);
3558
+ }
3559
+ const syncResult = await syncPacketFile({
3560
+ client: context.client,
3561
+ accessToken: context.accessToken,
3562
+ project: context.project,
3563
+ board: context.board,
3564
+ ticket: context.ticket,
3565
+ workspacePath: context.workspacePath,
3566
+ relativePacketPath: context.packetPath
3567
+ });
3568
+ stageOutcome.result = "synced";
3569
+ stageOutcome.costUsd = await readStageCostUsd(costOutputPath);
3570
+ if (context.options.requireCostTelemetry && stageOutcome.costUsd === null) {
3571
+ throw new Error("Agent spend budget cannot be verified because cost telemetry was not written.");
3572
+ }
3573
+ const knownSpendUsd = sumStageCostUsd(context.manifest);
3574
+ if (context.options.maxAgentSpendUsd !== null && knownSpendUsd > context.options.maxAgentSpendUsd) {
3575
+ throw new Error(`Agent spend budget exceeded: $${knownSpendUsd.toFixed(4)} > $${context.options.maxAgentSpendUsd.toFixed(4)}.`);
3576
+ }
3577
+ stageOutcome.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
3578
+ stageOutcome.elapsedMs = (0, import_packet_workflow2.computeElapsedMs)(stageOutcome.startedAt, stageOutcome.finishedAt);
3579
+ stageOutcome.laneAfter = syncResult.ticket.workflowState;
3580
+ stageOutcome.syncedChanges = syncResult.syncedChanges;
3581
+ await persistManifest(context.manifestPath, context.manifest);
3582
+ return { board: syncResult.board, ticket: syncResult.ticket };
3583
+ }
3584
+ async function syncPacketFile(input2) {
3585
+ const syncedAt = (/* @__PURE__ */ new Date()).toISOString();
3586
+ const fileContents = await readWorkspaceFile(input2.workspacePath, input2.relativePacketPath);
3587
+ const parsedPacket = (0, import_packet_workflow2.parsePacketFile)(fileContents);
3588
+ if (parsedPacket.frontmatter.projectId !== input2.project.id || parsedPacket.frontmatter.ticketId !== input2.ticket.id) {
3589
+ throw new Error(`Packet ${input2.relativePacketPath} does not belong to ticket ${input2.ticket.id}.`);
3590
+ }
3591
+ if (parsedPacket.frontmatter.syncRevision !== input2.ticket.revision) {
3592
+ throw new Error(`Packet ${input2.relativePacketPath} is stale; expected revision ${input2.ticket.revision}.`);
3593
+ }
3594
+ const shapeProblem = (0, import_packet_workflow2.findChecklistShapeProblem)(input2.ticket.checklistItems, parsedPacket.sections.checklists);
3595
+ if (shapeProblem) {
3596
+ throw new Error(shapeProblem.message);
3597
+ }
3598
+ let currentBoard = input2.board;
3599
+ let currentTicket = input2.ticket;
3600
+ let syncedChanges = 0;
3601
+ for (const checklistStage of import_packet_workflow2.CHECKLIST_STAGES) {
3602
+ const currentItems = (0, import_packet_workflow2.listChecklistItemsForStage)(currentTicket.checklistItems, checklistStage);
3603
+ const parsedItems = parsedPacket.sections.checklists[checklistStage];
3604
+ for (const [index, parsedItem] of parsedItems.entries()) {
3605
+ const currentItem = currentItems[index];
3606
+ if (currentItem.completed === parsedItem.completed) {
3607
+ continue;
3608
+ }
3609
+ currentBoard = await input2.client.updateChecklistItem(input2.project.id, currentTicket.id, currentItem.id, {
3610
+ completed: parsedItem.completed,
3611
+ expectedRevision: currentItem.revision
3612
+ }, input2.accessToken);
3613
+ currentTicket = requireTicket(currentBoard, currentTicket.id);
3614
+ syncedChanges += 1;
3615
+ }
3616
+ }
3617
+ const desiredNotes = (0, import_packet_workflow2.composeTicketNotes)(parsedPacket.sections.notes, parsedPacket.sections.agentUpdate);
3618
+ if ((currentTicket.notes ?? null) !== desiredNotes) {
3619
+ currentBoard = await input2.client.updateTicketNotes(input2.project.id, currentTicket.id, {
3620
+ notes: desiredNotes,
3621
+ expectedRevision: currentTicket.revision
3622
+ }, input2.accessToken);
3623
+ currentTicket = requireTicket(currentBoard, currentTicket.id);
3624
+ syncedChanges += 1;
3625
+ }
3626
+ if (parsedPacket.frontmatter.lane !== currentTicket.workflowState) {
3627
+ currentBoard = await moveTicket(input2.client, input2.accessToken, input2.project.id, currentTicket, parsedPacket.frontmatter.lane);
3628
+ currentTicket = requireTicket(currentBoard, currentTicket.id);
3629
+ syncedChanges += 1;
3630
+ }
3631
+ await refreshPacketMetadata(input2.workspacePath, input2.relativePacketPath, currentTicket, syncedAt);
3632
+ return { board: currentBoard, ticket: currentTicket, syncedChanges };
3633
+ }
3634
+ async function buildAgentEnvironment(options, stageEnv) {
3635
+ const env = {
3636
+ PATH: process.env.PATH ?? "",
3637
+ HOME: process.env.HOME,
3638
+ SHELL: process.env.SHELL,
3639
+ TERM: process.env.TERM,
3640
+ ...stageEnv
3641
+ };
3642
+ if (!options.agentApiKeyEnvName) {
3643
+ return env;
3644
+ }
3645
+ const envFileValues = options.agentEnvFilePath ? await readEnvFile(options.agentEnvFilePath) : {};
3646
+ const credentialValue = envFileValues[options.agentApiKeyEnvName] ?? process.env[options.agentApiKeyEnvName];
3647
+ if (!credentialValue) {
3648
+ throw new Error(`Missing approved agent credential ${options.agentApiKeyEnvName}.`);
3649
+ }
3650
+ env[options.agentApiKeyEnvName] = credentialValue;
3651
+ return env;
3652
+ }
3653
+ async function readEnvFile(envFilePath) {
3654
+ const contents = await (0, import_promises2.readFile)(envFilePath, "utf8");
3655
+ return Object.fromEntries(
3656
+ contents.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => {
3657
+ const separatorIndex = line.indexOf("=");
3658
+ if (separatorIndex < 0) {
3659
+ return null;
3660
+ }
3661
+ return [line.slice(0, separatorIndex).trim(), line.slice(separatorIndex + 1).trim().replace(/^"|"$/g, "")];
3662
+ }).filter((entry) => entry !== null)
3663
+ );
3664
+ }
3665
+ async function readStageCostUsd(costOutputPath) {
3666
+ try {
3667
+ const payload = JSON.parse(await (0, import_promises2.readFile)(costOutputPath, "utf8"));
3668
+ const value = typeof payload.totalCostUsd === "number" ? payload.totalCostUsd : payload.costUsd;
3669
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
3670
+ } catch {
3671
+ return null;
3672
+ }
3673
+ }
3674
+ function sumStageCostUsd(manifest) {
3675
+ return manifest.tickets.flatMap((ticket) => ticket.stages).reduce((total, stage) => total + Number(stage.costUsd ?? 0), 0);
3676
+ }
3677
+ async function moveAfterAcceptedChecking(context, board, ticket, packetPath) {
3678
+ if (context.options.donePolicy === "auto") {
3679
+ const doneBoard = ticket.workflowState === "done" ? board : await moveTicket(context.client, context.accessToken, context.project.id, ticket, "done");
3680
+ const doneTicket = requireTicket(doneBoard, ticket.id);
3681
+ await refreshPacketMetadata(context.workspacePath, packetPath, doneTicket);
3682
+ return { board: doneBoard, ticket: doneTicket, outcome: "done" };
3683
+ }
3684
+ const reviewBoard = ticket.workflowState === "reviewing" ? board : await moveTicket(context.client, context.accessToken, context.project.id, ticket, "reviewing");
3685
+ const reviewTicket = requireTicket(reviewBoard, ticket.id);
3686
+ await refreshPacketMetadata(context.workspacePath, packetPath, reviewTicket);
3687
+ return { board: reviewBoard, ticket: reviewTicket, outcome: "manual-review-required" };
3688
+ }
3689
+ async function moveTicket(client, accessToken, projectId, ticket, workflowState) {
3690
+ return client.moveTicket(projectId, ticket.id, {
3691
+ workflowState,
3692
+ targetIndex: null,
3693
+ expectedRevision: ticket.revision
3694
+ }, accessToken);
3695
+ }
3696
+ async function refreshPacketMetadata(workspacePath, relativePacketPath, ticket, syncedAt = (/* @__PURE__ */ new Date()).toISOString()) {
3697
+ const contents = await readWorkspaceFile(workspacePath, relativePacketPath);
3698
+ await writeWorkspaceFile(workspacePath, relativePacketPath, (0, import_packet_workflow2.rewritePacketFileMetadata)(contents, {
3699
+ lane: ticket.workflowState,
3700
+ syncRevision: ticket.revision,
3701
+ lastSyncedAt: syncedAt
3702
+ }));
3703
+ }
3704
+ function resolveAgentCommandTemplate(options) {
3705
+ if (options.agentCommand) {
3706
+ return options.agentCommand;
3707
+ }
3708
+ const providerDefault = (0, import_packet_workflow2.resolveExternalAgentProviderDefault)(options.agentProvider);
3709
+ if (providerDefault) {
3710
+ return providerDefault.command;
3711
+ }
3712
+ throw new Error("--agent-command is required when --agent-provider custom is used.");
3713
+ }
3714
+ function renderAgentCommand(commandTemplate, context) {
3715
+ const replacements = {
3716
+ command: shellQuote(context.command),
3717
+ stage: shellQuote(context.stage),
3718
+ ticket: shellQuote(context.ticket),
3719
+ workspace: shellQuote(context.workspace)
3720
+ };
3721
+ const rendered = commandTemplate.replace(/\{(command|stage|ticket|workspace)\}/g, (_, key) => replacements[key]);
3722
+ return rendered === commandTemplate ? `${commandTemplate} ${shellQuote(context.command)}` : rendered;
3723
+ }
3724
+ function shellQuote(value) {
3725
+ return `'${String(value).replace(/'/g, "'\\''")}'`;
3726
+ }
3727
+ function selectTickets(board, options) {
3728
+ const requestedTicketIds = new Set(options.ticketIds);
3729
+ const tickets = board.columns.flatMap((column) => column.tickets).filter((ticket) => ticket.workflowState !== "done").filter((ticket) => requestedTicketIds.size === 0 || requestedTicketIds.has(ticket.id)).sort((left, right) => left.recommendedOrder - right.recommendedOrder || left.columnOrder - right.columnOrder);
3730
+ return options.ticketLimit === "all" ? tickets : tickets.slice(0, options.ticketLimit);
3731
+ }
3732
+ function requireTicket(board, ticketId) {
3733
+ const ticket = board.columns.flatMap((column) => column.tickets).find((candidate) => candidate.id === ticketId);
3734
+ if (!ticket) {
3735
+ throw new Error(`Ticket ${ticketId} was not present in the updated board payload.`);
3736
+ }
3737
+ return ticket;
3738
+ }
3739
+ function resolveManifestStatus(manifest) {
3740
+ if (manifest.tickets.some((ticket) => ticket.outcome.startsWith("blocked"))) {
3741
+ return "blocked";
3742
+ }
3743
+ if (manifest.tickets.some((ticket) => ticket.outcome === "manual-review-required")) {
3744
+ return "manual-review-required";
3745
+ }
3746
+ return "success";
3747
+ }
3748
+ async function loadOrCreateManifest(manifestPath, fallback) {
3749
+ try {
3750
+ return JSON.parse(await (0, import_promises2.readFile)(manifestPath, "utf8"));
3751
+ } catch (error) {
3752
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
3753
+ return fallback;
3754
+ }
3755
+ throw error;
3756
+ }
3757
+ }
3758
+ async function persistManifest(manifestPath, manifest) {
3759
+ await (0, import_promises2.mkdir)(import_node_path3.default.dirname(manifestPath), { recursive: true });
3760
+ await (0, import_promises2.writeFile)(manifestPath, `${JSON.stringify(manifest, null, 2)}
3761
+ `, "utf8");
3762
+ }
3763
+ function resolveManifestPath(workspacePath, runId) {
3764
+ return import_node_path3.default.join(workspacePath, ".swarmcraft", "runs", runId, "manifest.json");
3765
+ }
3766
+ function createRunId() {
3767
+ return `run-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
3768
+ }
3769
+ function describeAgentPolicy(options) {
3770
+ return {
3771
+ sandboxMode: (0, import_packet_workflow2.resolveExternalAgentSandboxMode)({
3772
+ agentMode: "externalCommand",
3773
+ agentProvider: options.agentProvider,
3774
+ agentCommand: options.agentCommand ?? (0, import_packet_workflow2.resolveExternalAgentProviderDefault)(options.agentProvider)?.command ?? null,
3775
+ agentCommandSource: options.agentCommand ? "cli" : "provider-default"
3776
+ }),
3777
+ approvalPosture: (0, import_packet_workflow2.resolveExternalAgentApprovalPosture)({
3778
+ agentMode: "externalCommand",
3779
+ agentProvider: options.agentProvider,
3780
+ agentCommand: options.agentCommand ?? (0, import_packet_workflow2.resolveExternalAgentProviderDefault)(options.agentProvider)?.command ?? null,
3781
+ agentCommandSource: options.agentCommand ? "cli" : "provider-default"
3782
+ })
3783
+ };
3784
+ }
3785
+
3786
+ // src/sessionStore.ts
3787
+ var import_promises3 = require("node:fs/promises");
3788
+ var import_node_os = __toESM(require("node:os"), 1);
3789
+ var import_node_path4 = __toESM(require("node:path"), 1);
3790
+ function resolveSessionPath() {
3791
+ return import_node_path4.default.join(import_node_os.default.homedir(), ".swarmcraft", "cli-session.json");
3792
+ }
3793
+ async function readStoredSession() {
3794
+ try {
3795
+ return JSON.parse(await (0, import_promises3.readFile)(resolveSessionPath(), "utf8"));
3796
+ } catch (error) {
3797
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
3798
+ return null;
3799
+ }
3800
+ throw error;
3801
+ }
3802
+ }
3803
+ async function writeStoredSession(session) {
3804
+ const sessionPath = resolveSessionPath();
3805
+ await (0, import_promises3.mkdir)(import_node_path4.default.dirname(sessionPath), { recursive: true, mode: 448 });
3806
+ await (0, import_promises3.writeFile)(sessionPath, `${JSON.stringify(session, null, 2)}
3807
+ `, { mode: 384 });
3808
+ await (0, import_promises3.chmod)(sessionPath, 384);
3809
+ }
3810
+ function toStoredSession(apiBaseUrl, tokenResponse) {
3811
+ return {
3812
+ ...tokenResponse,
3813
+ apiBaseUrl,
3814
+ savedAt: (/* @__PURE__ */ new Date()).toISOString()
3815
+ };
3816
+ }
3817
+ function sessionExpiresSoon(session) {
3818
+ const expiresAt = Date.parse(session.accessTokenExpiresAt);
3819
+ if (!Number.isFinite(expiresAt)) {
3820
+ return true;
3821
+ }
3822
+ return expiresAt - Date.now() < 6e4;
3823
+ }
3824
+
3825
+ // src/main.ts
3826
+ var VERSION = "0.1.0";
3827
+ var DEFAULT_API_BASE_URL = "https://swarmcraft.ai/api";
3828
+ var AGENT_PROVIDER_USAGE = import_packet_workflow3.EXTERNAL_AGENT_PROVIDERS.join("|");
3829
+ var COMMANDS = [
3830
+ {
3831
+ name: "auth login",
3832
+ usage: "swarmcraft auth login [--email <email>] [--password <password>] [--mfa-code <code>] [--api-base-url <url>]",
3833
+ summary: "Sign in to SwarmCraft and store a local CLI session.",
3834
+ implemented: true
3835
+ },
3836
+ {
3837
+ name: "projects list",
3838
+ usage: "swarmcraft projects list",
3839
+ summary: "List SwarmCraft projects available to the signed-in user.",
3840
+ implemented: true
3841
+ },
3842
+ {
3843
+ name: "init",
3844
+ usage: "swarmcraft init --project <project-id> --workspace <path> [--ticket <ticket-id>] [--ticket-limit <n|all>]",
3845
+ summary: "Prepare a repository with SwarmCraft packet and agent guidance files.",
3846
+ implemented: true
3847
+ },
3848
+ {
3849
+ name: "one-shot",
3850
+ usage: `swarmcraft one-shot --project <project-id> --workspace <path> --agent-provider ${AGENT_PROVIDER_USAGE} [--run-id <id>] [--done-policy stop|auto] [--commit-policy none|done] [--allow-dirty]`,
3851
+ summary: "Run the project board packet loop with the selected agent provider.",
3852
+ implemented: true
3853
+ },
3854
+ {
3855
+ name: "resume",
3856
+ usage: "swarmcraft resume --run <run-id> --workspace <path>",
3857
+ summary: "Resume a prior CLI run from its recorded manifest.",
3858
+ implemented: true
3859
+ },
3860
+ {
3861
+ name: "status",
3862
+ usage: "swarmcraft status --run <run-id> --workspace <path>",
3863
+ summary: "Show the status of a recorded CLI run.",
3864
+ implemented: true
3865
+ },
3866
+ {
3867
+ name: "doctor",
3868
+ usage: "swarmcraft doctor [--workspace <path>] [--agent-provider codex|copilot|custom]",
3869
+ summary: "Check local auth, API, git, workspace, runtime, and agent prerequisites.",
3870
+ implemented: true
3871
+ },
3872
+ {
3873
+ name: "support-bundle",
3874
+ usage: "swarmcraft support-bundle --run <run-id> --workspace <path>",
3875
+ summary: "Collect a redacted support bundle for a CLI run.",
3876
+ implemented: true
3877
+ }
3878
+ ];
3879
+ async function main(argv) {
3880
+ const parsed = parseArgs(argv);
3881
+ const command = findCommand(parsed.positionals);
3882
+ if (parsed.positionals.length === 0 || hasFlag(parsed, "help") || hasFlag(parsed, "h")) {
3883
+ if (command) {
3884
+ printCommandHelp(command);
3885
+ } else {
3886
+ printGeneralHelp();
3887
+ }
3888
+ return 0;
3889
+ }
3890
+ if (hasFlag(parsed, "version") || hasFlag(parsed, "v")) {
3891
+ console.log(VERSION);
3892
+ return 0;
3893
+ }
3894
+ if (parsed.positionals[0] === "help") {
3895
+ const helpCommand = findCommand(parsed.positionals.slice(1));
3896
+ if (helpCommand) {
3897
+ printCommandHelp(helpCommand);
3898
+ } else {
3899
+ printGeneralHelp();
3900
+ }
3901
+ return 0;
3902
+ }
3903
+ if (!command) {
3904
+ throw new Error(`Unknown command: ${parsed.positionals.join(" ")}
3905
+ Run "swarmcraft --help" for available commands.`);
3906
+ }
3907
+ switch (command.name) {
3908
+ case "auth login":
3909
+ await runAuthLogin(parsed);
3910
+ return 0;
3911
+ case "projects list":
3912
+ await runProjectsList(parsed);
3913
+ return 0;
3914
+ case "init":
3915
+ await runInit(parsed);
3916
+ return 0;
3917
+ case "one-shot":
3918
+ await runOneShotCommand(parsed);
3919
+ return 0;
3920
+ case "resume":
3921
+ await runResume(parsed);
3922
+ return 0;
3923
+ case "status":
3924
+ await runStatus(parsed);
3925
+ return 0;
3926
+ case "doctor":
3927
+ await runDoctor(parsed);
3928
+ return 0;
3929
+ case "support-bundle":
3930
+ await runSupportBundle(parsed);
3931
+ return 0;
3932
+ default:
3933
+ throw new Error(`${command.usage}
3934
+
3935
+ ${command.summary}
3936
+
3937
+ This command is planned but not implemented yet.`);
3938
+ }
3939
+ }
3940
+ async function runAuthLogin(parsed) {
3941
+ const apiBaseUrl = getOption(parsed, "api-base-url") ?? process.env.SWARMCRAFT_API_BASE_URL ?? DEFAULT_API_BASE_URL;
3942
+ const email = getOption(parsed, "email") ?? process.env.SWARMCRAFT_EMAIL ?? await promptLine("Email: ");
3943
+ const password = getOption(parsed, "password") ?? process.env.SWARMCRAFT_PASSWORD ?? await promptSecret("Password: ");
3944
+ const client = new SwarmCraftClient(apiBaseUrl);
3945
+ let tokenResponse = await client.login(email, password);
3946
+ if (tokenResponse.user.mfaEnrolled && !tokenResponse.user.mfaVerified) {
3947
+ const mfaCode = getOption(parsed, "mfa-code") ?? process.env.SWARMCRAFT_MFA_CODE;
3948
+ const recoveryCode = getOption(parsed, "recovery-code") ?? process.env.SWARMCRAFT_MFA_RECOVERY_CODE;
3949
+ if (!mfaCode && !recoveryCode) {
3950
+ throw new Error("MFA is required. Rerun with --mfa-code <code> or --recovery-code <code>.");
3951
+ }
3952
+ const mfaResponse = recoveryCode ? await client.mfaRecovery(tokenResponse.accessToken, recoveryCode) : await client.mfaChallenge(tokenResponse.accessToken, mfaCode);
3953
+ tokenResponse = {
3954
+ ...mfaResponse.session,
3955
+ refreshToken: mfaResponse.refreshToken ?? mfaResponse.session.refreshToken
3956
+ };
3957
+ }
3958
+ await writeStoredSession(toStoredSession(apiBaseUrl, tokenResponse));
3959
+ console.log(`Signed in as ${tokenResponse.user.email}.`);
3960
+ }
3961
+ async function runProjectsList(parsed) {
3962
+ const { client, session } = await resolveAuthenticatedClient(parsed);
3963
+ const projects = await client.listProjects(session.accessToken);
3964
+ if (projects.length === 0) {
3965
+ console.log("No projects available.");
3966
+ return;
3967
+ }
3968
+ for (const project of projects) {
3969
+ const done = project.boardSummary?.doneCount ?? 0;
3970
+ const total = project.boardSummary?.totalCount ?? 0;
3971
+ console.log(`${project.id} ${project.boardState} ${done}/${total} done ${project.title}`);
3972
+ }
3973
+ }
3974
+ async function runInit(parsed) {
3975
+ const projectId = requireOption(parsed, "project");
3976
+ const workspacePath = requireOption(parsed, "workspace");
3977
+ const ticketLimit = parseTicketLimit(getOption(parsed, "ticket-limit") ?? "all");
3978
+ const { client, session } = await resolveAuthenticatedClient(parsed);
3979
+ const summary = await runBootstrap(client, session.accessToken, {
3980
+ projectId,
3981
+ workspacePath,
3982
+ ticketIds: getOptions(parsed, "ticket"),
3983
+ ticketLimit
3984
+ });
3985
+ printBootstrapSummary(summary);
3986
+ }
3987
+ async function runOneShotCommand(parsed) {
3988
+ const { client, session } = await resolveAuthenticatedClient(parsed);
3989
+ const options = parseOneShotOptions(parsed);
3990
+ const policy = describeAgentPolicy(options);
3991
+ console.log(`Agent provider: ${options.agentProvider}`);
3992
+ console.log(`Agent sandbox: ${policy.sandboxMode ?? "custom"}`);
3993
+ console.log(`Agent approval posture: ${policy.approvalPosture ?? "custom"}`);
3994
+ const onSigint = () => {
3995
+ console.error("Cancellation requested. The run manifest is written incrementally; use `swarmcraft resume --run <run-id> --workspace <path>` after the current process exits.");
3996
+ process.exit(130);
3997
+ };
3998
+ process.once("SIGINT", onSigint);
3999
+ try {
4000
+ const manifest = await runOneShot(client, session.accessToken, options);
4001
+ printRunSummary(manifest);
4002
+ } finally {
4003
+ process.off("SIGINT", onSigint);
4004
+ }
4005
+ }
4006
+ async function runResume(parsed) {
4007
+ const runId = requireOption(parsed, "run");
4008
+ const workspacePath = requireOption(parsed, "workspace");
4009
+ const manifest = await readRunManifest(workspacePath, runId);
4010
+ const { client, session } = await resolveAuthenticatedClient(parsed);
4011
+ const resumed = await runOneShot(client, session.accessToken, {
4012
+ ...manifest.options,
4013
+ workspacePath,
4014
+ resumeRunId: runId
4015
+ });
4016
+ printRunSummary(resumed);
4017
+ }
4018
+ async function runStatus(parsed) {
4019
+ const runId = requireOption(parsed, "run");
4020
+ const workspacePath = requireOption(parsed, "workspace");
4021
+ printRunSummary(await readRunManifest(workspacePath, runId));
4022
+ }
4023
+ async function runDoctor(parsed) {
4024
+ console.log(`Node: ${process.version}`);
4025
+ const session = await readStoredSession();
4026
+ console.log(`Session: ${session ? `signed in as ${session.user.email}` : "missing"}`);
4027
+ if (session) {
4028
+ try {
4029
+ const client = new SwarmCraftClient(getOption(parsed, "api-base-url") ?? session.apiBaseUrl);
4030
+ await client.listProjects(session.accessToken);
4031
+ console.log("API: reachable");
4032
+ } catch (error) {
4033
+ console.log(`API: ${error instanceof Error ? error.message : String(error)}`);
4034
+ }
4035
+ }
4036
+ const workspacePath = getOption(parsed, "workspace");
4037
+ if (workspacePath) {
4038
+ try {
4039
+ const workspace = await validateWorkspace(workspacePath);
4040
+ console.log(`Workspace: ${workspace.workspacePath}`);
4041
+ console.log(`Git root: ${workspace.gitRoot}`);
4042
+ console.log(`Changed files: ${workspace.dirtyFileCount}`);
4043
+ } catch (error) {
4044
+ console.log(`Workspace: ${error instanceof Error ? error.message : String(error)}`);
4045
+ }
4046
+ }
4047
+ const provider = getOption(parsed, "agent-provider");
4048
+ if (provider && provider !== "custom") {
4049
+ const commandName = provider === "codex" ? "codex" : "copilot";
4050
+ const result = await runCommand(`command -v ${commandName}`, process.cwd());
4051
+ console.log(`${commandName}: ${result.exitCode === 0 ? result.stdout.trim() : "not found"}`);
4052
+ }
4053
+ }
4054
+ async function runSupportBundle(parsed) {
4055
+ const runId = requireOption(parsed, "run");
4056
+ const workspacePath = import_node_path5.default.resolve(requireOption(parsed, "workspace"));
4057
+ const manifestPath = resolveManifestPath(workspacePath, runId);
4058
+ const manifest = JSON.parse(await (0, import_promises4.readFile)(manifestPath, "utf8"));
4059
+ const bundleDir = import_node_path5.default.join(workspacePath, ".swarmcraft", "runs", runId, "support-bundle");
4060
+ await (0, import_promises4.mkdir)(bundleDir, { recursive: true });
4061
+ await (0, import_promises4.writeFile)(import_node_path5.default.join(bundleDir, "manifest.redacted.json"), `${JSON.stringify(redact(manifest), null, 2)}
4062
+ `, "utf8");
4063
+ await (0, import_promises4.writeFile)(import_node_path5.default.join(bundleDir, "summary.json"), `${JSON.stringify({
4064
+ runId,
4065
+ manifestPath,
4066
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4067
+ node: process.version
4068
+ }, null, 2)}
4069
+ `, "utf8");
4070
+ console.log(`Support bundle written: ${bundleDir}`);
4071
+ }
4072
+ async function resolveAuthenticatedClient(parsed) {
4073
+ let session = await readStoredSession();
4074
+ if (!session) {
4075
+ throw new Error("No SwarmCraft CLI session found. Run `swarmcraft auth login` first.");
4076
+ }
4077
+ const apiBaseUrl = getOption(parsed, "api-base-url") ?? process.env.SWARMCRAFT_API_BASE_URL ?? session.apiBaseUrl;
4078
+ const client = new SwarmCraftClient(apiBaseUrl);
4079
+ if (sessionExpiresSoon(session)) {
4080
+ if (!session.refreshToken) {
4081
+ throw new Error("Stored SwarmCraft session has expired. Run `swarmcraft auth login` again.");
4082
+ }
4083
+ const refreshed = await client.refresh(session.refreshToken);
4084
+ session = toStoredSession(apiBaseUrl, {
4085
+ ...refreshed,
4086
+ refreshToken: refreshed.refreshToken ?? session.refreshToken
4087
+ });
4088
+ await writeStoredSession(session);
4089
+ }
4090
+ return { client, session };
4091
+ }
4092
+ function printBootstrapSummary(summary) {
4093
+ console.log(`Bootstrapped ${summary.projectTitle}`);
4094
+ console.log(`Workspace: ${summary.workspacePath}`);
4095
+ if (summary.dirtyFileCount > 0) {
4096
+ console.log(`Workspace had ${summary.dirtyFileCount} pre-existing changed file(s).`);
4097
+ }
4098
+ console.log(`Seed files written or updated: ${summary.seedFilesWritten.length}`);
4099
+ console.log(`Packet files created: ${summary.packetFilesCreated.length}`);
4100
+ console.log(`Packet files refreshed: ${summary.packetFilesRefreshed.length}`);
4101
+ console.log(`Packet links upserted: ${summary.linkedPackets.length}`);
4102
+ if (summary.skippedTickets.length > 0) {
4103
+ console.log("Skipped tickets:");
4104
+ for (const skipped of summary.skippedTickets) {
4105
+ console.log(` - ${skipped.ticketId} ${skipped.title}: ${skipped.reason}`);
4106
+ }
4107
+ }
4108
+ console.log("Next:");
4109
+ for (const nextCommand of summary.nextCommands) {
4110
+ console.log(` ${nextCommand}`);
4111
+ }
4112
+ }
4113
+ function printRunSummary(manifest) {
4114
+ console.log(`Run: ${manifest.runId}`);
4115
+ console.log(`Status: ${manifest.status}`);
4116
+ console.log(`Workspace: ${manifest.workspacePath}`);
4117
+ console.log(`Tickets: ${manifest.tickets.length}`);
4118
+ for (const ticket of manifest.tickets) {
4119
+ console.log(` - ${ticket.outcome}: ${ticket.title} (${ticket.stages.length} stage(s))`);
4120
+ }
4121
+ if (manifest.durations?.elapsedMs !== null && manifest.durations?.elapsedMs !== void 0) {
4122
+ console.log(`Elapsed: ${Math.round(manifest.durations.elapsedMs / 1e3)}s`);
4123
+ }
4124
+ }
4125
+ function parseOneShotOptions(parsed) {
4126
+ const agentProvider = (0, import_packet_workflow3.parseExternalAgentProvider)(requireOption(parsed, "agent-provider"));
4127
+ const donePolicy = parseChoice(getOption(parsed, "done-policy") ?? "stop", ["stop", "auto"], "--done-policy");
4128
+ const commitPolicy = parseChoice(getOption(parsed, "commit-policy") ?? "none", ["none", "done"], "--commit-policy");
4129
+ return {
4130
+ projectId: requireOption(parsed, "project"),
4131
+ workspacePath: requireOption(parsed, "workspace"),
4132
+ agentProvider,
4133
+ agentCommand: getOption(parsed, "agent-command") ?? process.env.SWARMCRAFT_AGENT_COMMAND ?? null,
4134
+ checking: parseOnOff(getOption(parsed, "checking") ?? "on", "--checking"),
4135
+ maxCheckingAttempts: parsePositiveInteger(getOption(parsed, "max-checking-attempts") ?? "2", "--max-checking-attempts"),
4136
+ donePolicy,
4137
+ commitPolicy,
4138
+ maxAgentRequests: getOption(parsed, "max-agent-requests") ? parsePositiveInteger(getOption(parsed, "max-agent-requests"), "--max-agent-requests") : null,
4139
+ maxAgentSpendUsd: getOption(parsed, "max-agent-spend-usd") ? parseNonNegativeNumber(getOption(parsed, "max-agent-spend-usd"), "--max-agent-spend-usd") : null,
4140
+ requireCostTelemetry: hasFlag(parsed, "require-cost-telemetry"),
4141
+ allowDirty: hasFlag(parsed, "allow-dirty"),
4142
+ agentEnvFilePath: getOption(parsed, "agent-env-file") ?? null,
4143
+ agentApiKeyEnvName: getOption(parsed, "agent-api-key-env-name") ?? null,
4144
+ ticketIds: getOptions(parsed, "ticket"),
4145
+ ticketLimit: parseTicketLimit(getOption(parsed, "ticket-limit") ?? "all"),
4146
+ runId: parseRunId(getOption(parsed, "run-id"))
4147
+ };
4148
+ }
4149
+ async function readRunManifest(workspacePath, runId) {
4150
+ return JSON.parse(await (0, import_promises4.readFile)(resolveManifestPath(import_node_path5.default.resolve(workspacePath), runId), "utf8"));
4151
+ }
4152
+ function parseArgs(argv) {
4153
+ const positionals = [];
4154
+ const options = /* @__PURE__ */ new Map();
4155
+ for (let index = 0; index < argv.length; index += 1) {
4156
+ const arg = argv[index];
4157
+ if (!arg.startsWith("-")) {
4158
+ positionals.push(arg);
4159
+ continue;
4160
+ }
4161
+ const normalized = arg.replace(/^-+/, "");
4162
+ if (normalized.includes("=")) {
4163
+ const [key, ...valueParts] = normalized.split("=");
4164
+ addOption(options, key, valueParts.join("="));
4165
+ continue;
4166
+ }
4167
+ const next = argv[index + 1];
4168
+ if (!next || next.startsWith("-")) {
4169
+ addOption(options, normalized, "true");
4170
+ continue;
4171
+ }
4172
+ addOption(options, normalized, next);
4173
+ index += 1;
4174
+ }
4175
+ return { positionals, options };
4176
+ }
4177
+ function findCommand(positionals) {
4178
+ if (positionals.length === 0) {
4179
+ return void 0;
4180
+ }
4181
+ const commandKey = positionals[0] === "auth" || positionals[0] === "projects" ? positionals.slice(0, 2).join(" ") : positionals[0];
4182
+ return COMMANDS.find((command) => command.name === commandKey);
4183
+ }
4184
+ function printGeneralHelp() {
4185
+ console.log(`SwarmCraft CLI ${VERSION}
4186
+
4187
+ Usage:
4188
+ swarmcraft <command> [options]
4189
+
4190
+ Commands:
4191
+ ${COMMANDS.map((command) => ` ${command.usage}
4192
+ ${command.summary}${command.implemented ? "" : " (planned)"}`).join("\n")}
4193
+
4194
+ Options:
4195
+ -h, --help Show help.
4196
+ -v, --version Show version.
4197
+
4198
+ Artifacts:
4199
+ Customer run manifests will live under .swarmcraft/runs/<run-id> in the selected workspace.
4200
+ `);
4201
+ }
4202
+ function printCommandHelp(command) {
4203
+ console.log(`${command.usage}
4204
+
4205
+ ${command.summary}${command.implemented ? "" : "\n\nThis command is planned but not implemented yet."}
4206
+ `);
4207
+ }
4208
+ function addOption(options, key, value) {
4209
+ const values = options.get(key) ?? [];
4210
+ values.push(value);
4211
+ options.set(key, values);
4212
+ }
4213
+ function hasFlag(parsed, key) {
4214
+ return parsed.options.has(key);
4215
+ }
4216
+ function getOption(parsed, key) {
4217
+ return parsed.options.get(key)?.at(-1);
4218
+ }
4219
+ function getOptions(parsed, key) {
4220
+ return parsed.options.get(key) ?? [];
4221
+ }
4222
+ function requireOption(parsed, key) {
4223
+ const value = getOption(parsed, key);
4224
+ if (!value || value === "true") {
4225
+ throw new Error(`Missing required option --${key}.`);
4226
+ }
4227
+ return value;
4228
+ }
4229
+ function parseTicketLimit(rawValue) {
4230
+ if (rawValue === "all") {
4231
+ return "all";
4232
+ }
4233
+ const parsed = Number.parseInt(rawValue, 10);
4234
+ if (!Number.isInteger(parsed) || parsed < 1) {
4235
+ throw new Error("--ticket-limit must be a positive integer or all.");
4236
+ }
4237
+ return parsed;
4238
+ }
4239
+ function parsePositiveInteger(rawValue, flagName) {
4240
+ const parsed = Number.parseInt(rawValue, 10);
4241
+ if (!Number.isInteger(parsed) || parsed < 1) {
4242
+ throw new Error(`${flagName} must be a positive integer.`);
4243
+ }
4244
+ return parsed;
4245
+ }
4246
+ function parseNonNegativeNumber(rawValue, flagName) {
4247
+ const parsed = Number.parseFloat(rawValue);
4248
+ if (!Number.isFinite(parsed) || parsed < 0) {
4249
+ throw new Error(`${flagName} must be a non-negative number.`);
4250
+ }
4251
+ return parsed;
4252
+ }
4253
+ function parseOnOff(rawValue, flagName) {
4254
+ if (rawValue === "on") {
4255
+ return true;
4256
+ }
4257
+ if (rawValue === "off") {
4258
+ return false;
4259
+ }
4260
+ throw new Error(`${flagName} must be on or off.`);
4261
+ }
4262
+ function parseChoice(rawValue, choices, flagName) {
4263
+ if (choices.includes(rawValue)) {
4264
+ return rawValue;
4265
+ }
4266
+ throw new Error(`${flagName} must be one of ${choices.join(", ")}.`);
4267
+ }
4268
+ function parseRunId(rawValue) {
4269
+ if (!rawValue) {
4270
+ return void 0;
4271
+ }
4272
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,120}$/.test(rawValue)) {
4273
+ throw new Error("--run-id must start with a letter or number and contain only letters, numbers, dots, underscores, or hyphens.");
4274
+ }
4275
+ return rawValue;
4276
+ }
4277
+ function redact(value) {
4278
+ if (Array.isArray(value)) {
4279
+ return value.map(redact);
4280
+ }
4281
+ if (!value || typeof value !== "object") {
4282
+ return value;
4283
+ }
4284
+ return Object.fromEntries(
4285
+ Object.entries(value).map(([key, entry]) => [
4286
+ key,
4287
+ /token|secret|password|api[-_]?key|credential/i.test(key) ? "<redacted>" : redact(entry)
4288
+ ])
4289
+ );
4290
+ }
4291
+ async function promptLine(prompt) {
4292
+ const readline = (0, import_promises5.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
4293
+ try {
4294
+ return (await readline.question(prompt)).trim();
4295
+ } finally {
4296
+ readline.close();
4297
+ }
4298
+ }
4299
+ async function promptSecret(prompt) {
4300
+ return promptLine(prompt);
4301
+ }
4302
+ main(process.argv.slice(2)).then((exitCode) => {
4303
+ process.exitCode = exitCode;
4304
+ }).catch((error) => {
4305
+ if (error instanceof SwarmCraftApiError) {
4306
+ const request = error.requestId ? ` requestId=${error.requestId}` : "";
4307
+ console.error(`${error.code}: ${error.message}${request}`);
4308
+ } else {
4309
+ console.error(error instanceof Error ? error.message : String(error));
4310
+ }
4311
+ process.exitCode = 1;
4312
+ });