@abranjith/spec-lite 0.0.1 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -12,14 +12,255 @@ import inquirer from "inquirer";
12
12
  // src/providers/copilot.ts
13
13
  import path from "path";
14
14
  import fs from "fs-extra";
15
+ var AGENT_HANDOFFS = {
16
+ spec_help: [],
17
+ brainstorm: [
18
+ {
19
+ label: "Create Plan",
20
+ agent: "spec.planner",
21
+ prompt: "Create a detailed technical plan based on the brainstorm above."
22
+ },
23
+ {
24
+ label: "Capture Conventions",
25
+ agent: "spec.memorize",
26
+ prompt: "Bootstrap memory from the project context established in the brainstorm."
27
+ }
28
+ ],
29
+ planner: [
30
+ {
31
+ label: "Break Down Features",
32
+ agent: "spec.feature",
33
+ prompt: "Break the plan into individual feature specification files."
34
+ },
35
+ {
36
+ label: "Design Architecture",
37
+ agent: "spec.architect",
38
+ prompt: "Create a detailed cloud and infrastructure architecture for the plan."
39
+ },
40
+ {
41
+ label: "Capture Conventions",
42
+ agent: "spec.memorize",
43
+ prompt: "Bootstrap memory from the plan's tech stack and conventions."
44
+ }
45
+ ],
46
+ architect: [
47
+ {
48
+ label: "Break Down Features",
49
+ agent: "spec.feature",
50
+ prompt: "Break the plan into individual feature specification files."
51
+ },
52
+ {
53
+ label: "Set Up Infrastructure",
54
+ agent: "spec.devops",
55
+ prompt: "Set up Docker, CI/CD, and deployment infrastructure based on the architecture."
56
+ }
57
+ ],
58
+ feature: [
59
+ {
60
+ label: "Implement Feature",
61
+ agent: "spec.implement",
62
+ prompt: "Implement the feature spec produced above."
63
+ },
64
+ {
65
+ label: "Write Unit Tests",
66
+ agent: "spec.unit_tests",
67
+ prompt: "Write unit tests for the feature spec produced above."
68
+ }
69
+ ],
70
+ implement: [
71
+ {
72
+ label: "Write Unit Tests",
73
+ agent: "spec.unit_tests",
74
+ prompt: "Write comprehensive unit tests for the code just implemented."
75
+ },
76
+ {
77
+ label: "Review Code",
78
+ agent: "spec.code_review",
79
+ prompt: "Review the code just implemented for correctness, architecture, and readability."
80
+ },
81
+ {
82
+ label: "Write Integration Tests",
83
+ agent: "spec.integration_tests",
84
+ prompt: "Write integration test scenarios for the feature just implemented."
85
+ }
86
+ ],
87
+ unit_tests: [
88
+ {
89
+ label: "Review Code",
90
+ agent: "spec.code_review",
91
+ prompt: "Review the implementation and tests for correctness, architecture, and readability."
92
+ },
93
+ {
94
+ label: "Write Integration Tests",
95
+ agent: "spec.integration_tests",
96
+ prompt: "Write integration test scenarios to complement the unit tests."
97
+ }
98
+ ],
99
+ code_review: [
100
+ {
101
+ label: "Fix Issues",
102
+ agent: "spec.fix",
103
+ prompt: "Fix the issues identified in the code review above."
104
+ },
105
+ {
106
+ label: "Security Audit",
107
+ agent: "spec.security_audit",
108
+ prompt: "Run a security audit on the code reviewed above."
109
+ },
110
+ {
111
+ label: "Write Technical Docs",
112
+ agent: "spec.technical_docs",
113
+ prompt: "Write technical documentation for the reviewed code."
114
+ }
115
+ ],
116
+ integration_tests: [
117
+ {
118
+ label: "Security Audit",
119
+ agent: "spec.security_audit",
120
+ prompt: "Run a security audit on the features covered by integration tests."
121
+ },
122
+ {
123
+ label: "Performance Review",
124
+ agent: "spec.performance_review",
125
+ prompt: "Review performance of the features covered by integration tests."
126
+ },
127
+ {
128
+ label: "Write Technical Docs",
129
+ agent: "spec.technical_docs",
130
+ prompt: "Write technical documentation for the features covered by integration tests."
131
+ }
132
+ ],
133
+ performance_review: [
134
+ {
135
+ label: "Fix Critical Issues",
136
+ agent: "spec.fix",
137
+ prompt: "Fix the critical performance issues identified in the review above."
138
+ },
139
+ {
140
+ label: "Security Audit",
141
+ agent: "spec.security_audit",
142
+ prompt: "Run a security audit alongside the performance improvements."
143
+ },
144
+ {
145
+ label: "Write Technical Docs",
146
+ agent: "spec.technical_docs",
147
+ prompt: "Write technical documentation capturing the performance findings and fixes."
148
+ }
149
+ ],
150
+ security_audit: [
151
+ {
152
+ label: "Fix Vulnerabilities",
153
+ agent: "spec.fix",
154
+ prompt: "Fix the vulnerabilities and security issues identified in the audit above."
155
+ },
156
+ {
157
+ label: "Write Technical Docs",
158
+ agent: "spec.technical_docs",
159
+ prompt: "Write technical documentation capturing the security findings and mitigations."
160
+ },
161
+ {
162
+ label: "Update README",
163
+ agent: "spec.readme",
164
+ prompt: "Update the README to reflect the hardened security posture."
165
+ }
166
+ ],
167
+ fix: [
168
+ {
169
+ label: "Review Fix",
170
+ agent: "spec.code_review",
171
+ prompt: "Review the fix applied above for correctness and regressions."
172
+ },
173
+ {
174
+ label: "Write Regression Tests",
175
+ agent: "spec.unit_tests",
176
+ prompt: "Write regression tests to cover the bug fixed above."
177
+ }
178
+ ],
179
+ memorize: [
180
+ {
181
+ label: "Create Plan",
182
+ agent: "spec.planner",
183
+ prompt: "Create a technical plan for the project using the conventions captured in memory."
184
+ },
185
+ {
186
+ label: "Add Feature",
187
+ agent: "spec.feature",
188
+ prompt: "Define a feature specification using the conventions captured in memory."
189
+ }
190
+ ],
191
+ technical_docs: [
192
+ {
193
+ label: "Update README",
194
+ agent: "spec.readme",
195
+ prompt: "Write or update the project README based on the technical docs produced above."
196
+ },
197
+ {
198
+ label: "Set Up DevOps",
199
+ agent: "spec.devops",
200
+ prompt: "Set up deployment infrastructure to complement the documented architecture."
201
+ }
202
+ ],
203
+ readme: [
204
+ {
205
+ label: "Set Up DevOps",
206
+ agent: "spec.devops",
207
+ prompt: "Set up Docker, CI/CD, and deployment infrastructure for this project."
208
+ },
209
+ {
210
+ label: "Security Audit",
211
+ agent: "spec.security_audit",
212
+ prompt: "Run a final security audit before releasing the project."
213
+ }
214
+ ],
215
+ devops: [
216
+ {
217
+ label: "Security Audit",
218
+ agent: "spec.security_audit",
219
+ prompt: "Run a security audit on the infrastructure and deployment configuration."
220
+ },
221
+ {
222
+ label: "Update README",
223
+ agent: "spec.readme",
224
+ prompt: "Update the README with deployment and infrastructure instructions."
225
+ },
226
+ {
227
+ label: "Update Technical Docs",
228
+ agent: "spec.technical_docs",
229
+ prompt: "Update the technical documentation to include the DevOps setup."
230
+ }
231
+ ]
232
+ };
233
+ function buildAgentFrontmatter(meta) {
234
+ const handoffs = AGENT_HANDOFFS[meta.name] ?? [];
235
+ const lines = ["---", `description: ${meta.description}`];
236
+ if (handoffs.length > 0) {
237
+ lines.push("handoffs:");
238
+ for (const h of handoffs) {
239
+ lines.push(` - label: ${h.label}`);
240
+ lines.push(` agent: ${h.agent}`);
241
+ lines.push(` prompt: ${h.prompt}`);
242
+ }
243
+ }
244
+ lines.push("---", "");
245
+ return lines.join("\n");
246
+ }
15
247
  var CopilotProvider = class {
16
248
  name = "GitHub Copilot";
17
249
  alias = "copilot";
18
250
  description = "GitHub Copilot (VS Code, JetBrains, Neovim)";
251
+ /** Primary target: the .agent.md file in .github/agents/ */
19
252
  getTargetPath(promptName) {
20
- return path.join(".github", "copilot", `${promptName}.prompt.md`);
253
+ return path.join(".github", "agents", `spec.${promptName}.agent.md`);
21
254
  }
255
+ /** Transform content into an agent file: YAML frontmatter + prompt body. */
22
256
  transformPrompt(content, meta) {
257
+ return buildAgentFrontmatter(meta) + content;
258
+ }
259
+ /**
260
+ * Transform content into a prompt file (no frontmatter — just the managed-file
261
+ * header comment followed by the prompt body).
262
+ */
263
+ transformPromptFile(content, meta) {
23
264
  const header = [
24
265
  `<!-- spec-lite | ${meta.name} | DO NOT EDIT below the project-context block \u2014 managed by spec-lite -->`,
25
266
  `<!-- To update: run "spec-lite update" \u2014 your Project Context edits will be preserved -->`,
@@ -27,44 +268,107 @@ var CopilotProvider = class {
27
268
  ].join("\n");
28
269
  return header + content;
29
270
  }
271
+ /** Returns the path for the companion .prompt.md file */
272
+ getPromptFilePath(promptName) {
273
+ return path.join(".github", "prompts", `${promptName}.prompt.md`);
274
+ }
30
275
  async detectExisting(workspaceRoot) {
31
276
  const existing = [];
32
- const copilotDir = path.join(workspaceRoot, ".github", "copilot");
33
- if (await fs.pathExists(copilotDir)) {
34
- const files = await fs.readdir(copilotDir);
277
+ const agentsDir = path.join(workspaceRoot, ".github", "agents");
278
+ if (await fs.pathExists(agentsDir)) {
279
+ const files = await fs.readdir(agentsDir);
35
280
  for (const f of files) {
36
- if (f.endsWith(".prompt.md") || f.endsWith(".md")) {
37
- existing.push(path.join(".github", "copilot", f));
281
+ if (f.startsWith("spec.") && f.endsWith(".agent.md")) {
282
+ existing.push(path.join(".github", "agents", f));
38
283
  }
39
284
  }
40
285
  }
41
- const mainFile = path.join(
42
- workspaceRoot,
43
- ".github",
44
- "copilot-instructions.md"
45
- );
286
+ const promptsDir = path.join(workspaceRoot, ".github", "prompts");
287
+ if (await fs.pathExists(promptsDir)) {
288
+ const files = await fs.readdir(promptsDir);
289
+ for (const f of files) {
290
+ if (f.endsWith(".prompt.md")) {
291
+ existing.push(path.join(".github", "prompts", f));
292
+ }
293
+ }
294
+ }
295
+ const mainFile = path.join(workspaceRoot, ".github", "copilot-instructions.md");
46
296
  if (await fs.pathExists(mainFile)) {
47
297
  existing.push(".github/copilot-instructions.md");
48
298
  }
49
299
  return existing;
50
300
  }
301
+ async getMemorySeedSource(workspaceRoot) {
302
+ const p = path.join(workspaceRoot, ".github", "copilot-instructions.md");
303
+ if (await fs.pathExists(p)) {
304
+ return { path: ".github/copilot-instructions.md", label: "GitHub Copilot global instructions" };
305
+ }
306
+ return null;
307
+ }
51
308
  getPostInitMessage() {
52
309
  return [
53
310
  "",
54
311
  "\u{1F4CB} GitHub Copilot setup complete!",
55
312
  "",
56
- " Your sub-agent prompts are in .github/copilot/",
313
+ " Agent files : .github/agents/spec.<name>.agent.md",
314
+ " Prompt files : .github/prompts/<name>.prompt.md",
57
315
  "",
58
316
  " How to use:",
59
317
  " 1. Open GitHub Copilot Chat in VS Code",
60
- " 2. Sub-agents are available as slash commands \u2014 type /prompt_name",
61
- " (e.g., /brainstorm, /planner, /feature)",
62
- " 3. Files ending in .prompt.md are natively recognized by Copilot",
318
+ " 2. Select a sub-agent from the agents dropdown (e.g., spec.planner)",
319
+ " \u2014 or \u2014 reference a prompt file with #file or type / to browse",
320
+ " 3. Agent files include handoff buttons to guide you through the pipeline",
63
321
  " 4. Customize the Project Context block in each file for your project",
64
322
  ""
65
323
  ].join("\n");
66
324
  }
67
325
  };
326
+ var SPEC_LITE_MARKER_START = "<!-- spec-lite:start -->";
327
+ var SPEC_LITE_MARKER_END = "<!-- spec-lite:end -->";
328
+ function generateSpecLiteBlock(installedPrompts) {
329
+ const lines = [
330
+ SPEC_LITE_MARKER_START,
331
+ "## spec-lite Sub-Agents",
332
+ "",
333
+ "This project uses [spec-lite](https://github.com/abranjith/spec-lite) sub-agent prompts",
334
+ "for structured software engineering workflows.",
335
+ "",
336
+ "The following specialist sub-agents are available:",
337
+ "",
338
+ "**Agent files** (`.github/agents/`) \u2014 select from the agents dropdown in Copilot Chat:",
339
+ ""
340
+ ];
341
+ for (const name of installedPrompts) {
342
+ lines.push(`- [spec.${name}](.github/agents/spec.${name}.agent.md)`);
343
+ }
344
+ lines.push(
345
+ "",
346
+ "**Prompt files** (`.github/prompts/`) \u2014 reference with `#file` or browse with `/`:",
347
+ ""
348
+ );
349
+ for (const name of installedPrompts) {
350
+ lines.push(`- [${name}](.github/prompts/${name}.prompt.md)`);
351
+ }
352
+ lines.push(
353
+ "",
354
+ "To invoke a sub-agent, select it from the agents dropdown or use `#file` to reference a prompt file.",
355
+ SPEC_LITE_MARKER_END
356
+ );
357
+ return lines.join("\n");
358
+ }
359
+ function mergeCopilotInstructions(existingContent, installedPrompts) {
360
+ const block = generateSpecLiteBlock(installedPrompts);
361
+ if (!existingContent) {
362
+ return block + "\n";
363
+ }
364
+ const startIdx = existingContent.indexOf(SPEC_LITE_MARKER_START);
365
+ const endIdx = existingContent.indexOf(SPEC_LITE_MARKER_END);
366
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
367
+ return existingContent.slice(0, startIdx) + block + existingContent.slice(endIdx + SPEC_LITE_MARKER_END.length);
368
+ }
369
+ const separator = existingContent.endsWith("\n") ? "\n" : "\n\n";
370
+ return existingContent + separator + block + "\n";
371
+ }
68
372
 
69
373
  // src/providers/claude-code.ts
70
374
  import path2 from "path";
@@ -105,6 +409,13 @@ var ClaudeCodeProvider = class {
105
409
  }
106
410
  return existing;
107
411
  }
412
+ async getMemorySeedSource(workspaceRoot) {
413
+ const p = path2.join(workspaceRoot, "CLAUDE.md");
414
+ if (await fs2.pathExists(p)) {
415
+ return { path: "CLAUDE.md", label: "Claude root instructions (CLAUDE.md)" };
416
+ }
417
+ return null;
418
+ }
108
419
  getPostInitMessage() {
109
420
  return [
110
421
  "",
@@ -127,7 +438,7 @@ function generateClaudeRootMd(installedPrompts) {
127
438
  "",
128
439
  "# Project Instructions",
129
440
  "",
130
- "This project uses [spec-lite](https://github.com/ranjithab/spec-lite) sub-agent prompts",
441
+ "This project uses [spec-lite](https://github.com/abranjith/spec-lite) sub-agent prompts",
131
442
  "for structured software engineering workflows.",
132
443
  "",
133
444
  "## Available Sub-Agents",
@@ -150,10 +461,10 @@ function generateClaudeRootMd(installedPrompts) {
150
461
  "",
151
462
  "## Output Directory",
152
463
  "",
153
- "Sub-agent outputs are written to the `.spec/` directory:",
464
+ "Sub-agent outputs are written to the `.spec-lite/` directory:",
154
465
  "",
155
466
  "```text",
156
- ".spec/",
467
+ ".spec-lite/",
157
468
  "\u251C\u2500\u2500 brainstorm.md",
158
469
  "\u251C\u2500\u2500 plan.md # Default plan (simple projects)",
159
470
  "\u251C\u2500\u2500 plan_<name>.md # Named plans (complex projects)",
@@ -197,6 +508,9 @@ var GenericProvider = class {
197
508
  }
198
509
  return existing;
199
510
  }
511
+ async getMemorySeedSource(_workspaceRoot) {
512
+ return null;
513
+ }
200
514
  getPostInitMessage() {
201
515
  return [
202
516
  "",
@@ -245,17 +559,17 @@ var PROMPT_CATALOG = {
245
559
  brainstorm: {
246
560
  title: "Brainstorm",
247
561
  description: "Refines a vague idea into a clear, actionable vision",
248
- output: ".spec/brainstorm.md"
562
+ output: ".spec-lite/brainstorm.md"
249
563
  },
250
564
  planner: {
251
565
  title: "Planner",
252
566
  description: "Creates a detailed technical blueprint from requirements",
253
- output: ".spec/plan.md or .spec/plan_<name>.md"
567
+ output: ".spec-lite/plan.md or .spec-lite/plan_<name>.md"
254
568
  },
255
569
  feature: {
256
570
  title: "Feature",
257
571
  description: "Breaks one feature into granular, verifiable vertical slices",
258
- output: ".spec/features/feature_<name>.md"
572
+ output: ".spec-lite/features/feature_<name>.md"
259
573
  },
260
574
  implement: {
261
575
  title: "Implement",
@@ -265,17 +579,17 @@ var PROMPT_CATALOG = {
265
579
  code_review: {
266
580
  title: "Code Review",
267
581
  description: "Reviews code for correctness, architecture, and readability",
268
- output: ".spec/reviews/code_review_<name>.md"
582
+ output: ".spec-lite/reviews/code_review_<name>.md"
269
583
  },
270
584
  security_audit: {
271
585
  title: "Security Audit",
272
586
  description: "Scans for vulnerabilities, misconfigurations, and security risks",
273
- output: ".spec/reviews/security_audit_<scope>.md"
587
+ output: ".spec-lite/reviews/security_audit_<scope>.md"
274
588
  },
275
589
  performance_review: {
276
590
  title: "Performance Review",
277
591
  description: "Identifies bottlenecks and optimization opportunities",
278
- output: ".spec/reviews/performance_review_<scope>.md"
592
+ output: ".spec-lite/reviews/performance_review_<scope>.md"
279
593
  },
280
594
  integration_tests: {
281
595
  title: "Integration Tests",
@@ -285,7 +599,7 @@ var PROMPT_CATALOG = {
285
599
  unit_tests: {
286
600
  title: "Unit Tests",
287
601
  description: "Generates comprehensive unit tests with edge-case coverage and smart coverage exclusions",
288
- output: ".spec/features/unit_tests_<name>.md"
602
+ output: ".spec-lite/features/unit_tests_<name>.md"
289
603
  },
290
604
  devops: {
291
605
  title: "DevOps",
@@ -300,7 +614,7 @@ var PROMPT_CATALOG = {
300
614
  memorize: {
301
615
  title: "Memorize",
302
616
  description: "Stores standing instructions that all sub-agents enforce. Use `/memorize bootstrap` to auto-generate from project analysis.",
303
- output: ".spec/memory.md"
617
+ output: ".spec-lite/memory.md"
304
618
  },
305
619
  technical_docs: {
306
620
  title: "Technical Docs",
@@ -311,6 +625,11 @@ var PROMPT_CATALOG = {
311
625
  title: "README",
312
626
  description: "Writes the project README and optional user guide",
313
627
  output: "README.md + docs/user_guide.md"
628
+ },
629
+ architect: {
630
+ title: "Architect",
631
+ description: "Designs cloud infrastructure, database strategy, and scaling architecture with Mermaid diagrams",
632
+ output: ".spec-lite/architect_<name>.md"
314
633
  }
315
634
  };
316
635
  var SKIP_FILES = /* @__PURE__ */ new Set(["orchestrator"]);
@@ -492,6 +811,34 @@ function buildProjectContextBlock(profile) {
492
811
  lines.push("");
493
812
  return lines.join("\n");
494
813
  }
814
+ function buildSeededMemory(sourceContent, sourcePath, version) {
815
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
816
+ return [
817
+ `<!-- Generated by spec-lite v${version} | sub-agent: memorize | seeded-from: ${sourcePath} | updated: ${date} -->`,
818
+ "",
819
+ "# Memory \u2014 Standing Instructions",
820
+ "",
821
+ `> These instructions were **auto-seeded** from \`${sourcePath}\` during \`spec-lite init\`.`,
822
+ "> They have not yet been organized into sections.",
823
+ "> Run `/memorize bootstrap` in your AI assistant to review, reorganize, and refine them.",
824
+ ">",
825
+ "> Memory is the **authoritative source** for coding standards, architecture, testing, logging, and security.",
826
+ "> Plans may contain plan-specific overrides but should not duplicate these rules.",
827
+ "> Managed by the Memorize sub-agent. Do not edit section headers manually.",
828
+ "> To add or change instructions, invoke: `/memorize <your instructions>`",
829
+ "> To override: `/memorize override <your instructions>`",
830
+ "> To generate from project analysis: `/memorize bootstrap`",
831
+ "",
832
+ `<!-- seed-start: raw content imported from ${sourcePath} -->`,
833
+ "",
834
+ `## Imported from \`${sourcePath}\``,
835
+ "",
836
+ sourceContent.trim(),
837
+ "",
838
+ "<!-- seed-end -->",
839
+ ""
840
+ ].join("\n");
841
+ }
495
842
  async function initCommand(options) {
496
843
  const cwd = process.cwd();
497
844
  console.log(chalk.bold("\n\u26A1 spec-lite init\n"));
@@ -532,7 +879,16 @@ async function initCommand(options) {
532
879
  if (exclude.length > 0) {
533
880
  console.log(chalk.dim(` Excluding: ${exclude.join(", ")}`));
534
881
  }
882
+ const memorySeedSource = await provider.getMemorySeedSource(cwd);
883
+ let preSeedContent = null;
884
+ if (memorySeedSource) {
885
+ const seedAbsPath = path6.join(cwd, memorySeedSource.path);
886
+ if (await fs6.pathExists(seedAbsPath)) {
887
+ preSeedContent = await fs6.readFile(seedAbsPath, "utf-8");
888
+ }
889
+ }
535
890
  const existingFiles = await provider.detectExisting(cwd);
891
+ let globalAction = null;
536
892
  if (existingFiles.length > 0 && !options.force) {
537
893
  console.log(
538
894
  chalk.yellow(
@@ -563,7 +919,8 @@ ${existingFiles.map((f) => ` - ${f}`).join("\n")}`
563
919
  console.log(chalk.dim(" Aborted."));
564
920
  return;
565
921
  }
566
- if (answer.action === "skip") {
922
+ globalAction = answer.action;
923
+ if (globalAction === "skip") {
567
924
  console.log(chalk.dim(" Skipping existing files."));
568
925
  }
569
926
  }
@@ -575,23 +932,10 @@ ${existingFiles.map((f) => ` - ${f}`).join("\n")}`
575
932
  for (const prompt of prompts) {
576
933
  const targetRelPath = provider.getTargetPath(prompt.name);
577
934
  const targetAbsPath = path6.join(cwd, targetRelPath);
578
- if (!options.force && existingFiles.includes(targetRelPath) && existingFiles.length > 0) {
579
- const answer = await inquirer.prompt([
580
- {
581
- type: "list",
582
- name: "action",
583
- message: `How should we handle existing files?`,
584
- choices: [
585
- { name: "Overwrite", value: "overwrite" },
586
- { name: "Skip", value: "skip" }
587
- ]
588
- }
589
- ]);
590
- if (answer.action === "skip") {
591
- skipped++;
592
- installedPrompts.push(prompt.name);
593
- continue;
594
- }
935
+ if (!options.force && existingFiles.includes(targetRelPath) && globalAction === "skip") {
936
+ skipped++;
937
+ installedPrompts.push(prompt.name);
938
+ continue;
595
939
  }
596
940
  let content = prompt.content;
597
941
  if (contextBlock) {
@@ -615,10 +959,43 @@ ${existingFiles.map((f) => ` - ${f}`).join("\n")}`
615
959
  console.log(chalk.green(` \u2713 CLAUDE.md`));
616
960
  written++;
617
961
  }
962
+ if (provider.alias === "copilot") {
963
+ const copilotProvider = provider;
964
+ for (const prompt of prompts) {
965
+ const promptRelPath = copilotProvider.getPromptFilePath(prompt.name);
966
+ const promptAbsPath = path6.join(cwd, promptRelPath);
967
+ if (!options.force && existingFiles.includes(promptRelPath) && globalAction === "skip") {
968
+ continue;
969
+ }
970
+ let content = prompt.content;
971
+ if (contextBlock) {
972
+ content = replaceProjectContext(content, contextBlock);
973
+ }
974
+ const transformed = copilotProvider.transformPromptFile(content, {
975
+ name: prompt.name,
976
+ title: prompt.title,
977
+ description: prompt.description
978
+ });
979
+ await fs6.ensureDir(path6.dirname(promptAbsPath));
980
+ await fs6.writeFile(promptAbsPath, transformed, "utf-8");
981
+ written++;
982
+ console.log(chalk.green(` \u2713 ${promptRelPath}`));
983
+ }
984
+ const copilotInstructionsPath = path6.join(cwd, ".github", "copilot-instructions.md");
985
+ await fs6.ensureDir(path6.join(cwd, ".github"));
986
+ const existingContent = await fs6.pathExists(copilotInstructionsPath) ? await fs6.readFile(copilotInstructionsPath, "utf-8") : null;
987
+ const merged = mergeCopilotInstructions(existingContent, installedPrompts);
988
+ await fs6.writeFile(copilotInstructionsPath, merged, "utf-8");
989
+ if (existingContent) {
990
+ console.log(chalk.green(` \u2713 .github/copilot-instructions.md (updated with spec-lite block)`));
991
+ } else {
992
+ console.log(chalk.green(` \u2713 .github/copilot-instructions.md`));
993
+ }
994
+ written++;
995
+ }
618
996
  const specDirs = [
619
- ".spec",
620
- path6.join(".spec", "features"),
621
- path6.join(".spec", "reviews")
997
+ path6.join(".spec-lite", "features"),
998
+ path6.join(".spec-lite", "reviews")
622
999
  ];
623
1000
  for (const dir of specDirs) {
624
1001
  const absDir = path6.join(cwd, dir);
@@ -627,7 +1004,7 @@ ${existingFiles.map((f) => ` - ${f}`).join("\n")}`
627
1004
  console.log(chalk.green(` \u2713 ${dir}/`));
628
1005
  }
629
1006
  }
630
- const todoPath = path6.join(cwd, ".spec", "TODO.md");
1007
+ const todoPath = path6.join(cwd, ".spec-lite", "TODO.md");
631
1008
  if (!await fs6.pathExists(todoPath)) {
632
1009
  const todoContent = [
633
1010
  "# TODO \u2014 Enhancements & Ideas",
@@ -649,7 +1026,7 @@ ${existingFiles.map((f) => ` - ${f}`).join("\n")}`
649
1026
  ""
650
1027
  ].join("\n");
651
1028
  await fs6.writeFile(todoPath, todoContent, "utf-8");
652
- console.log(chalk.green(` \u2713 .spec/TODO.md`));
1029
+ console.log(chalk.green(` \u2713 .spec-lite/TODO.md`));
653
1030
  }
654
1031
  if (projectProfile) {
655
1032
  const snippet = getStackSnippet(projectProfile.language);
@@ -674,6 +1051,32 @@ ${existingFiles.map((f) => ` - ${f}`).join("\n")}`
674
1051
  }
675
1052
  }
676
1053
  }
1054
+ let memorySeedWritten = false;
1055
+ const memoryPath = path6.join(cwd, ".spec-lite", "memory.md");
1056
+ if (preSeedContent && memorySeedSource && !await fs6.pathExists(memoryPath)) {
1057
+ console.log(
1058
+ chalk.cyan(`
1059
+ \u{1F4A1} Found existing ${memorySeedSource.label} (${memorySeedSource.path}).`)
1060
+ );
1061
+ const seedAnswer = await inquirer.prompt([
1062
+ {
1063
+ type: "confirm",
1064
+ name: "seedMemory",
1065
+ message: `Seed .spec-lite/memory.md from it so /memorize bootstrap can refine your existing conventions?`,
1066
+ default: true
1067
+ }
1068
+ ]);
1069
+ if (seedAnswer.seedMemory) {
1070
+ const seedPkg = await loadPackageVersion();
1071
+ const seededContent = buildSeededMemory(preSeedContent, memorySeedSource.path, seedPkg);
1072
+ await fs6.ensureDir(path6.join(cwd, ".spec-lite"));
1073
+ await fs6.writeFile(memoryPath, seededContent, "utf-8");
1074
+ memorySeedWritten = true;
1075
+ written++;
1076
+ console.log(chalk.green(` \u2713 .spec-lite/memory.md (seeded from ${memorySeedSource.path})`));
1077
+ console.log(chalk.dim(" \u21B3 Run /memorize bootstrap to organize and refine into standing instructions"));
1078
+ }
1079
+ }
677
1080
  const pkg2 = await loadPackageVersion();
678
1081
  const config = {
679
1082
  version: pkg2,
@@ -693,14 +1096,24 @@ ${existingFiles.map((f) => ` - ${f}`).join("\n")}`
693
1096
  )
694
1097
  );
695
1098
  console.log(provider.getPostInitMessage());
696
- if (projectProfile) {
697
- console.log(
698
- chalk.cyan(
699
- "\n \u{1F4CC} Next step: Run "
700
- ) + chalk.bold("/memorize bootstrap") + chalk.cyan(
701
- " in your AI assistant to auto-generate\n coding standards, architecture guidelines, and best practices\n for your project based on the profile you just provided."
702
- )
703
- );
1099
+ if (projectProfile || memorySeedWritten) {
1100
+ if (memorySeedWritten) {
1101
+ console.log(
1102
+ chalk.cyan(
1103
+ "\n \u{1F4CC} Next step: Run "
1104
+ ) + chalk.bold("/memorize bootstrap") + chalk.cyan(
1105
+ " in your AI assistant.\n It will see your seeded memory and offer to merge or refine it\n into properly organized standing instructions."
1106
+ )
1107
+ );
1108
+ } else {
1109
+ console.log(
1110
+ chalk.cyan(
1111
+ "\n \u{1F4CC} Next step: Run "
1112
+ ) + chalk.bold("/memorize bootstrap") + chalk.cyan(
1113
+ " in your AI assistant to auto-generate\n coding standards, architecture guidelines, and best practices\n for your project based on the profile you just provided."
1114
+ )
1115
+ );
1116
+ }
704
1117
  }
705
1118
  }
706
1119
  async function loadPackageVersion() {
@@ -710,7 +1123,7 @@ async function loadPackageVersion() {
710
1123
  const pkg2 = require3("../../package.json");
711
1124
  return pkg2.version;
712
1125
  } catch {
713
- return "1.0.0";
1126
+ return "0.0.4";
714
1127
  }
715
1128
  }
716
1129
 
@@ -750,24 +1163,9 @@ async function updateCommand(options) {
750
1163
  let updated = 0;
751
1164
  let preserved = 0;
752
1165
  let unchanged = 0;
753
- let migrated = 0;
754
1166
  for (const prompt of prompts) {
755
1167
  const targetRelPath = provider.getTargetPath(prompt.name);
756
1168
  const targetAbsPath = path7.join(cwd, targetRelPath);
757
- if (provider.alias === "copilot") {
758
- const oldRelPath = path7.join(".github", "copilot", `${prompt.name}.md`);
759
- const oldAbsPath = path7.join(cwd, oldRelPath);
760
- if (targetRelPath !== oldRelPath && await fs7.pathExists(oldAbsPath) && !await fs7.pathExists(targetAbsPath)) {
761
- await fs7.ensureDir(path7.dirname(targetAbsPath));
762
- await fs7.rename(oldAbsPath, targetAbsPath);
763
- console.log(
764
- chalk2.cyan(
765
- ` \u2197 ${oldRelPath} \u2192 ${targetRelPath} (migrated to .prompt.md)`
766
- )
767
- );
768
- migrated++;
769
- }
770
- }
771
1169
  const newContent = provider.transformPrompt(prompt.content, {
772
1170
  name: prompt.name,
773
1171
  title: prompt.title,
@@ -810,6 +1208,50 @@ async function updateCommand(options) {
810
1208
  await fs7.writeFile(claudeMdPath, claudeMdContent, "utf-8");
811
1209
  console.log(chalk2.green(` \u2713 CLAUDE.md (regenerated)`));
812
1210
  }
1211
+ if (provider.alias === "copilot") {
1212
+ const copilotProvider = provider;
1213
+ for (const prompt of prompts) {
1214
+ const promptRelPath = copilotProvider.getPromptFilePath(prompt.name);
1215
+ const promptAbsPath = path7.join(cwd, promptRelPath);
1216
+ const newContent = copilotProvider.transformPromptFile(prompt.content, {
1217
+ name: prompt.name,
1218
+ title: prompt.title,
1219
+ description: prompt.description
1220
+ });
1221
+ if (!await fs7.pathExists(promptAbsPath)) {
1222
+ await fs7.ensureDir(path7.dirname(promptAbsPath));
1223
+ await fs7.writeFile(promptAbsPath, newContent, "utf-8");
1224
+ console.log(chalk2.green(` \u2713 ${promptRelPath} (restored)`));
1225
+ updated++;
1226
+ continue;
1227
+ }
1228
+ const currentContent = await fs7.readFile(promptAbsPath, "utf-8");
1229
+ if (currentContent === newContent) {
1230
+ unchanged++;
1231
+ continue;
1232
+ }
1233
+ if (!options.force) {
1234
+ const userContext = extractProjectContext(currentContent);
1235
+ if (userContext) {
1236
+ const mergedContent = replaceProjectContext(newContent, userContext);
1237
+ await fs7.writeFile(promptAbsPath, mergedContent, "utf-8");
1238
+ console.log(chalk2.green(` \u2713 ${promptRelPath} (updated, Project Context preserved)`));
1239
+ preserved++;
1240
+ updated++;
1241
+ continue;
1242
+ }
1243
+ }
1244
+ await fs7.writeFile(promptAbsPath, newContent, "utf-8");
1245
+ console.log(chalk2.green(` \u2713 ${promptRelPath} (updated)`));
1246
+ updated++;
1247
+ }
1248
+ const copilotInstructionsPath = path7.join(cwd, ".github", "copilot-instructions.md");
1249
+ await fs7.ensureDir(path7.join(cwd, ".github"));
1250
+ const existingContent = await fs7.pathExists(copilotInstructionsPath) ? await fs7.readFile(copilotInstructionsPath, "utf-8") : null;
1251
+ const merged = mergeCopilotInstructions(existingContent, config.installedPrompts);
1252
+ await fs7.writeFile(copilotInstructionsPath, merged, "utf-8");
1253
+ console.log(chalk2.green(` \u2713 .github/copilot-instructions.md (updated)`));
1254
+ }
813
1255
  config.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
814
1256
  try {
815
1257
  const { createRequire: createRequire2 } = await import("module");
@@ -822,7 +1264,7 @@ async function updateCommand(options) {
822
1264
  console.log(
823
1265
  chalk2.bold(
824
1266
  `
825
- Done! ${updated} updated, ${unchanged} unchanged, ${preserved} with preserved edits${migrated > 0 ? `, ${migrated} migrated` : ""}.`
1267
+ Done! ${updated} updated, ${unchanged} unchanged, ${preserved} with preserved edits.`
826
1268
  )
827
1269
  );
828
1270
  }