specweave 0.3.13 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/CLAUDE.md +506 -17
  2. package/README.md +100 -58
  3. package/bin/install-all.sh +9 -2
  4. package/bin/install-hooks.sh +57 -0
  5. package/bin/specweave.js +16 -0
  6. package/dist/adapters/adapter-base.d.ts +21 -0
  7. package/dist/adapters/adapter-base.d.ts.map +1 -1
  8. package/dist/adapters/adapter-base.js +28 -0
  9. package/dist/adapters/adapter-base.js.map +1 -1
  10. package/dist/adapters/adapter-interface.d.ts +41 -0
  11. package/dist/adapters/adapter-interface.d.ts.map +1 -1
  12. package/dist/adapters/claude/adapter.d.ts +36 -0
  13. package/dist/adapters/claude/adapter.d.ts.map +1 -1
  14. package/dist/adapters/claude/adapter.js +135 -0
  15. package/dist/adapters/claude/adapter.js.map +1 -1
  16. package/dist/adapters/copilot/adapter.d.ts +25 -0
  17. package/dist/adapters/copilot/adapter.d.ts.map +1 -1
  18. package/dist/adapters/copilot/adapter.js +112 -0
  19. package/dist/adapters/copilot/adapter.js.map +1 -1
  20. package/dist/adapters/cursor/adapter.d.ts +36 -0
  21. package/dist/adapters/cursor/adapter.d.ts.map +1 -1
  22. package/dist/adapters/cursor/adapter.js +140 -0
  23. package/dist/adapters/cursor/adapter.js.map +1 -1
  24. package/dist/adapters/generic/adapter.d.ts +25 -0
  25. package/dist/adapters/generic/adapter.d.ts.map +1 -1
  26. package/dist/adapters/generic/adapter.js +111 -0
  27. package/dist/adapters/generic/adapter.js.map +1 -1
  28. package/dist/cli/commands/init.d.ts.map +1 -1
  29. package/dist/cli/commands/init.js +103 -1
  30. package/dist/cli/commands/init.js.map +1 -1
  31. package/dist/cli/commands/plugin.d.ts +37 -0
  32. package/dist/cli/commands/plugin.d.ts.map +1 -0
  33. package/dist/cli/commands/plugin.js +296 -0
  34. package/dist/cli/commands/plugin.js.map +1 -0
  35. package/dist/core/agent-model-manager.d.ts +52 -0
  36. package/dist/core/agent-model-manager.d.ts.map +1 -0
  37. package/dist/core/agent-model-manager.js +120 -0
  38. package/dist/core/agent-model-manager.js.map +1 -0
  39. package/dist/core/cost-tracker.d.ts +108 -0
  40. package/dist/core/cost-tracker.d.ts.map +1 -0
  41. package/dist/core/cost-tracker.js +281 -0
  42. package/dist/core/cost-tracker.js.map +1 -0
  43. package/dist/core/model-selector.d.ts +57 -0
  44. package/dist/core/model-selector.d.ts.map +1 -0
  45. package/dist/core/model-selector.js +115 -0
  46. package/dist/core/model-selector.js.map +1 -0
  47. package/dist/core/phase-detector.d.ts +62 -0
  48. package/dist/core/phase-detector.d.ts.map +1 -0
  49. package/dist/core/phase-detector.js +229 -0
  50. package/dist/core/phase-detector.js.map +1 -0
  51. package/dist/core/plugin-detector.d.ts +96 -0
  52. package/dist/core/plugin-detector.d.ts.map +1 -0
  53. package/dist/core/plugin-detector.js +349 -0
  54. package/dist/core/plugin-detector.js.map +1 -0
  55. package/dist/core/plugin-loader.d.ts +111 -0
  56. package/dist/core/plugin-loader.d.ts.map +1 -0
  57. package/dist/core/plugin-loader.js +319 -0
  58. package/dist/core/plugin-loader.js.map +1 -0
  59. package/dist/core/plugin-manager.d.ts +144 -0
  60. package/dist/core/plugin-manager.d.ts.map +1 -0
  61. package/dist/core/plugin-manager.js +393 -0
  62. package/dist/core/plugin-manager.js.map +1 -0
  63. package/dist/core/schemas/plugin-manifest.schema.json +253 -0
  64. package/dist/core/types/plugin.d.ts +252 -0
  65. package/dist/core/types/plugin.d.ts.map +1 -0
  66. package/dist/core/types/plugin.js +48 -0
  67. package/dist/core/types/plugin.js.map +1 -0
  68. package/dist/integrations/jira/jira-mapper.d.ts +2 -2
  69. package/dist/integrations/jira/jira-mapper.js +2 -2
  70. package/dist/types/cost-tracking.d.ts +43 -0
  71. package/dist/types/cost-tracking.d.ts.map +1 -0
  72. package/dist/types/cost-tracking.js +8 -0
  73. package/dist/types/cost-tracking.js.map +1 -0
  74. package/dist/types/model-selection.d.ts +53 -0
  75. package/dist/types/model-selection.d.ts.map +1 -0
  76. package/dist/types/model-selection.js +12 -0
  77. package/dist/types/model-selection.js.map +1 -0
  78. package/dist/utils/cost-reporter.d.ts +58 -0
  79. package/dist/utils/cost-reporter.d.ts.map +1 -0
  80. package/dist/utils/cost-reporter.js +224 -0
  81. package/dist/utils/cost-reporter.js.map +1 -0
  82. package/dist/utils/pricing-constants.d.ts +70 -0
  83. package/dist/utils/pricing-constants.d.ts.map +1 -0
  84. package/dist/utils/pricing-constants.js +71 -0
  85. package/dist/utils/pricing-constants.js.map +1 -0
  86. package/package.json +13 -9
  87. package/src/adapters/adapter-base.ts +33 -0
  88. package/src/adapters/adapter-interface.ts +46 -0
  89. package/src/adapters/claude/adapter.ts +164 -0
  90. package/src/adapters/copilot/adapter.ts +138 -0
  91. package/src/adapters/cursor/adapter.ts +170 -0
  92. package/src/adapters/generic/adapter.ts +137 -0
  93. package/src/agents/architect/AGENT.md +3 -0
  94. package/src/agents/code-reviewer.md +156 -0
  95. package/src/agents/data-scientist/AGENT.md +181 -0
  96. package/src/agents/database-optimizer/AGENT.md +147 -0
  97. package/src/agents/devops/AGENT.md +3 -0
  98. package/src/agents/diagrams-architect/AGENT.md +3 -0
  99. package/src/agents/docs-writer/AGENT.md +3 -0
  100. package/src/agents/kubernetes-architect/AGENT.md +142 -0
  101. package/src/agents/ml-engineer/AGENT.md +150 -0
  102. package/src/agents/mlops-engineer/AGENT.md +201 -0
  103. package/src/agents/network-engineer/AGENT.md +149 -0
  104. package/src/agents/observability-engineer/AGENT.md +213 -0
  105. package/src/agents/payment-integration/AGENT.md +35 -0
  106. package/src/agents/performance/AGENT.md +3 -0
  107. package/src/agents/performance-engineer/AGENT.md +153 -0
  108. package/src/agents/pm/AGENT.md +3 -0
  109. package/src/agents/qa-lead/AGENT.md +3 -0
  110. package/src/agents/security/AGENT.md +3 -0
  111. package/src/agents/sre/AGENT.md +3 -0
  112. package/src/agents/tdd-orchestrator/AGENT.md +169 -0
  113. package/src/agents/tech-lead/AGENT.md +3 -0
  114. package/src/commands/specweave.costs.md +261 -0
  115. package/src/commands/specweave.increment.md +48 -4
  116. package/src/commands/specweave.ml-pipeline.md +292 -0
  117. package/src/commands/specweave.monitor-setup.md +501 -0
  118. package/src/commands/specweave.slo-implement.md +1055 -0
  119. package/src/commands/specweave.sync-github.md +1 -1
  120. package/src/commands/specweave.tdd-cycle.md +199 -0
  121. package/src/commands/specweave.tdd-green.md +842 -0
  122. package/src/commands/specweave.tdd-red.md +135 -0
  123. package/src/commands/specweave.tdd-refactor.md +165 -0
  124. package/src/hooks/post-increment-plugin-detect.sh +142 -0
  125. package/src/hooks/post-task-completion.sh +53 -11
  126. package/src/hooks/pre-task-plugin-detect.sh +96 -0
  127. package/src/skills/SKILLS-INDEX.md +18 -10
  128. package/src/skills/billing-automation/SKILL.md +559 -0
  129. package/src/skills/distributed-tracing/SKILL.md +438 -0
  130. package/src/skills/e2e-playwright/README.md +1 -1
  131. package/src/skills/e2e-playwright/package.json +1 -1
  132. package/src/skills/gitops-workflow/SKILL.md +285 -0
  133. package/src/skills/gitops-workflow/references/argocd-setup.md +134 -0
  134. package/src/skills/gitops-workflow/references/sync-policies.md +131 -0
  135. package/src/skills/grafana-dashboards/SKILL.md +369 -0
  136. package/src/skills/helm-chart-scaffolding/SKILL.md +544 -0
  137. package/src/skills/helm-chart-scaffolding/assets/Chart.yaml.template +42 -0
  138. package/src/skills/helm-chart-scaffolding/assets/values.yaml.template +185 -0
  139. package/src/skills/helm-chart-scaffolding/references/chart-structure.md +500 -0
  140. package/src/skills/helm-chart-scaffolding/scripts/validate-chart.sh +244 -0
  141. package/src/skills/k8s-manifest-generator/SKILL.md +511 -0
  142. package/src/skills/k8s-manifest-generator/assets/configmap-template.yaml +296 -0
  143. package/src/skills/k8s-manifest-generator/assets/deployment-template.yaml +203 -0
  144. package/src/skills/k8s-manifest-generator/assets/service-template.yaml +171 -0
  145. package/src/skills/k8s-manifest-generator/references/deployment-spec.md +753 -0
  146. package/src/skills/k8s-manifest-generator/references/service-spec.md +724 -0
  147. package/src/skills/k8s-security-policies/SKILL.md +334 -0
  148. package/src/skills/k8s-security-policies/assets/network-policy-template.yaml +177 -0
  149. package/src/skills/k8s-security-policies/references/rbac-patterns.md +187 -0
  150. package/src/skills/ml-pipeline-workflow/SKILL.md +245 -0
  151. package/src/skills/paypal-integration/SKILL.md +467 -0
  152. package/src/skills/pci-compliance/SKILL.md +466 -0
  153. package/src/skills/prometheus-configuration/SKILL.md +392 -0
  154. package/src/skills/slo-implementation/SKILL.md +329 -0
  155. package/src/skills/stripe-integration/SKILL.md +442 -0
  156. package/src/skills/tdd-workflow/SKILL.md +378 -0
  157. package/src/templates/README.md.template +1 -1
  158. package/src/skills/bmad-method-expert/SKILL.md +0 -626
  159. package/src/skills/bmad-method-expert/scripts/analyze-project.js +0 -318
  160. package/src/skills/bmad-method-expert/scripts/check-setup.js +0 -208
  161. package/src/skills/bmad-method-expert/scripts/generate-template.js +0 -1149
  162. package/src/skills/bmad-method-expert/scripts/validate-documents.js +0 -340
  163. package/src/skills/context-optimizer/SKILL.md +0 -588
  164. package/src/skills/figma-designer/SKILL.md +0 -149
  165. package/src/skills/figma-implementer/SKILL.md +0 -148
  166. package/src/skills/figma-mcp-connector/SKILL.md +0 -136
  167. package/src/skills/figma-to-code/SKILL.md +0 -128
  168. package/src/skills/spec-kit-expert/SKILL.md +0 -1010
@@ -12,6 +12,7 @@ import * as path from 'path';
12
12
  import fs from 'fs-extra';
13
13
  import { AdapterBase } from '../adapter-base.js';
14
14
  import { AdapterOptions, AdapterFile } from '../adapter-interface.js';
15
+ import type { Plugin } from '../../core/types/plugin.js';
15
16
 
16
17
  export class ClaudeAdapter extends AdapterBase {
17
18
  name = 'claude';
@@ -154,4 +155,167 @@ You're ready to build with SpecWeave on Claude Code!
154
155
  For complete documentation, see: .claude/README.md
155
156
  `;
156
157
  }
158
+
159
+ /**
160
+ * Check if Claude adapter supports plugins
161
+ *
162
+ * Claude Code has FULL plugin support via native .claude/ directory
163
+ *
164
+ * @returns boolean Always true
165
+ */
166
+ supportsPlugins(): boolean {
167
+ return true;
168
+ }
169
+
170
+ /**
171
+ * Compile and install a plugin for Claude Code
172
+ *
173
+ * Claude uses native plugin installation:
174
+ * - Copy skills to .claude/skills/{plugin-name}/{skill-name}/
175
+ * - Copy agents to .claude/agents/{plugin-name}/{agent-name}/
176
+ * - Copy commands to .claude/commands/
177
+ *
178
+ * @param plugin Plugin to install
179
+ */
180
+ async compilePlugin(plugin: Plugin): Promise<void> {
181
+ const projectPath = process.cwd();
182
+ const claudeDir = path.join(projectPath, '.claude');
183
+
184
+ console.log(`\nđŸ“Ļ Installing plugin: ${plugin.manifest.name}`);
185
+
186
+ // Ensure base directories exist
187
+ await fs.ensureDir(path.join(claudeDir, 'skills'));
188
+ await fs.ensureDir(path.join(claudeDir, 'agents'));
189
+ await fs.ensureDir(path.join(claudeDir, 'commands'));
190
+
191
+ // Install skills
192
+ for (const skill of plugin.skills) {
193
+ const targetPath = path.join(claudeDir, 'skills', skill.name);
194
+ await fs.ensureDir(targetPath);
195
+
196
+ // Copy SKILL.md
197
+ const skillMdPath = path.join(skill.path, 'SKILL.md');
198
+ if (await fs.pathExists(skillMdPath)) {
199
+ await fs.copy(skillMdPath, path.join(targetPath, 'SKILL.md'));
200
+ }
201
+
202
+ // Copy test cases if they exist
203
+ const testCasesDir = path.join(skill.path, 'test-cases');
204
+ if (await fs.pathExists(testCasesDir)) {
205
+ await fs.copy(testCasesDir, path.join(targetPath, 'test-cases'));
206
+ }
207
+
208
+ console.log(` ✓ Skill: ${skill.name}`);
209
+ }
210
+
211
+ // Install agents
212
+ for (const agent of plugin.agents) {
213
+ const targetPath = path.join(claudeDir, 'agents', agent.name);
214
+ await fs.ensureDir(targetPath);
215
+
216
+ // Copy AGENT.md
217
+ const agentMdPath = path.join(agent.path, 'AGENT.md');
218
+ if (await fs.pathExists(agentMdPath)) {
219
+ await fs.copy(agentMdPath, path.join(targetPath, 'AGENT.md'));
220
+ }
221
+
222
+ console.log(` ✓ Agent: ${agent.name}`);
223
+ }
224
+
225
+ // Install commands
226
+ for (const command of plugin.commands) {
227
+ // Commands use their full name as filename
228
+ const fileName = command.name.replace(/\./g, '-') + '.md';
229
+ const targetPath = path.join(claudeDir, 'commands', fileName);
230
+
231
+ if (await fs.pathExists(command.path)) {
232
+ await fs.copy(command.path, targetPath);
233
+ }
234
+
235
+ console.log(` ✓ Command: /${command.name}`);
236
+ }
237
+
238
+ console.log(`\n✅ Plugin ${plugin.manifest.name} installed!`);
239
+ }
240
+
241
+ /**
242
+ * Unload a plugin from Claude Code
243
+ *
244
+ * Removes plugin files from .claude/ directory
245
+ *
246
+ * @param pluginName Name of plugin to unload
247
+ */
248
+ async unloadPlugin(pluginName: string): Promise<void> {
249
+ const projectPath = process.cwd();
250
+ const claudeDir = path.join(projectPath, '.claude');
251
+
252
+ console.log(`\nđŸ—‘ī¸ Unloading plugin: ${pluginName}`);
253
+
254
+ // Read plugin manifest to know what to remove
255
+ const pluginsDir = path.join(projectPath, 'src', 'plugins');
256
+ const pluginPath = path.join(pluginsDir, pluginName);
257
+
258
+ if (!(await fs.pathExists(pluginPath))) {
259
+ console.warn(`âš ī¸ Plugin ${pluginName} not found`);
260
+ return;
261
+ }
262
+
263
+ // Load plugin to get its components
264
+ const { PluginLoader } = await import('../../core/plugin-loader.js');
265
+ const loader = new PluginLoader();
266
+ const plugin = await loader.loadFromDirectory(pluginPath);
267
+
268
+ // Remove skills
269
+ for (const skill of plugin.skills) {
270
+ const skillPath = path.join(claudeDir, 'skills', skill.name);
271
+ if (await fs.pathExists(skillPath)) {
272
+ await fs.remove(skillPath);
273
+ console.log(` ✓ Removed skill: ${skill.name}`);
274
+ }
275
+ }
276
+
277
+ // Remove agents
278
+ for (const agent of plugin.agents) {
279
+ const agentPath = path.join(claudeDir, 'agents', agent.name);
280
+ if (await fs.pathExists(agentPath)) {
281
+ await fs.remove(agentPath);
282
+ console.log(` ✓ Removed agent: ${agent.name}`);
283
+ }
284
+ }
285
+
286
+ // Remove commands
287
+ for (const command of plugin.commands) {
288
+ const fileName = command.name.replace(/\./g, '-') + '.md';
289
+ const commandPath = path.join(claudeDir, 'commands', fileName);
290
+ if (await fs.pathExists(commandPath)) {
291
+ await fs.remove(commandPath);
292
+ console.log(` ✓ Removed command: /${command.name}`);
293
+ }
294
+ }
295
+
296
+ console.log(`\n✅ Plugin ${pluginName} unloaded!`);
297
+ }
298
+
299
+ /**
300
+ * Get list of installed plugins
301
+ *
302
+ * Returns plugin names that are currently installed in .claude/
303
+ *
304
+ * @returns Array of installed plugin names
305
+ */
306
+ async getInstalledPlugins(): Promise<string[]> {
307
+ const projectPath = process.cwd();
308
+ const configPath = path.join(projectPath, '.specweave', 'config.yaml');
309
+
310
+ if (!(await fs.pathExists(configPath))) {
311
+ return [];
312
+ }
313
+
314
+ // Read config to get enabled plugins
315
+ const yaml = await import('js-yaml');
316
+ const content = await fs.readFile(configPath, 'utf-8');
317
+ const config = yaml.load(content) as any;
318
+
319
+ return config.plugins?.enabled || [];
320
+ }
157
321
  }
@@ -11,6 +11,7 @@ import * as path from 'path';
11
11
  import fs from 'fs-extra';
12
12
  import { AdapterBase } from '../adapter-base.js';
13
13
  import { AdapterOptions, AdapterFile } from '../adapter-interface.js';
14
+ import type { Plugin } from '../../core/types/plugin.js';
14
15
 
15
16
  export class CopilotAdapter extends AdapterBase {
16
17
  name = 'copilot';
@@ -178,4 +179,141 @@ Note: For better automation, consider Claude Code (full) or Cursor (semi).
178
179
  Copilot is best for simple projects or when already using VS Code + Copilot.
179
180
  `;
180
181
  }
182
+
183
+ /**
184
+ * Check if Copilot adapter supports plugins
185
+ *
186
+ * Copilot has plugin support via AGENTS.md compilation (same as Cursor)
187
+ *
188
+ * @returns boolean True for Copilot
189
+ */
190
+ supportsPlugins(): boolean {
191
+ return true;
192
+ }
193
+
194
+ /**
195
+ * Compile and install a plugin for Copilot
196
+ *
197
+ * Copilot uses AGENTS.md compilation (same as Cursor)
198
+ *
199
+ * @param plugin Plugin to install
200
+ */
201
+ async compilePlugin(plugin: Plugin): Promise<void> {
202
+ const projectPath = process.cwd();
203
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
204
+
205
+ console.log(`\nđŸ“Ļ Compiling plugin for Copilot: ${plugin.manifest.name}`);
206
+
207
+ if (!(await fs.pathExists(agentsMdPath))) {
208
+ throw new Error('AGENTS.md not found. Run specweave init first.');
209
+ }
210
+
211
+ let agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
212
+
213
+ const pluginMarker = `<!-- Plugin: ${plugin.manifest.name} -->`;
214
+ if (agentsMd.includes(pluginMarker)) {
215
+ console.log(` â„šī¸ Plugin ${plugin.manifest.name} already compiled to AGENTS.md`);
216
+ return;
217
+ }
218
+
219
+ let pluginSection = `\n\n${pluginMarker}\n\n`;
220
+ pluginSection += `# Plugin: ${plugin.manifest.name}\n\n`;
221
+ pluginSection += `${plugin.manifest.description}\n\n`;
222
+
223
+ if (plugin.skills.length > 0) {
224
+ pluginSection += `## Skills\n\n`;
225
+ for (const skill of plugin.skills) {
226
+ const skillContent = await fs.readFile(path.join(skill.path, 'SKILL.md'), 'utf-8');
227
+ const contentWithoutFrontmatter = skillContent.replace(/^---\n[\s\S]+?\n---\n/, '');
228
+ pluginSection += `### ${skill.name}\n\n${contentWithoutFrontmatter}\n\n`;
229
+ }
230
+ }
231
+
232
+ if (plugin.agents.length > 0) {
233
+ pluginSection += `## Agents\n\n`;
234
+ for (const agent of plugin.agents) {
235
+ const agentContent = await fs.readFile(path.join(agent.path, 'AGENT.md'), 'utf-8');
236
+ pluginSection += `### ${agent.name}\n\n${agentContent}\n\n`;
237
+ }
238
+ }
239
+
240
+ if (plugin.commands.length > 0) {
241
+ pluginSection += `## Commands\n\n`;
242
+ for (const command of plugin.commands) {
243
+ const commandContent = await fs.readFile(command.path, 'utf-8');
244
+ const contentWithoutFrontmatter = commandContent.replace(/^---\n[\s\S]+?\n---\n/, '');
245
+ pluginSection += `### /${command.name}\n\n${contentWithoutFrontmatter}\n\n`;
246
+ }
247
+ }
248
+
249
+ pluginSection += `<!-- End Plugin: ${plugin.manifest.name} -->\n`;
250
+
251
+ agentsMd += pluginSection;
252
+ await fs.writeFile(agentsMdPath, agentsMd, 'utf-8');
253
+
254
+ console.log(` ✓ Compiled to AGENTS.md`);
255
+ console.log(` ✓ ${plugin.skills.length} skills, ${plugin.agents.length} agents, ${plugin.commands.length} commands`);
256
+ console.log(`\n✅ Plugin ${plugin.manifest.name} compiled for Copilot!`);
257
+ }
258
+
259
+ /**
260
+ * Unload a plugin from Copilot
261
+ */
262
+ async unloadPlugin(pluginName: string): Promise<void> {
263
+ const projectPath = process.cwd();
264
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
265
+
266
+ console.log(`\nđŸ—‘ī¸ Unloading plugin from Copilot: ${pluginName}`);
267
+
268
+ if (!(await fs.pathExists(agentsMdPath))) {
269
+ console.warn(`âš ī¸ AGENTS.md not found`);
270
+ return;
271
+ }
272
+
273
+ let agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
274
+
275
+ const startMarker = `<!-- Plugin: ${pluginName} -->`;
276
+ const endMarker = `<!-- End Plugin: ${pluginName} -->`;
277
+
278
+ const startIndex = agentsMd.indexOf(startMarker);
279
+ if (startIndex === -1) {
280
+ console.warn(`âš ī¸ Plugin ${pluginName} not found in AGENTS.md`);
281
+ return;
282
+ }
283
+
284
+ const endIndex = agentsMd.indexOf(endMarker, startIndex);
285
+ if (endIndex === -1) {
286
+ console.warn(`âš ī¸ Plugin ${pluginName} section malformed`);
287
+ return;
288
+ }
289
+
290
+ agentsMd = agentsMd.slice(0, startIndex) + agentsMd.slice(endIndex + endMarker.length);
291
+ await fs.writeFile(agentsMdPath, agentsMd, 'utf-8');
292
+
293
+ console.log(` ✓ Removed from AGENTS.md`);
294
+ console.log(`\n✅ Plugin ${pluginName} unloaded!`);
295
+ }
296
+
297
+ /**
298
+ * Get list of installed plugins for Copilot
299
+ */
300
+ async getInstalledPlugins(): Promise<string[]> {
301
+ const projectPath = process.cwd();
302
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
303
+
304
+ if (!(await fs.pathExists(agentsMdPath))) {
305
+ return [];
306
+ }
307
+
308
+ const agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
309
+ const pluginMarkerRegex = /<!-- Plugin: (specweave-[a-z0-9-]+) -->/g;
310
+ const matches = agentsMd.matchAll(pluginMarkerRegex);
311
+
312
+ const plugins: string[] = [];
313
+ for (const match of matches) {
314
+ plugins.push(match[1]);
315
+ }
316
+
317
+ return plugins;
318
+ }
181
319
  }
@@ -12,6 +12,7 @@ import * as path from 'path';
12
12
  import fs from 'fs-extra';
13
13
  import { AdapterBase } from '../adapter-base.js';
14
14
  import { AdapterOptions, AdapterFile } from '../adapter-interface.js';
15
+ import type { Plugin } from '../../core/types/plugin.js';
15
16
 
16
17
  export class CursorAdapter extends AdapterBase {
17
18
  name = 'cursor';
@@ -219,4 +220,173 @@ Pro tip: Say "act as [role]" to follow AGENTS.md patterns:
219
220
  - "act as DevOps and create infrastructure" (AGENTS.md defines DevOps role)
220
221
  `;
221
222
  }
223
+
224
+ /**
225
+ * Check if Cursor adapter supports plugins
226
+ *
227
+ * Cursor has plugin support via AGENTS.md compilation
228
+ *
229
+ * @returns boolean True for Cursor
230
+ */
231
+ supportsPlugins(): boolean {
232
+ return true;
233
+ }
234
+
235
+ /**
236
+ * Compile and install a plugin for Cursor
237
+ *
238
+ * Cursor uses AGENTS.md compilation:
239
+ * - Append skills to AGENTS.md
240
+ * - Append agents to AGENTS.md
241
+ * - Append commands to team commands JSON
242
+ *
243
+ * @param plugin Plugin to install
244
+ */
245
+ async compilePlugin(plugin: Plugin): Promise<void> {
246
+ const projectPath = process.cwd();
247
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
248
+
249
+ console.log(`\nđŸ“Ļ Compiling plugin for Cursor: ${plugin.manifest.name}`);
250
+
251
+ // Ensure AGENTS.md exists
252
+ if (!(await fs.pathExists(agentsMdPath))) {
253
+ throw new Error('AGENTS.md not found. Run specweave init first.');
254
+ }
255
+
256
+ // Read current AGENTS.md
257
+ let agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
258
+
259
+ // Check if plugin already compiled
260
+ const pluginMarker = `<!-- Plugin: ${plugin.manifest.name} -->`;
261
+ if (agentsMd.includes(pluginMarker)) {
262
+ console.log(` â„šī¸ Plugin ${plugin.manifest.name} already compiled to AGENTS.md`);
263
+ return;
264
+ }
265
+
266
+ // Generate plugin section for AGENTS.md
267
+ let pluginSection = `\n\n${pluginMarker}\n\n`;
268
+ pluginSection += `# Plugin: ${plugin.manifest.name}\n\n`;
269
+ pluginSection += `${plugin.manifest.description}\n\n`;
270
+
271
+ // Add skills
272
+ if (plugin.skills.length > 0) {
273
+ pluginSection += `## Skills\n\n`;
274
+ for (const skill of plugin.skills) {
275
+ const skillContent = await fs.readFile(path.join(skill.path, 'SKILL.md'), 'utf-8');
276
+ // Remove frontmatter for AGENTS.md
277
+ const contentWithoutFrontmatter = skillContent.replace(/^---\n[\s\S]+?\n---\n/, '');
278
+ pluginSection += `### ${skill.name}\n\n`;
279
+ pluginSection += `${contentWithoutFrontmatter}\n\n`;
280
+ }
281
+ }
282
+
283
+ // Add agents
284
+ if (plugin.agents.length > 0) {
285
+ pluginSection += `## Agents\n\n`;
286
+ for (const agent of plugin.agents) {
287
+ const agentContent = await fs.readFile(path.join(agent.path, 'AGENT.md'), 'utf-8');
288
+ pluginSection += `### ${agent.name}\n\n`;
289
+ pluginSection += `${agentContent}\n\n`;
290
+ }
291
+ }
292
+
293
+ // Add commands
294
+ if (plugin.commands.length > 0) {
295
+ pluginSection += `## Commands\n\n`;
296
+ for (const command of plugin.commands) {
297
+ const commandContent = await fs.readFile(command.path, 'utf-8');
298
+ // Remove frontmatter
299
+ const contentWithoutFrontmatter = commandContent.replace(/^---\n[\s\S]+?\n---\n/, '');
300
+ pluginSection += `### /${command.name}\n\n`;
301
+ pluginSection += `${contentWithoutFrontmatter}\n\n`;
302
+ }
303
+ }
304
+
305
+ pluginSection += `<!-- End Plugin: ${plugin.manifest.name} -->\n`;
306
+
307
+ // Append to AGENTS.md
308
+ agentsMd += pluginSection;
309
+ await fs.writeFile(agentsMdPath, agentsMd, 'utf-8');
310
+
311
+ console.log(` ✓ Compiled to AGENTS.md`);
312
+ console.log(` ✓ ${plugin.skills.length} skills added`);
313
+ console.log(` ✓ ${plugin.agents.length} agents added`);
314
+ console.log(` ✓ ${plugin.commands.length} commands added`);
315
+
316
+ console.log(`\n✅ Plugin ${plugin.manifest.name} compiled for Cursor!`);
317
+ }
318
+
319
+ /**
320
+ * Unload a plugin from Cursor
321
+ *
322
+ * Removes plugin section from AGENTS.md
323
+ *
324
+ * @param pluginName Name of plugin to unload
325
+ */
326
+ async unloadPlugin(pluginName: string): Promise<void> {
327
+ const projectPath = process.cwd();
328
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
329
+
330
+ console.log(`\nđŸ—‘ī¸ Unloading plugin from Cursor: ${pluginName}`);
331
+
332
+ if (!(await fs.pathExists(agentsMdPath))) {
333
+ console.warn(`âš ī¸ AGENTS.md not found`);
334
+ return;
335
+ }
336
+
337
+ // Read AGENTS.md
338
+ let agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
339
+
340
+ // Find plugin section
341
+ const startMarker = `<!-- Plugin: ${pluginName} -->`;
342
+ const endMarker = `<!-- End Plugin: ${pluginName} -->`;
343
+
344
+ const startIndex = agentsMd.indexOf(startMarker);
345
+ if (startIndex === -1) {
346
+ console.warn(`âš ī¸ Plugin ${pluginName} not found in AGENTS.md`);
347
+ return;
348
+ }
349
+
350
+ const endIndex = agentsMd.indexOf(endMarker, startIndex);
351
+ if (endIndex === -1) {
352
+ console.warn(`âš ī¸ Plugin ${pluginName} section malformed in AGENTS.md`);
353
+ return;
354
+ }
355
+
356
+ // Remove plugin section
357
+ agentsMd = agentsMd.slice(0, startIndex) + agentsMd.slice(endIndex + endMarker.length);
358
+
359
+ // Write back
360
+ await fs.writeFile(agentsMdPath, agentsMd, 'utf-8');
361
+
362
+ console.log(` ✓ Removed from AGENTS.md`);
363
+ console.log(`\n✅ Plugin ${pluginName} unloaded!`);
364
+ }
365
+
366
+ /**
367
+ * Get list of installed plugins for Cursor
368
+ *
369
+ * Parses AGENTS.md for plugin markers
370
+ *
371
+ * @returns Array of installed plugin names
372
+ */
373
+ async getInstalledPlugins(): Promise<string[]> {
374
+ const projectPath = process.cwd();
375
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
376
+
377
+ if (!(await fs.pathExists(agentsMdPath))) {
378
+ return [];
379
+ }
380
+
381
+ const agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
382
+ const pluginMarkerRegex = /<!-- Plugin: (specweave-[a-z0-9-]+) -->/g;
383
+ const matches = agentsMd.matchAll(pluginMarkerRegex);
384
+
385
+ const plugins: string[] = [];
386
+ for (const match of matches) {
387
+ plugins.push(match[1]);
388
+ }
389
+
390
+ return plugins;
391
+ }
222
392
  }
@@ -12,6 +12,7 @@ import * as path from 'path';
12
12
  import fs from 'fs-extra';
13
13
  import { AdapterBase } from '../adapter-base.js';
14
14
  import { AdapterOptions, AdapterFile } from '../adapter-interface.js';
15
+ import type { Plugin } from '../../core/types/plugin.js';
15
16
 
16
17
  export class GenericAdapter extends AdapterBase {
17
18
  name = 'generic';
@@ -160,4 +161,140 @@ You're ready to build with SpecWeave using ANY AI tool!
160
161
  Remember: AGENTS.md is the universal standard - it works everywhere!
161
162
  `;
162
163
  }
164
+
165
+ /**
166
+ * Check if Generic adapter supports plugins
167
+ *
168
+ * Generic has manual plugin support via AGENTS.md
169
+ *
170
+ * @returns boolean True
171
+ */
172
+ supportsPlugins(): boolean {
173
+ return true;
174
+ }
175
+
176
+ /**
177
+ * Compile and install a plugin for Generic adapter
178
+ *
179
+ * Appends plugin content to AGENTS.md for manual copy-paste workflows
180
+ *
181
+ * @param plugin Plugin to install
182
+ */
183
+ async compilePlugin(plugin: Plugin): Promise<void> {
184
+ const projectPath = process.cwd();
185
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
186
+
187
+ console.log(`\nđŸ“Ļ Adding plugin to AGENTS.md: ${plugin.manifest.name}`);
188
+
189
+ if (!(await fs.pathExists(agentsMdPath))) {
190
+ throw new Error('AGENTS.md not found. Run specweave init first.');
191
+ }
192
+
193
+ let agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
194
+
195
+ const pluginMarker = `<!-- Plugin: ${plugin.manifest.name} -->`;
196
+ if (agentsMd.includes(pluginMarker)) {
197
+ console.log(` â„šī¸ Plugin ${plugin.manifest.name} already in AGENTS.md`);
198
+ return;
199
+ }
200
+
201
+ let pluginSection = `\n\n${pluginMarker}\n\n`;
202
+ pluginSection += `# Plugin: ${plugin.manifest.name}\n\n`;
203
+ pluginSection += `${plugin.manifest.description}\n\n`;
204
+
205
+ if (plugin.skills.length > 0) {
206
+ pluginSection += `## Skills\n\n`;
207
+ for (const skill of plugin.skills) {
208
+ const skillContent = await fs.readFile(path.join(skill.path, 'SKILL.md'), 'utf-8');
209
+ const contentWithoutFrontmatter = skillContent.replace(/^---\n[\s\S]+?\n---\n/, '');
210
+ pluginSection += `### ${skill.name}\n\n${contentWithoutFrontmatter}\n\n`;
211
+ }
212
+ }
213
+
214
+ if (plugin.agents.length > 0) {
215
+ pluginSection += `## Agents\n\n`;
216
+ for (const agent of plugin.agents) {
217
+ const agentContent = await fs.readFile(path.join(agent.path, 'AGENT.md'), 'utf-8');
218
+ pluginSection += `### ${agent.name}\n\n${agentContent}\n\n`;
219
+ }
220
+ }
221
+
222
+ if (plugin.commands.length > 0) {
223
+ pluginSection += `## Workflows (Manual)\n\n`;
224
+ for (const command of plugin.commands) {
225
+ const commandContent = await fs.readFile(command.path, 'utf-8');
226
+ const contentWithoutFrontmatter = commandContent.replace(/^---\n[\s\S]+?\n---\n/, '');
227
+ pluginSection += `### ${command.name.replace('specweave.', '')}\n\n${contentWithoutFrontmatter}\n\n`;
228
+ }
229
+ }
230
+
231
+ pluginSection += `<!-- End Plugin: ${plugin.manifest.name} -->\n`;
232
+
233
+ agentsMd += pluginSection;
234
+ await fs.writeFile(agentsMdPath, agentsMd, 'utf-8');
235
+
236
+ console.log(` ✓ Added to AGENTS.md (copy-paste workflows)`);
237
+ console.log(`\n✅ Plugin ${plugin.manifest.name} available for manual use!`);
238
+ }
239
+
240
+ /**
241
+ * Unload a plugin from Generic adapter
242
+ */
243
+ async unloadPlugin(pluginName: string): Promise<void> {
244
+ const projectPath = process.cwd();
245
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
246
+
247
+ console.log(`\nđŸ—‘ī¸ Removing plugin from AGENTS.md: ${pluginName}`);
248
+
249
+ if (!(await fs.pathExists(agentsMdPath))) {
250
+ console.warn(`âš ī¸ AGENTS.md not found`);
251
+ return;
252
+ }
253
+
254
+ let agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
255
+
256
+ const startMarker = `<!-- Plugin: ${pluginName} -->`;
257
+ const endMarker = `<!-- End Plugin: ${pluginName} -->`;
258
+
259
+ const startIndex = agentsMd.indexOf(startMarker);
260
+ if (startIndex === -1) {
261
+ console.warn(`âš ī¸ Plugin ${pluginName} not found in AGENTS.md`);
262
+ return;
263
+ }
264
+
265
+ const endIndex = agentsMd.indexOf(endMarker, startIndex);
266
+ if (endIndex === -1) {
267
+ console.warn(`âš ī¸ Plugin ${pluginName} section malformed`);
268
+ return;
269
+ }
270
+
271
+ agentsMd = agentsMd.slice(0, startIndex) + agentsMd.slice(endIndex + endMarker.length);
272
+ await fs.writeFile(agentsMdPath, agentsMd, 'utf-8');
273
+
274
+ console.log(` ✓ Removed from AGENTS.md`);
275
+ console.log(`\n✅ Plugin ${pluginName} removed!`);
276
+ }
277
+
278
+ /**
279
+ * Get list of installed plugins for Generic adapter
280
+ */
281
+ async getInstalledPlugins(): Promise<string[]> {
282
+ const projectPath = process.cwd();
283
+ const agentsMdPath = path.join(projectPath, 'AGENTS.md');
284
+
285
+ if (!(await fs.pathExists(agentsMdPath))) {
286
+ return [];
287
+ }
288
+
289
+ const agentsMd = await fs.readFile(agentsMdPath, 'utf-8');
290
+ const pluginMarkerRegex = /<!-- Plugin: (specweave-[a-z0-9-]+) -->/g;
291
+ const matches = agentsMd.matchAll(pluginMarkerRegex);
292
+
293
+ const plugins: string[] = [];
294
+ for (const match of matches) {
295
+ plugins.push(match[1]);
296
+ }
297
+
298
+ return plugins;
299
+ }
163
300
  }
@@ -3,6 +3,9 @@ name: architect
3
3
  description: System Architect and technical design expert. Creates system architecture, technical specifications, Architecture Decision Records (ADRs), component designs, API contracts, data models, and deployment architectures. Handles design patterns, scalability planning, technology stack decisions, microservices architecture, event-driven systems, CQRS, domain-driven design. Activates for: architecture, system design, technical design, ADR, architecture decision record, design patterns, microservices, API design, data model, database schema, scalability, performance architecture, technology stack, tech stack selection, distributed systems, event-driven, CQRS, DDD, domain model, component architecture, integration patterns, CAP theorem, consistency, availability, partition tolerance.
4
4
  tools: Read, Write, Edit
5
5
  model: claude-sonnet-4-5-20250929
6
+ model_preference: sonnet
7
+ cost_profile: planning
8
+ fallback_behavior: strict
6
9
  ---
7
10
 
8
11
  # Architect Agent - System Architecture & Technical Design Expert