@dedesfr/prompter 0.9.0 → 1.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.
Files changed (225) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +105 -77
  3. package/dist/cli/index.js +25 -1
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +35 -9
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/login.d.ts +4 -0
  9. package/dist/commands/login.d.ts.map +1 -0
  10. package/dist/commands/login.js +56 -0
  11. package/dist/commands/login.js.map +1 -0
  12. package/dist/commands/logout.d.ts +4 -0
  13. package/dist/commands/logout.d.ts.map +1 -0
  14. package/dist/commands/logout.js +14 -0
  15. package/dist/commands/logout.js.map +1 -0
  16. package/dist/commands/update.d.ts +0 -2
  17. package/dist/commands/update.d.ts.map +1 -1
  18. package/dist/commands/update.js +19 -48
  19. package/dist/commands/update.js.map +1 -1
  20. package/dist/commands/whoami.d.ts +4 -0
  21. package/dist/commands/whoami.d.ts.map +1 -0
  22. package/dist/commands/whoami.js +42 -0
  23. package/dist/commands/whoami.js.map +1 -0
  24. package/dist/core/auth-store.d.ts +10 -0
  25. package/dist/core/auth-store.d.ts.map +1 -0
  26. package/dist/core/auth-store.js +39 -0
  27. package/dist/core/auth-store.js.map +1 -0
  28. package/dist/core/config.d.ts +0 -7
  29. package/dist/core/config.d.ts.map +1 -1
  30. package/dist/core/config.js +0 -128
  31. package/dist/core/config.js.map +1 -1
  32. package/dist/core/registry.d.ts +18 -0
  33. package/dist/core/registry.d.ts.map +1 -0
  34. package/dist/core/registry.js +94 -0
  35. package/dist/core/registry.js.map +1 -0
  36. package/package.json +7 -1
  37. package/AGENTS.md +0 -123
  38. package/CLAUDE.md +0 -17
  39. package/build.js +0 -20
  40. package/convex-setup.md +0 -403
  41. package/dist/core/prompt-templates.d.ts +0 -23
  42. package/dist/core/prompt-templates.d.ts.map +0 -1
  43. package/dist/core/prompt-templates.js +0 -3485
  44. package/dist/core/prompt-templates.js.map +0 -1
  45. package/prompt/ai-humanizer.md +0 -45
  46. package/prompt/api-contract-generator.md +0 -234
  47. package/prompt/apply.md +0 -17
  48. package/prompt/archive.md +0 -21
  49. package/prompt/design-system.md +0 -210
  50. package/prompt/document-explainer.md +0 -149
  51. package/prompt/epic-generator.md +0 -198
  52. package/prompt/epic-single.md +0 -47
  53. package/prompt/erd-generator.md +0 -130
  54. package/prompt/fsd-generator.md +0 -157
  55. package/prompt/prd-agent-generator.md +0 -147
  56. package/prompt/prd-generator.md +0 -195
  57. package/prompt/product-brief.md +0 -289
  58. package/prompt/proposal.md +0 -22
  59. package/prompt/qa-test-scenario.md +0 -133
  60. package/prompt/skill-creator.md +0 -350
  61. package/prompt/story-generator.md +0 -278
  62. package/prompt/story-single.md +0 -70
  63. package/prompt/tdd-generator.md +0 -294
  64. package/prompt/tdd-lite-generator.md +0 -224
  65. package/prompt/wireframe-generator.md +0 -219
  66. package/skills/ai-context-generator/SKILL.md +0 -54
  67. package/skills/ai-context-generator/references/AGENTS.template.md +0 -83
  68. package/skills/ai-context-generator/references/CLAUDE.template.md +0 -39
  69. package/skills/ai-context-generator/references/behavioral-guidelines.md +0 -71
  70. package/skills/ai-context-generator/references/discovery-checklist.md +0 -40
  71. package/skills/ai-context-generator/references/examples/AGENTS.good.md +0 -103
  72. package/skills/ai-context-generator/references/extraction-checklist.md +0 -23
  73. package/skills/ai-context-generator/references/overlays/laravel.md +0 -44
  74. package/skills/ai-humanizer/SKILL.md +0 -50
  75. package/skills/api-contract-generator/SKILL.md +0 -243
  76. package/skills/apply/SKILL.md +0 -23
  77. package/skills/archive/SKILL.md +0 -27
  78. package/skills/cerebro/SKILL.md +0 -187
  79. package/skills/cerebro/references/agents.md +0 -213
  80. package/skills/code-review/SKILL.md +0 -373
  81. package/skills/code-review/assets/report-template-agent.md +0 -212
  82. package/skills/code-review/assets/report-template-compact.md +0 -81
  83. package/skills/code-review/assets/report-template-full.md +0 -264
  84. package/skills/code-review/assets/report-template-human.md +0 -168
  85. package/skills/code-review/references/universal-patterns.md +0 -495
  86. package/skills/design-md/README.md +0 -34
  87. package/skills/design-md/SKILL.md +0 -172
  88. package/skills/design-md/examples/DESIGN.md +0 -154
  89. package/skills/design-system/SKILL.md +0 -216
  90. package/skills/design-system-generator/SKILL.md +0 -324
  91. package/skills/design-system-generator/assets/design-system-template.md +0 -348
  92. package/skills/design-system-generator/references/extraction-patterns.md +0 -321
  93. package/skills/doc-builder/SKILL.md +0 -115
  94. package/skills/doc-builder/references/ui-patterns.md +0 -394
  95. package/skills/document-explainer/SKILL.md +0 -155
  96. package/skills/document-translator/SKILL.md +0 -58
  97. package/skills/enhance/SKILL.md +0 -47
  98. package/skills/enhance-prompt/README.md +0 -34
  99. package/skills/enhance-prompt/SKILL.md +0 -204
  100. package/skills/enhance-prompt/references/KEYWORDS.md +0 -114
  101. package/skills/epic-generator/SKILL.md +0 -204
  102. package/skills/epic-single/SKILL.md +0 -63
  103. package/skills/erd-generator/SKILL.md +0 -138
  104. package/skills/feature-planner/SKILL.md +0 -305
  105. package/skills/feature-planner/assets/implementation-plan-template.md +0 -85
  106. package/skills/frontend-design/LICENSE.txt +0 -177
  107. package/skills/frontend-design/SKILL.md +0 -42
  108. package/skills/fsd-generator/SKILL.md +0 -163
  109. package/skills/gamma-builder/SKILL.md +0 -134
  110. package/skills/laravel-code-review/SKILL.md +0 -383
  111. package/skills/laravel-code-review/assets/report-template-agent.md +0 -195
  112. package/skills/laravel-code-review/assets/report-template-compact.md +0 -79
  113. package/skills/laravel-code-review/assets/report-template-full.md +0 -253
  114. package/skills/laravel-code-review/assets/report-template-human.md +0 -159
  115. package/skills/laravel-code-review/references/laravel-patterns.md +0 -571
  116. package/skills/laravel-code-review/references/php84-features.md +0 -442
  117. package/skills/mcp-builder/LICENSE.txt +0 -202
  118. package/skills/mcp-builder/SKILL.md +0 -236
  119. package/skills/mcp-builder/reference/evaluation.md +0 -602
  120. package/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  121. package/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  122. package/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  123. package/skills/mcp-builder/scripts/connections.py +0 -151
  124. package/skills/mcp-builder/scripts/evaluation.py +0 -373
  125. package/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  126. package/skills/mcp-builder/scripts/requirements.txt +0 -2
  127. package/skills/meeting-notes/SKILL.md +0 -159
  128. package/skills/meeting-notes/evals/evals.json +0 -23
  129. package/skills/prd-agent-generator/SKILL.md +0 -132
  130. package/skills/prd-generator/SKILL.md +0 -211
  131. package/skills/product-brief/SKILL.md +0 -141
  132. package/skills/project-orchestrator/SKILL.md +0 -487
  133. package/skills/project-orchestrator/assets/caddy-vps-setup.md +0 -180
  134. package/skills/project-orchestrator/assets/plan-summary-template.md +0 -159
  135. package/skills/prompter-specs/SKILL.md +0 -115
  136. package/skills/prompter-workflow/SKILL.md +0 -166
  137. package/skills/prompter-workflow/evals/evals.json +0 -89
  138. package/skills/proposal/SKILL.md +0 -28
  139. package/skills/qa-test-scenario/SKILL.md +0 -149
  140. package/skills/skill-creator/SKILL.md +0 -173
  141. package/skills/sph-generator/SKILL.md +0 -488
  142. package/skills/story-generator/SKILL.md +0 -285
  143. package/skills/story-single/SKILL.md +0 -86
  144. package/skills/tdd-generator/SKILL.md +0 -300
  145. package/skills/tdd-lite-generator/SKILL.md +0 -230
  146. package/skills/ui-ux-pro/SKILL.md +0 -199
  147. package/skills/ui-ux-pro/assets/design-spec-template.md +0 -173
  148. package/skills/ui-ux-pro/references/component-patterns.md +0 -255
  149. package/skills/ui-ux-pro/references/design-principles.md +0 -167
  150. package/skills/wireframe-generator/SKILL.md +0 -227
  151. package/src/cli/index.ts +0 -223
  152. package/src/commands/archive.ts +0 -302
  153. package/src/commands/change.ts +0 -292
  154. package/src/commands/config.ts +0 -233
  155. package/src/commands/guide.ts +0 -50
  156. package/src/commands/init.ts +0 -597
  157. package/src/commands/list.ts +0 -194
  158. package/src/commands/show.ts +0 -138
  159. package/src/commands/spec.ts +0 -251
  160. package/src/commands/update.ts +0 -129
  161. package/src/commands/upgrade.ts +0 -30
  162. package/src/commands/validate.ts +0 -326
  163. package/src/core/artifact-graph/graph.ts +0 -167
  164. package/src/core/artifact-graph/index.ts +0 -44
  165. package/src/core/artifact-graph/instruction-loader.ts +0 -302
  166. package/src/core/artifact-graph/resolver.ts +0 -226
  167. package/src/core/artifact-graph/schema.ts +0 -124
  168. package/src/core/artifact-graph/state.ts +0 -64
  169. package/src/core/artifact-graph/types.ts +0 -65
  170. package/src/core/completions/command-registry.ts +0 -382
  171. package/src/core/completions/completion-provider.ts +0 -128
  172. package/src/core/completions/generators/bash-generator.ts +0 -191
  173. package/src/core/completions/generators/fish-generator.ts +0 -188
  174. package/src/core/completions/generators/powershell-generator.ts +0 -223
  175. package/src/core/completions/generators/zsh-generator.ts +0 -281
  176. package/src/core/completions/templates/bash-templates.ts +0 -24
  177. package/src/core/completions/templates/fish-templates.ts +0 -40
  178. package/src/core/completions/templates/powershell-templates.ts +0 -25
  179. package/src/core/completions/templates/zsh-templates.ts +0 -36
  180. package/src/core/completions/types.ts +0 -90
  181. package/src/core/config-schema.ts +0 -230
  182. package/src/core/config.ts +0 -181
  183. package/src/core/configurators/slash/antigravity.ts +0 -10
  184. package/src/core/configurators/slash/base.ts +0 -109
  185. package/src/core/configurators/slash/claude.ts +0 -10
  186. package/src/core/configurators/slash/codex.ts +0 -10
  187. package/src/core/configurators/slash/droid.ts +0 -10
  188. package/src/core/configurators/slash/forge.ts +0 -10
  189. package/src/core/configurators/slash/github-copilot.ts +0 -10
  190. package/src/core/configurators/slash/index.ts +0 -10
  191. package/src/core/configurators/slash/kilocode.ts +0 -10
  192. package/src/core/configurators/slash/opencode.ts +0 -10
  193. package/src/core/configurators/slash/registry.ts +0 -51
  194. package/src/core/converters/json-converter.ts +0 -62
  195. package/src/core/global-config.ts +0 -136
  196. package/src/core/parsers/change-parser.ts +0 -234
  197. package/src/core/parsers/markdown-parser.ts +0 -237
  198. package/src/core/parsers/requirement-blocks.ts +0 -234
  199. package/src/core/prompt-templates.ts +0 -3504
  200. package/src/core/schemas/base.schema.ts +0 -20
  201. package/src/core/schemas/change.schema.ts +0 -42
  202. package/src/core/schemas/index.ts +0 -20
  203. package/src/core/schemas/spec.schema.ts +0 -17
  204. package/src/core/skill-discovery.ts +0 -68
  205. package/src/core/specs-apply.ts +0 -483
  206. package/src/core/styles/palette.ts +0 -8
  207. package/src/core/templates/agents-template.ts +0 -459
  208. package/src/core/templates/claude-template.ts +0 -2
  209. package/src/core/templates/index.ts +0 -3
  210. package/src/core/templates/project-template.ts +0 -32
  211. package/src/core/validation/constants.ts +0 -48
  212. package/src/core/validation/types.ts +0 -19
  213. package/src/core/validation/validator.ts +0 -449
  214. package/src/core/view.ts +0 -219
  215. package/src/index.ts +0 -1
  216. package/src/utils/change-metadata.ts +0 -171
  217. package/src/utils/change-utils.ts +0 -131
  218. package/src/utils/file-system.ts +0 -252
  219. package/src/utils/index.ts +0 -12
  220. package/src/utils/interactive.ts +0 -29
  221. package/src/utils/item-discovery.ts +0 -66
  222. package/src/utils/match.ts +0 -26
  223. package/src/utils/shell-detection.ts +0 -62
  224. package/src/utils/task-progress.ts +0 -43
  225. package/tsconfig.json +0 -28
@@ -1,302 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import { getSchemaDir, resolveSchema } from './resolver.js';
4
- import { ArtifactGraph } from './graph.js';
5
- import { detectCompleted } from './state.js';
6
- import { resolveSchemaForChange } from '../../utils/change-metadata.js';
7
- import type { Artifact, CompletedSet } from './types.js';
8
-
9
- /**
10
- * Error thrown when loading a template fails.
11
- */
12
- export class TemplateLoadError extends Error {
13
- constructor(
14
- message: string,
15
- public readonly templatePath: string
16
- ) {
17
- super(message);
18
- this.name = 'TemplateLoadError';
19
- }
20
- }
21
-
22
- /**
23
- * Change context containing graph, completion state, and metadata.
24
- */
25
- export interface ChangeContext {
26
- /** The artifact dependency graph */
27
- graph: ArtifactGraph;
28
- /** Set of completed artifact IDs */
29
- completed: CompletedSet;
30
- /** Schema name being used */
31
- schemaName: string;
32
- /** Change name */
33
- changeName: string;
34
- /** Path to the change directory */
35
- changeDir: string;
36
- }
37
-
38
- /**
39
- * Enriched instructions for creating an artifact.
40
- */
41
- export interface ArtifactInstructions {
42
- /** Change name */
43
- changeName: string;
44
- /** Artifact ID */
45
- artifactId: string;
46
- /** Schema name */
47
- schemaName: string;
48
- /** Full path to change directory */
49
- changeDir: string;
50
- /** Output path pattern (e.g., "proposal.md") */
51
- outputPath: string;
52
- /** Artifact description */
53
- description: string;
54
- /** Guidance on how to create this artifact (from schema instruction field) */
55
- instruction: string | undefined;
56
- /** Template content (structure to follow) */
57
- template: string;
58
- /** Dependencies with completion status and paths */
59
- dependencies: DependencyInfo[];
60
- /** Artifacts that become available after completing this one */
61
- unlocks: string[];
62
- }
63
-
64
- /**
65
- * Dependency information including path and description.
66
- */
67
- export interface DependencyInfo {
68
- /** Artifact ID */
69
- id: string;
70
- /** Whether the dependency is completed */
71
- done: boolean;
72
- /** Relative output path of the dependency (e.g., "proposal.md") */
73
- path: string;
74
- /** Description of the dependency artifact */
75
- description: string;
76
- }
77
-
78
- /**
79
- * Status of a single artifact in the workflow.
80
- */
81
- export interface ArtifactStatus {
82
- /** Artifact ID */
83
- id: string;
84
- /** Output path pattern */
85
- outputPath: string;
86
- /** Status: done, ready, or blocked */
87
- status: 'done' | 'ready' | 'blocked';
88
- /** Missing dependencies (only for blocked) */
89
- missingDeps?: string[];
90
- }
91
-
92
- /**
93
- * Formatted change status.
94
- */
95
- export interface ChangeStatus {
96
- /** Change name */
97
- changeName: string;
98
- /** Schema name */
99
- schemaName: string;
100
- /** Whether all artifacts are complete */
101
- isComplete: boolean;
102
- /** Artifact IDs required before apply phase (from schema's apply.requires) */
103
- applyRequires: string[];
104
- /** Status of each artifact */
105
- artifacts: ArtifactStatus[];
106
- }
107
-
108
- /**
109
- * Loads a template from a schema's templates directory.
110
- *
111
- * @param schemaName - Schema name (e.g., "spec-driven")
112
- * @param templatePath - Relative path within the templates directory (e.g., "proposal.md")
113
- * @returns The template content
114
- * @throws TemplateLoadError if the template cannot be loaded
115
- */
116
- export function loadTemplate(schemaName: string, templatePath: string): string {
117
- const schemaDir = getSchemaDir(schemaName);
118
- if (!schemaDir) {
119
- throw new TemplateLoadError(
120
- `Schema '${schemaName}' not found`,
121
- templatePath
122
- );
123
- }
124
-
125
- const fullPath = path.join(schemaDir, 'templates', templatePath);
126
-
127
- if (!fs.existsSync(fullPath)) {
128
- throw new TemplateLoadError(
129
- `Template not found: ${fullPath}`,
130
- fullPath
131
- );
132
- }
133
-
134
- try {
135
- return fs.readFileSync(fullPath, 'utf-8');
136
- } catch (err) {
137
- const ioError = err instanceof Error ? err : new Error(String(err));
138
- throw new TemplateLoadError(
139
- `Failed to read template: ${ioError.message}`,
140
- fullPath
141
- );
142
- }
143
- }
144
-
145
- /**
146
- * Loads change context combining graph and completion state.
147
- *
148
- * Schema resolution order:
149
- * 1. Explicit schemaName parameter (if provided)
150
- * 2. Schema from .prompter.yaml metadata (if exists in change directory)
151
- * 3. Default 'spec-driven'
152
- *
153
- * @param projectRoot - Project root directory
154
- * @param changeName - Change name
155
- * @param schemaName - Optional schema name override. If not provided, auto-detected from metadata.
156
- * @returns Change context with graph, completed set, and metadata
157
- */
158
- export function loadChangeContext(
159
- projectRoot: string,
160
- changeName: string,
161
- schemaName?: string
162
- ): ChangeContext {
163
- const changeDir = path.join(projectRoot, 'prompter', 'changes', changeName);
164
-
165
- // Resolve schema: explicit > metadata > default
166
- const resolvedSchemaName = resolveSchemaForChange(changeDir, schemaName);
167
-
168
- const schema = resolveSchema(resolvedSchemaName);
169
- const graph = ArtifactGraph.fromSchema(schema);
170
- const completed = detectCompleted(graph, changeDir);
171
-
172
- return {
173
- graph,
174
- completed,
175
- schemaName: resolvedSchemaName,
176
- changeName,
177
- changeDir,
178
- };
179
- }
180
-
181
- /**
182
- * Generates enriched instructions for creating an artifact.
183
- *
184
- * @param context - Change context
185
- * @param artifactId - Artifact ID to generate instructions for
186
- * @returns Enriched artifact instructions
187
- * @throws Error if artifact not found
188
- */
189
- export function generateInstructions(
190
- context: ChangeContext,
191
- artifactId: string
192
- ): ArtifactInstructions {
193
- const artifact = context.graph.getArtifact(artifactId);
194
- if (!artifact) {
195
- throw new Error(`Artifact '${artifactId}' not found in schema '${context.schemaName}'`);
196
- }
197
-
198
- const template = loadTemplate(context.schemaName, artifact.template);
199
- const dependencies = getDependencyInfo(artifact, context.graph, context.completed);
200
- const unlocks = getUnlockedArtifacts(context.graph, artifactId);
201
-
202
- return {
203
- changeName: context.changeName,
204
- artifactId: artifact.id,
205
- schemaName: context.schemaName,
206
- changeDir: context.changeDir,
207
- outputPath: artifact.generates,
208
- description: artifact.description,
209
- instruction: artifact.instruction,
210
- template,
211
- dependencies,
212
- unlocks,
213
- };
214
- }
215
-
216
- /**
217
- * Gets dependency info including paths and descriptions.
218
- */
219
- function getDependencyInfo(
220
- artifact: Artifact,
221
- graph: ArtifactGraph,
222
- completed: CompletedSet
223
- ): DependencyInfo[] {
224
- return artifact.requires.map(id => {
225
- const depArtifact = graph.getArtifact(id);
226
- return {
227
- id,
228
- done: completed.has(id),
229
- path: depArtifact?.generates ?? id,
230
- description: depArtifact?.description ?? '',
231
- };
232
- });
233
- }
234
-
235
- /**
236
- * Gets artifacts that become available after completing the given artifact.
237
- */
238
- function getUnlockedArtifacts(graph: ArtifactGraph, artifactId: string): string[] {
239
- const unlocks: string[] = [];
240
-
241
- for (const artifact of graph.getAllArtifacts()) {
242
- if (artifact.requires.includes(artifactId)) {
243
- unlocks.push(artifact.id);
244
- }
245
- }
246
-
247
- return unlocks.sort();
248
- }
249
-
250
- /**
251
- * Formats the status of all artifacts in a change.
252
- *
253
- * @param context - Change context
254
- * @returns Formatted change status
255
- */
256
- export function formatChangeStatus(context: ChangeContext): ChangeStatus {
257
- // Load schema to get apply phase configuration
258
- const schema = resolveSchema(context.schemaName);
259
- const applyRequires = schema.apply?.requires ?? schema.artifacts.map(a => a.id);
260
-
261
- const artifacts = context.graph.getAllArtifacts();
262
- const ready = new Set(context.graph.getNextArtifacts(context.completed));
263
- const blocked = context.graph.getBlocked(context.completed);
264
-
265
- const artifactStatuses: ArtifactStatus[] = artifacts.map(artifact => {
266
- if (context.completed.has(artifact.id)) {
267
- return {
268
- id: artifact.id,
269
- outputPath: artifact.generates,
270
- status: 'done' as const,
271
- };
272
- }
273
-
274
- if (ready.has(artifact.id)) {
275
- return {
276
- id: artifact.id,
277
- outputPath: artifact.generates,
278
- status: 'ready' as const,
279
- };
280
- }
281
-
282
- return {
283
- id: artifact.id,
284
- outputPath: artifact.generates,
285
- status: 'blocked' as const,
286
- missingDeps: blocked[artifact.id] ?? [],
287
- };
288
- });
289
-
290
- // Sort by build order for consistent output
291
- const buildOrder = context.graph.getBuildOrder();
292
- const orderMap = new Map(buildOrder.map((id, idx) => [id, idx]));
293
- artifactStatuses.sort((a, b) => (orderMap.get(a.id) ?? 0) - (orderMap.get(b.id) ?? 0));
294
-
295
- return {
296
- changeName: context.changeName,
297
- schemaName: context.schemaName,
298
- isComplete: context.graph.isComplete(context.completed),
299
- applyRequires,
300
- artifacts: artifactStatuses,
301
- };
302
- }
@@ -1,226 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { getGlobalDataDir } from '../global-config.js';
5
- import { parseSchema, SchemaValidationError } from './schema.js';
6
- import type { SchemaYaml } from './types.js';
7
-
8
- /**
9
- * Error thrown when loading a schema fails.
10
- */
11
- export class SchemaLoadError extends Error {
12
- constructor(
13
- message: string,
14
- public readonly schemaPath: string,
15
- public readonly cause?: Error
16
- ) {
17
- super(message);
18
- this.name = 'SchemaLoadError';
19
- }
20
- }
21
-
22
- /**
23
- * Gets the package's built-in schemas directory path.
24
- * Uses import.meta.url to resolve relative to the current module.
25
- */
26
- export function getPackageSchemasDir(): string {
27
- const currentFile = fileURLToPath(import.meta.url);
28
- // Navigate from dist/core/artifact-graph/ to package root's schemas/
29
- return path.join(path.dirname(currentFile), '..', '..', '..', 'schemas');
30
- }
31
-
32
- /**
33
- * Gets the user's schema override directory path.
34
- */
35
- export function getUserSchemasDir(): string {
36
- return path.join(getGlobalDataDir(), 'schemas');
37
- }
38
-
39
- /**
40
- * Resolves a schema name to its directory path.
41
- *
42
- * Resolution order:
43
- * 1. User override: ${XDG_DATA_HOME}/prompter/schemas/<name>/schema.yaml
44
- * 2. Package built-in: <package>/schemas/<name>/schema.yaml
45
- *
46
- * @param name - Schema name (e.g., "spec-driven")
47
- * @returns The path to the schema directory, or null if not found
48
- */
49
- export function getSchemaDir(name: string): string | null {
50
- // 1. Check user override directory
51
- const userDir = path.join(getUserSchemasDir(), name);
52
- const userSchemaPath = path.join(userDir, 'schema.yaml');
53
- if (fs.existsSync(userSchemaPath)) {
54
- return userDir;
55
- }
56
-
57
- // 2. Check package built-in directory
58
- const packageDir = path.join(getPackageSchemasDir(), name);
59
- const packageSchemaPath = path.join(packageDir, 'schema.yaml');
60
- if (fs.existsSync(packageSchemaPath)) {
61
- return packageDir;
62
- }
63
-
64
- return null;
65
- }
66
-
67
- /**
68
- * Resolves a schema name to a SchemaYaml object.
69
- *
70
- * Resolution order:
71
- * 1. User override: ${XDG_DATA_HOME}/prompter/schemas/<name>/schema.yaml
72
- * 2. Package built-in: <package>/schemas/<name>/schema.yaml
73
- *
74
- * @param name - Schema name (e.g., "spec-driven")
75
- * @returns The resolved schema object
76
- * @throws Error if schema is not found in any location
77
- */
78
- export function resolveSchema(name: string): SchemaYaml {
79
- // Normalize name (remove .yaml extension if provided)
80
- const normalizedName = name.replace(/\.ya?ml$/, '');
81
-
82
- const schemaDir = getSchemaDir(normalizedName);
83
- if (!schemaDir) {
84
- const availableSchemas = listSchemas();
85
- throw new Error(
86
- `Schema '${normalizedName}' not found. Available schemas: ${availableSchemas.join(', ')}`
87
- );
88
- }
89
-
90
- const schemaPath = path.join(schemaDir, 'schema.yaml');
91
-
92
- // Load and parse the schema
93
- let content: string;
94
- try {
95
- content = fs.readFileSync(schemaPath, 'utf-8');
96
- } catch (err) {
97
- const ioError = err instanceof Error ? err : new Error(String(err));
98
- throw new SchemaLoadError(
99
- `Failed to read schema at '${schemaPath}': ${ioError.message}`,
100
- schemaPath,
101
- ioError
102
- );
103
- }
104
-
105
- try {
106
- return parseSchema(content);
107
- } catch (err) {
108
- if (err instanceof SchemaValidationError) {
109
- throw new SchemaLoadError(
110
- `Invalid schema at '${schemaPath}': ${err.message}`,
111
- schemaPath,
112
- err
113
- );
114
- }
115
- const parseError = err instanceof Error ? err : new Error(String(err));
116
- throw new SchemaLoadError(
117
- `Failed to parse schema at '${schemaPath}': ${parseError.message}`,
118
- schemaPath,
119
- parseError
120
- );
121
- }
122
- }
123
-
124
- /**
125
- * Lists all available schema names.
126
- * Combines user override and package built-in schemas.
127
- */
128
- export function listSchemas(): string[] {
129
- const schemas = new Set<string>();
130
-
131
- // Add package built-in schemas
132
- const packageDir = getPackageSchemasDir();
133
- if (fs.existsSync(packageDir)) {
134
- for (const entry of fs.readdirSync(packageDir, { withFileTypes: true })) {
135
- if (entry.isDirectory()) {
136
- const schemaPath = path.join(packageDir, entry.name, 'schema.yaml');
137
- if (fs.existsSync(schemaPath)) {
138
- schemas.add(entry.name);
139
- }
140
- }
141
- }
142
- }
143
-
144
- // Add user override schemas (may override package schemas)
145
- const userDir = getUserSchemasDir();
146
- if (fs.existsSync(userDir)) {
147
- for (const entry of fs.readdirSync(userDir, { withFileTypes: true })) {
148
- if (entry.isDirectory()) {
149
- const schemaPath = path.join(userDir, entry.name, 'schema.yaml');
150
- if (fs.existsSync(schemaPath)) {
151
- schemas.add(entry.name);
152
- }
153
- }
154
- }
155
- }
156
-
157
- return Array.from(schemas).sort();
158
- }
159
-
160
- /**
161
- * Schema info with metadata (name, description, artifacts).
162
- */
163
- export interface SchemaInfo {
164
- name: string;
165
- description: string;
166
- artifacts: string[];
167
- source: 'package' | 'user';
168
- }
169
-
170
- /**
171
- * Lists all available schemas with their descriptions and artifact lists.
172
- * Useful for agent skills to present schema selection to users.
173
- */
174
- export function listSchemasWithInfo(): SchemaInfo[] {
175
- const schemas: SchemaInfo[] = [];
176
- const seenNames = new Set<string>();
177
-
178
- // Add user override schemas first (they take precedence)
179
- const userDir = getUserSchemasDir();
180
- if (fs.existsSync(userDir)) {
181
- for (const entry of fs.readdirSync(userDir, { withFileTypes: true })) {
182
- if (entry.isDirectory()) {
183
- const schemaPath = path.join(userDir, entry.name, 'schema.yaml');
184
- if (fs.existsSync(schemaPath)) {
185
- try {
186
- const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
187
- schemas.push({
188
- name: entry.name,
189
- description: schema.description || '',
190
- artifacts: schema.artifacts.map((a) => a.id),
191
- source: 'user',
192
- });
193
- seenNames.add(entry.name);
194
- } catch {
195
- // Skip invalid schemas
196
- }
197
- }
198
- }
199
- }
200
- }
201
-
202
- // Add package built-in schemas (if not overridden)
203
- const packageDir = getPackageSchemasDir();
204
- if (fs.existsSync(packageDir)) {
205
- for (const entry of fs.readdirSync(packageDir, { withFileTypes: true })) {
206
- if (entry.isDirectory() && !seenNames.has(entry.name)) {
207
- const schemaPath = path.join(packageDir, entry.name, 'schema.yaml');
208
- if (fs.existsSync(schemaPath)) {
209
- try {
210
- const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
211
- schemas.push({
212
- name: entry.name,
213
- description: schema.description || '',
214
- artifacts: schema.artifacts.map((a) => a.id),
215
- source: 'package',
216
- });
217
- } catch {
218
- // Skip invalid schemas
219
- }
220
- }
221
- }
222
- }
223
- }
224
-
225
- return schemas.sort((a, b) => a.name.localeCompare(b.name));
226
- }
@@ -1,124 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import { parse as parseYaml } from 'yaml';
3
- import { SchemaYamlSchema, type SchemaYaml, type Artifact } from './types.js';
4
-
5
- export class SchemaValidationError extends Error {
6
- constructor(message: string) {
7
- super(message);
8
- this.name = 'SchemaValidationError';
9
- }
10
- }
11
-
12
- /**
13
- * Loads and validates an artifact schema from a YAML file.
14
- */
15
- export function loadSchema(filePath: string): SchemaYaml {
16
- const content = fs.readFileSync(filePath, 'utf-8');
17
- return parseSchema(content);
18
- }
19
-
20
- /**
21
- * Parses and validates an artifact schema from YAML content.
22
- */
23
- export function parseSchema(yamlContent: string): SchemaYaml {
24
- const parsed = parseYaml(yamlContent);
25
-
26
- // Validate with Zod
27
- const result = SchemaYamlSchema.safeParse(parsed);
28
- if (!result.success) {
29
- const errors = result.error.issues.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
30
- throw new SchemaValidationError(`Invalid schema: ${errors}`);
31
- }
32
-
33
- const schema = result.data;
34
-
35
- // Check for duplicate artifact IDs
36
- validateNoDuplicateIds(schema.artifacts);
37
-
38
- // Check that all requires references are valid
39
- validateRequiresReferences(schema.artifacts);
40
-
41
- // Check for cycles
42
- validateNoCycles(schema.artifacts);
43
-
44
- return schema;
45
- }
46
-
47
- /**
48
- * Validates that there are no duplicate artifact IDs.
49
- */
50
- function validateNoDuplicateIds(artifacts: Artifact[]): void {
51
- const seen = new Set<string>();
52
- for (const artifact of artifacts) {
53
- if (seen.has(artifact.id)) {
54
- throw new SchemaValidationError(`Duplicate artifact ID: ${artifact.id}`);
55
- }
56
- seen.add(artifact.id);
57
- }
58
- }
59
-
60
- /**
61
- * Validates that all `requires` references point to valid artifact IDs.
62
- */
63
- function validateRequiresReferences(artifacts: Artifact[]): void {
64
- const validIds = new Set(artifacts.map(a => a.id));
65
-
66
- for (const artifact of artifacts) {
67
- for (const req of artifact.requires) {
68
- if (!validIds.has(req)) {
69
- throw new SchemaValidationError(
70
- `Invalid dependency reference in artifact '${artifact.id}': '${req}' does not exist`
71
- );
72
- }
73
- }
74
- }
75
- }
76
-
77
- /**
78
- * Validates that there are no cyclic dependencies.
79
- * Uses DFS to detect cycles and reports the full cycle path.
80
- */
81
- function validateNoCycles(artifacts: Artifact[]): void {
82
- const artifactMap = new Map(artifacts.map(a => [a.id, a]));
83
- const visited = new Set<string>();
84
- const inStack = new Set<string>();
85
- const parent = new Map<string, string>();
86
-
87
- function dfs(id: string): string | null {
88
- visited.add(id);
89
- inStack.add(id);
90
-
91
- const artifact = artifactMap.get(id);
92
- if (!artifact) return null;
93
-
94
- for (const dep of artifact.requires) {
95
- if (!visited.has(dep)) {
96
- parent.set(dep, id);
97
- const cycle = dfs(dep);
98
- if (cycle) return cycle;
99
- } else if (inStack.has(dep)) {
100
- // Found a cycle - reconstruct the path
101
- const cyclePath = [dep];
102
- let current = id;
103
- while (current !== dep) {
104
- cyclePath.unshift(current);
105
- current = parent.get(current)!;
106
- }
107
- cyclePath.unshift(dep);
108
- return cyclePath.join(' → ');
109
- }
110
- }
111
-
112
- inStack.delete(id);
113
- return null;
114
- }
115
-
116
- for (const artifact of artifacts) {
117
- if (!visited.has(artifact.id)) {
118
- const cycle = dfs(artifact.id);
119
- if (cycle) {
120
- throw new SchemaValidationError(`Cyclic dependency detected: ${cycle}`);
121
- }
122
- }
123
- }
124
- }
@@ -1,64 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import fg from 'fast-glob';
4
- import type { CompletedSet } from './types.js';
5
- import type { ArtifactGraph } from './graph.js';
6
- import { FileSystemUtils } from '../../utils/file-system.js';
7
-
8
- /**
9
- * Detects which artifacts are completed by checking file existence in the change directory.
10
- * Returns a Set of completed artifact IDs.
11
- *
12
- * @param graph - The artifact graph to check
13
- * @param changeDir - The change directory to scan for files
14
- * @returns Set of artifact IDs whose generated files exist
15
- */
16
- export function detectCompleted(graph: ArtifactGraph, changeDir: string): CompletedSet {
17
- const completed = new Set<string>();
18
-
19
- // Handle missing change directory gracefully
20
- if (!fs.existsSync(changeDir)) {
21
- return completed;
22
- }
23
-
24
- for (const artifact of graph.getAllArtifacts()) {
25
- if (isArtifactComplete(artifact.generates, changeDir)) {
26
- completed.add(artifact.id);
27
- }
28
- }
29
-
30
- return completed;
31
- }
32
-
33
- /**
34
- * Checks if an artifact is complete by checking if its generated file(s) exist.
35
- * Supports both simple paths and glob patterns.
36
- */
37
- function isArtifactComplete(generates: string, changeDir: string): boolean {
38
- const fullPattern = path.join(changeDir, generates);
39
-
40
- // Check if it's a glob pattern
41
- if (isGlobPattern(generates)) {
42
- return hasGlobMatches(fullPattern);
43
- }
44
-
45
- // Simple file path - check if file exists
46
- return fs.existsSync(fullPattern);
47
- }
48
-
49
- /**
50
- * Checks if a path contains glob pattern characters.
51
- */
52
- function isGlobPattern(pattern: string): boolean {
53
- return pattern.includes('*') || pattern.includes('?') || pattern.includes('[');
54
- }
55
-
56
- /**
57
- * Checks if a glob pattern has any matches.
58
- * Normalizes Windows backslashes to forward slashes for cross-platform glob compatibility.
59
- */
60
- function hasGlobMatches(pattern: string): boolean {
61
- const normalizedPattern = FileSystemUtils.toPosixPath(pattern);
62
- const matches = fg.sync(normalizedPattern, { onlyFiles: true });
63
- return matches.length > 0;
64
- }