@dedesfr/prompter 0.9.0 → 1.0.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 (216) hide show
  1. package/CHANGELOG.md +21 -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 +32 -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.map +1 -1
  17. package/dist/commands/update.js +18 -5
  18. package/dist/commands/update.js.map +1 -1
  19. package/dist/commands/whoami.d.ts +4 -0
  20. package/dist/commands/whoami.d.ts.map +1 -0
  21. package/dist/commands/whoami.js +42 -0
  22. package/dist/commands/whoami.js.map +1 -0
  23. package/dist/core/auth-store.d.ts +10 -0
  24. package/dist/core/auth-store.d.ts.map +1 -0
  25. package/dist/core/auth-store.js +39 -0
  26. package/dist/core/auth-store.js.map +1 -0
  27. package/dist/core/registry.d.ts +18 -0
  28. package/dist/core/registry.d.ts.map +1 -0
  29. package/dist/core/registry.js +94 -0
  30. package/dist/core/registry.js.map +1 -0
  31. package/package.json +7 -1
  32. package/AGENTS.md +0 -123
  33. package/CLAUDE.md +0 -17
  34. package/build.js +0 -20
  35. package/convex-setup.md +0 -403
  36. package/prompt/ai-humanizer.md +0 -45
  37. package/prompt/api-contract-generator.md +0 -234
  38. package/prompt/apply.md +0 -17
  39. package/prompt/archive.md +0 -21
  40. package/prompt/design-system.md +0 -210
  41. package/prompt/document-explainer.md +0 -149
  42. package/prompt/epic-generator.md +0 -198
  43. package/prompt/epic-single.md +0 -47
  44. package/prompt/erd-generator.md +0 -130
  45. package/prompt/fsd-generator.md +0 -157
  46. package/prompt/prd-agent-generator.md +0 -147
  47. package/prompt/prd-generator.md +0 -195
  48. package/prompt/product-brief.md +0 -289
  49. package/prompt/proposal.md +0 -22
  50. package/prompt/qa-test-scenario.md +0 -133
  51. package/prompt/skill-creator.md +0 -350
  52. package/prompt/story-generator.md +0 -278
  53. package/prompt/story-single.md +0 -70
  54. package/prompt/tdd-generator.md +0 -294
  55. package/prompt/tdd-lite-generator.md +0 -224
  56. package/prompt/wireframe-generator.md +0 -219
  57. package/skills/ai-context-generator/SKILL.md +0 -54
  58. package/skills/ai-context-generator/references/AGENTS.template.md +0 -83
  59. package/skills/ai-context-generator/references/CLAUDE.template.md +0 -39
  60. package/skills/ai-context-generator/references/behavioral-guidelines.md +0 -71
  61. package/skills/ai-context-generator/references/discovery-checklist.md +0 -40
  62. package/skills/ai-context-generator/references/examples/AGENTS.good.md +0 -103
  63. package/skills/ai-context-generator/references/extraction-checklist.md +0 -23
  64. package/skills/ai-context-generator/references/overlays/laravel.md +0 -44
  65. package/skills/ai-humanizer/SKILL.md +0 -50
  66. package/skills/api-contract-generator/SKILL.md +0 -243
  67. package/skills/apply/SKILL.md +0 -23
  68. package/skills/archive/SKILL.md +0 -27
  69. package/skills/cerebro/SKILL.md +0 -187
  70. package/skills/cerebro/references/agents.md +0 -213
  71. package/skills/code-review/SKILL.md +0 -373
  72. package/skills/code-review/assets/report-template-agent.md +0 -212
  73. package/skills/code-review/assets/report-template-compact.md +0 -81
  74. package/skills/code-review/assets/report-template-full.md +0 -264
  75. package/skills/code-review/assets/report-template-human.md +0 -168
  76. package/skills/code-review/references/universal-patterns.md +0 -495
  77. package/skills/design-md/README.md +0 -34
  78. package/skills/design-md/SKILL.md +0 -172
  79. package/skills/design-md/examples/DESIGN.md +0 -154
  80. package/skills/design-system/SKILL.md +0 -216
  81. package/skills/design-system-generator/SKILL.md +0 -324
  82. package/skills/design-system-generator/assets/design-system-template.md +0 -348
  83. package/skills/design-system-generator/references/extraction-patterns.md +0 -321
  84. package/skills/doc-builder/SKILL.md +0 -115
  85. package/skills/doc-builder/references/ui-patterns.md +0 -394
  86. package/skills/document-explainer/SKILL.md +0 -155
  87. package/skills/document-translator/SKILL.md +0 -58
  88. package/skills/enhance/SKILL.md +0 -47
  89. package/skills/enhance-prompt/README.md +0 -34
  90. package/skills/enhance-prompt/SKILL.md +0 -204
  91. package/skills/enhance-prompt/references/KEYWORDS.md +0 -114
  92. package/skills/epic-generator/SKILL.md +0 -204
  93. package/skills/epic-single/SKILL.md +0 -63
  94. package/skills/erd-generator/SKILL.md +0 -138
  95. package/skills/feature-planner/SKILL.md +0 -305
  96. package/skills/feature-planner/assets/implementation-plan-template.md +0 -85
  97. package/skills/frontend-design/LICENSE.txt +0 -177
  98. package/skills/frontend-design/SKILL.md +0 -42
  99. package/skills/fsd-generator/SKILL.md +0 -163
  100. package/skills/gamma-builder/SKILL.md +0 -134
  101. package/skills/laravel-code-review/SKILL.md +0 -383
  102. package/skills/laravel-code-review/assets/report-template-agent.md +0 -195
  103. package/skills/laravel-code-review/assets/report-template-compact.md +0 -79
  104. package/skills/laravel-code-review/assets/report-template-full.md +0 -253
  105. package/skills/laravel-code-review/assets/report-template-human.md +0 -159
  106. package/skills/laravel-code-review/references/laravel-patterns.md +0 -571
  107. package/skills/laravel-code-review/references/php84-features.md +0 -442
  108. package/skills/mcp-builder/LICENSE.txt +0 -202
  109. package/skills/mcp-builder/SKILL.md +0 -236
  110. package/skills/mcp-builder/reference/evaluation.md +0 -602
  111. package/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  112. package/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  113. package/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  114. package/skills/mcp-builder/scripts/connections.py +0 -151
  115. package/skills/mcp-builder/scripts/evaluation.py +0 -373
  116. package/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  117. package/skills/mcp-builder/scripts/requirements.txt +0 -2
  118. package/skills/meeting-notes/SKILL.md +0 -159
  119. package/skills/meeting-notes/evals/evals.json +0 -23
  120. package/skills/prd-agent-generator/SKILL.md +0 -132
  121. package/skills/prd-generator/SKILL.md +0 -211
  122. package/skills/product-brief/SKILL.md +0 -141
  123. package/skills/project-orchestrator/SKILL.md +0 -487
  124. package/skills/project-orchestrator/assets/caddy-vps-setup.md +0 -180
  125. package/skills/project-orchestrator/assets/plan-summary-template.md +0 -159
  126. package/skills/prompter-specs/SKILL.md +0 -115
  127. package/skills/prompter-workflow/SKILL.md +0 -166
  128. package/skills/prompter-workflow/evals/evals.json +0 -89
  129. package/skills/proposal/SKILL.md +0 -28
  130. package/skills/qa-test-scenario/SKILL.md +0 -149
  131. package/skills/skill-creator/SKILL.md +0 -173
  132. package/skills/sph-generator/SKILL.md +0 -488
  133. package/skills/story-generator/SKILL.md +0 -285
  134. package/skills/story-single/SKILL.md +0 -86
  135. package/skills/tdd-generator/SKILL.md +0 -300
  136. package/skills/tdd-lite-generator/SKILL.md +0 -230
  137. package/skills/ui-ux-pro/SKILL.md +0 -199
  138. package/skills/ui-ux-pro/assets/design-spec-template.md +0 -173
  139. package/skills/ui-ux-pro/references/component-patterns.md +0 -255
  140. package/skills/ui-ux-pro/references/design-principles.md +0 -167
  141. package/skills/wireframe-generator/SKILL.md +0 -227
  142. package/src/cli/index.ts +0 -223
  143. package/src/commands/archive.ts +0 -302
  144. package/src/commands/change.ts +0 -292
  145. package/src/commands/config.ts +0 -233
  146. package/src/commands/guide.ts +0 -50
  147. package/src/commands/init.ts +0 -597
  148. package/src/commands/list.ts +0 -194
  149. package/src/commands/show.ts +0 -138
  150. package/src/commands/spec.ts +0 -251
  151. package/src/commands/update.ts +0 -129
  152. package/src/commands/upgrade.ts +0 -30
  153. package/src/commands/validate.ts +0 -326
  154. package/src/core/artifact-graph/graph.ts +0 -167
  155. package/src/core/artifact-graph/index.ts +0 -44
  156. package/src/core/artifact-graph/instruction-loader.ts +0 -302
  157. package/src/core/artifact-graph/resolver.ts +0 -226
  158. package/src/core/artifact-graph/schema.ts +0 -124
  159. package/src/core/artifact-graph/state.ts +0 -64
  160. package/src/core/artifact-graph/types.ts +0 -65
  161. package/src/core/completions/command-registry.ts +0 -382
  162. package/src/core/completions/completion-provider.ts +0 -128
  163. package/src/core/completions/generators/bash-generator.ts +0 -191
  164. package/src/core/completions/generators/fish-generator.ts +0 -188
  165. package/src/core/completions/generators/powershell-generator.ts +0 -223
  166. package/src/core/completions/generators/zsh-generator.ts +0 -281
  167. package/src/core/completions/templates/bash-templates.ts +0 -24
  168. package/src/core/completions/templates/fish-templates.ts +0 -40
  169. package/src/core/completions/templates/powershell-templates.ts +0 -25
  170. package/src/core/completions/templates/zsh-templates.ts +0 -36
  171. package/src/core/completions/types.ts +0 -90
  172. package/src/core/config-schema.ts +0 -230
  173. package/src/core/config.ts +0 -181
  174. package/src/core/configurators/slash/antigravity.ts +0 -10
  175. package/src/core/configurators/slash/base.ts +0 -109
  176. package/src/core/configurators/slash/claude.ts +0 -10
  177. package/src/core/configurators/slash/codex.ts +0 -10
  178. package/src/core/configurators/slash/droid.ts +0 -10
  179. package/src/core/configurators/slash/forge.ts +0 -10
  180. package/src/core/configurators/slash/github-copilot.ts +0 -10
  181. package/src/core/configurators/slash/index.ts +0 -10
  182. package/src/core/configurators/slash/kilocode.ts +0 -10
  183. package/src/core/configurators/slash/opencode.ts +0 -10
  184. package/src/core/configurators/slash/registry.ts +0 -51
  185. package/src/core/converters/json-converter.ts +0 -62
  186. package/src/core/global-config.ts +0 -136
  187. package/src/core/parsers/change-parser.ts +0 -234
  188. package/src/core/parsers/markdown-parser.ts +0 -237
  189. package/src/core/parsers/requirement-blocks.ts +0 -234
  190. package/src/core/prompt-templates.ts +0 -3504
  191. package/src/core/schemas/base.schema.ts +0 -20
  192. package/src/core/schemas/change.schema.ts +0 -42
  193. package/src/core/schemas/index.ts +0 -20
  194. package/src/core/schemas/spec.schema.ts +0 -17
  195. package/src/core/skill-discovery.ts +0 -68
  196. package/src/core/specs-apply.ts +0 -483
  197. package/src/core/styles/palette.ts +0 -8
  198. package/src/core/templates/agents-template.ts +0 -459
  199. package/src/core/templates/claude-template.ts +0 -2
  200. package/src/core/templates/index.ts +0 -3
  201. package/src/core/templates/project-template.ts +0 -32
  202. package/src/core/validation/constants.ts +0 -48
  203. package/src/core/validation/types.ts +0 -19
  204. package/src/core/validation/validator.ts +0 -449
  205. package/src/core/view.ts +0 -219
  206. package/src/index.ts +0 -1
  207. package/src/utils/change-metadata.ts +0 -171
  208. package/src/utils/change-utils.ts +0 -131
  209. package/src/utils/file-system.ts +0 -252
  210. package/src/utils/index.ts +0 -12
  211. package/src/utils/interactive.ts +0 -29
  212. package/src/utils/item-discovery.ts +0 -66
  213. package/src/utils/match.ts +0 -26
  214. package/src/utils/shell-detection.ts +0 -62
  215. package/src/utils/task-progress.ts +0 -43
  216. 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
- }