@fission-ai/openspec 0.20.0 → 0.22.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.
@@ -21,6 +21,8 @@ export interface ChangeContext {
21
21
  changeName: string;
22
22
  /** Path to the change directory */
23
23
  changeDir: string;
24
+ /** Project root directory */
25
+ projectRoot: string;
24
26
  }
25
27
  /**
26
28
  * Enriched instructions for creating an artifact.
@@ -93,10 +95,11 @@ export interface ChangeStatus {
93
95
  *
94
96
  * @param schemaName - Schema name (e.g., "spec-driven")
95
97
  * @param templatePath - Relative path within the templates directory (e.g., "proposal.md")
98
+ * @param projectRoot - Optional project root for project-local schema resolution
96
99
  * @returns The template content
97
100
  * @throws TemplateLoadError if the template cannot be loaded
98
101
  */
99
- export declare function loadTemplate(schemaName: string, templatePath: string): string;
102
+ export declare function loadTemplate(schemaName: string, templatePath: string, projectRoot?: string): string;
100
103
  /**
101
104
  * Loads change context combining graph and completion state.
102
105
  *
@@ -114,12 +117,18 @@ export declare function loadChangeContext(projectRoot: string, changeName: strin
114
117
  /**
115
118
  * Generates enriched instructions for creating an artifact.
116
119
  *
120
+ * Instruction injection order:
121
+ * 1. <context> - Project context from config (if present)
122
+ * 2. <rules> - Artifact-specific rules from config (if present)
123
+ * 3. <template> - Schema's template content
124
+ *
117
125
  * @param context - Change context
118
126
  * @param artifactId - Artifact ID to generate instructions for
127
+ * @param projectRoot - Project root directory (for reading config)
119
128
  * @returns Enriched artifact instructions
120
129
  * @throws Error if artifact not found
121
130
  */
122
- export declare function generateInstructions(context: ChangeContext, artifactId: string): ArtifactInstructions;
131
+ export declare function generateInstructions(context: ChangeContext, artifactId: string, projectRoot?: string): ArtifactInstructions;
123
132
  /**
124
133
  * Formats the status of all artifacts in a change.
125
134
  *
@@ -4,6 +4,9 @@ import { getSchemaDir, resolveSchema } from './resolver.js';
4
4
  import { ArtifactGraph } from './graph.js';
5
5
  import { detectCompleted } from './state.js';
6
6
  import { resolveSchemaForChange } from '../../utils/change-metadata.js';
7
+ import { readProjectConfig, validateConfigRules } from '../project-config.js';
8
+ // Session-level cache for validation warnings (avoid repeating same warnings)
9
+ const shownWarnings = new Set();
7
10
  /**
8
11
  * Error thrown when loading a template fails.
9
12
  */
@@ -20,11 +23,12 @@ export class TemplateLoadError extends Error {
20
23
  *
21
24
  * @param schemaName - Schema name (e.g., "spec-driven")
22
25
  * @param templatePath - Relative path within the templates directory (e.g., "proposal.md")
26
+ * @param projectRoot - Optional project root for project-local schema resolution
23
27
  * @returns The template content
24
28
  * @throws TemplateLoadError if the template cannot be loaded
25
29
  */
26
- export function loadTemplate(schemaName, templatePath) {
27
- const schemaDir = getSchemaDir(schemaName);
30
+ export function loadTemplate(schemaName, templatePath, projectRoot) {
31
+ const schemaDir = getSchemaDir(schemaName, projectRoot);
28
32
  if (!schemaDir) {
29
33
  throw new TemplateLoadError(`Schema '${schemaName}' not found`, templatePath);
30
34
  }
@@ -57,7 +61,7 @@ export function loadChangeContext(projectRoot, changeName, schemaName) {
57
61
  const changeDir = path.join(projectRoot, 'openspec', 'changes', changeName);
58
62
  // Resolve schema: explicit > metadata > default
59
63
  const resolvedSchemaName = resolveSchemaForChange(changeDir, schemaName);
60
- const schema = resolveSchema(resolvedSchemaName);
64
+ const schema = resolveSchema(resolvedSchemaName, projectRoot);
61
65
  const graph = ArtifactGraph.fromSchema(schema);
62
66
  const completed = detectCompleted(graph, changeDir);
63
67
  return {
@@ -66,24 +70,72 @@ export function loadChangeContext(projectRoot, changeName, schemaName) {
66
70
  schemaName: resolvedSchemaName,
67
71
  changeName,
68
72
  changeDir,
73
+ projectRoot,
69
74
  };
70
75
  }
71
76
  /**
72
77
  * Generates enriched instructions for creating an artifact.
73
78
  *
79
+ * Instruction injection order:
80
+ * 1. <context> - Project context from config (if present)
81
+ * 2. <rules> - Artifact-specific rules from config (if present)
82
+ * 3. <template> - Schema's template content
83
+ *
74
84
  * @param context - Change context
75
85
  * @param artifactId - Artifact ID to generate instructions for
86
+ * @param projectRoot - Project root directory (for reading config)
76
87
  * @returns Enriched artifact instructions
77
88
  * @throws Error if artifact not found
78
89
  */
79
- export function generateInstructions(context, artifactId) {
90
+ export function generateInstructions(context, artifactId, projectRoot) {
80
91
  const artifact = context.graph.getArtifact(artifactId);
81
92
  if (!artifact) {
82
93
  throw new Error(`Artifact '${artifactId}' not found in schema '${context.schemaName}'`);
83
94
  }
84
- const template = loadTemplate(context.schemaName, artifact.template);
95
+ const templateContent = loadTemplate(context.schemaName, artifact.template, context.projectRoot);
85
96
  const dependencies = getDependencyInfo(artifact, context.graph, context.completed);
86
97
  const unlocks = getUnlockedArtifacts(context.graph, artifactId);
98
+ // Build enriched template with project config injections
99
+ let enrichedTemplate = '';
100
+ let projectConfig = null;
101
+ // Use projectRoot from context if not explicitly provided
102
+ const effectiveProjectRoot = projectRoot ?? context.projectRoot;
103
+ // Try to read project config
104
+ if (effectiveProjectRoot) {
105
+ try {
106
+ projectConfig = readProjectConfig(effectiveProjectRoot);
107
+ }
108
+ catch {
109
+ // If config read fails, continue without config
110
+ }
111
+ }
112
+ // Validate rules artifact IDs if config has rules (only once per session)
113
+ if (projectConfig?.rules) {
114
+ const validArtifactIds = new Set(context.graph.getAllArtifacts().map((a) => a.id));
115
+ const warnings = validateConfigRules(projectConfig.rules, validArtifactIds, context.schemaName);
116
+ // Show each unique warning only once per session
117
+ for (const warning of warnings) {
118
+ if (!shownWarnings.has(warning)) {
119
+ console.warn(warning);
120
+ shownWarnings.add(warning);
121
+ }
122
+ }
123
+ }
124
+ // 1. Add context (all artifacts)
125
+ if (projectConfig?.context) {
126
+ enrichedTemplate += `<context>\n${projectConfig.context}\n</context>\n\n`;
127
+ }
128
+ // 2. Add rules (only for matching artifact)
129
+ const rulesForArtifact = projectConfig?.rules?.[artifactId];
130
+ if (rulesForArtifact && rulesForArtifact.length > 0) {
131
+ enrichedTemplate += `<rules>\n`;
132
+ for (const rule of rulesForArtifact) {
133
+ enrichedTemplate += `- ${rule}\n`;
134
+ }
135
+ enrichedTemplate += `</rules>\n\n`;
136
+ }
137
+ // 3. Add original template (without wrapper - CLI handles XML structure)
138
+ enrichedTemplate += templateContent;
87
139
  return {
88
140
  changeName: context.changeName,
89
141
  artifactId: artifact.id,
@@ -92,7 +144,7 @@ export function generateInstructions(context, artifactId) {
92
144
  outputPath: artifact.generates,
93
145
  description: artifact.description,
94
146
  instruction: artifact.instruction,
95
- template,
147
+ template: enrichedTemplate,
96
148
  dependencies,
97
149
  unlocks,
98
150
  };
@@ -131,7 +183,7 @@ function getUnlockedArtifacts(graph, artifactId) {
131
183
  */
132
184
  export function formatChangeStatus(context) {
133
185
  // Load schema to get apply phase configuration
134
- const schema = resolveSchema(context.schemaName);
186
+ const schema = resolveSchema(context.schemaName, context.projectRoot);
135
187
  const applyRequires = schema.apply?.requires ?? schema.artifacts.map(a => a.id);
136
188
  const artifacts = context.graph.getAllArtifacts();
137
189
  const ready = new Set(context.graph.getNextArtifacts(context.completed));
@@ -16,34 +16,52 @@ export declare function getPackageSchemasDir(): string;
16
16
  * Gets the user's schema override directory path.
17
17
  */
18
18
  export declare function getUserSchemasDir(): string;
19
+ /**
20
+ * Gets the project-local schemas directory path.
21
+ * @param projectRoot - The project root directory
22
+ * @returns The path to the project's schemas directory
23
+ */
24
+ export declare function getProjectSchemasDir(projectRoot: string): string;
19
25
  /**
20
26
  * Resolves a schema name to its directory path.
21
27
  *
22
- * Resolution order:
23
- * 1. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
24
- * 2. Package built-in: <package>/schemas/<name>/schema.yaml
28
+ * Resolution order (when projectRoot is provided):
29
+ * 1. Project-local: <projectRoot>/openspec/schemas/<name>/schema.yaml
30
+ * 2. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
31
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
32
+ *
33
+ * When projectRoot is not provided, only user override and package built-in are checked
34
+ * (backward compatible behavior).
25
35
  *
26
36
  * @param name - Schema name (e.g., "spec-driven")
37
+ * @param projectRoot - Optional project root directory for project-local schema resolution
27
38
  * @returns The path to the schema directory, or null if not found
28
39
  */
29
- export declare function getSchemaDir(name: string): string | null;
40
+ export declare function getSchemaDir(name: string, projectRoot?: string): string | null;
30
41
  /**
31
42
  * Resolves a schema name to a SchemaYaml object.
32
43
  *
33
- * Resolution order:
34
- * 1. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
35
- * 2. Package built-in: <package>/schemas/<name>/schema.yaml
44
+ * Resolution order (when projectRoot is provided):
45
+ * 1. Project-local: <projectRoot>/openspec/schemas/<name>/schema.yaml
46
+ * 2. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
47
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
48
+ *
49
+ * When projectRoot is not provided, only user override and package built-in are checked
50
+ * (backward compatible behavior).
36
51
  *
37
52
  * @param name - Schema name (e.g., "spec-driven")
53
+ * @param projectRoot - Optional project root directory for project-local schema resolution
38
54
  * @returns The resolved schema object
39
55
  * @throws Error if schema is not found in any location
40
56
  */
41
- export declare function resolveSchema(name: string): SchemaYaml;
57
+ export declare function resolveSchema(name: string, projectRoot?: string): SchemaYaml;
42
58
  /**
43
59
  * Lists all available schema names.
44
- * Combines user override and package built-in schemas.
60
+ * Combines project-local, user override, and package built-in schemas.
61
+ *
62
+ * @param projectRoot - Optional project root directory for project-local schema resolution
45
63
  */
46
- export declare function listSchemas(): string[];
64
+ export declare function listSchemas(projectRoot?: string): string[];
47
65
  /**
48
66
  * Schema info with metadata (name, description, artifacts).
49
67
  */
@@ -51,11 +69,13 @@ export interface SchemaInfo {
51
69
  name: string;
52
70
  description: string;
53
71
  artifacts: string[];
54
- source: 'package' | 'user';
72
+ source: 'project' | 'user' | 'package';
55
73
  }
56
74
  /**
57
75
  * Lists all available schemas with their descriptions and artifact lists.
58
76
  * Useful for agent skills to present schema selection to users.
77
+ *
78
+ * @param projectRoot - Optional project root directory for project-local schema resolution
59
79
  */
60
- export declare function listSchemasWithInfo(): SchemaInfo[];
80
+ export declare function listSchemasWithInfo(projectRoot?: string): SchemaInfo[];
61
81
  //# sourceMappingURL=resolver.d.ts.map
@@ -31,24 +31,45 @@ export function getPackageSchemasDir() {
31
31
  export function getUserSchemasDir() {
32
32
  return path.join(getGlobalDataDir(), 'schemas');
33
33
  }
34
+ /**
35
+ * Gets the project-local schemas directory path.
36
+ * @param projectRoot - The project root directory
37
+ * @returns The path to the project's schemas directory
38
+ */
39
+ export function getProjectSchemasDir(projectRoot) {
40
+ return path.join(projectRoot, 'openspec', 'schemas');
41
+ }
34
42
  /**
35
43
  * Resolves a schema name to its directory path.
36
44
  *
37
- * Resolution order:
38
- * 1. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
39
- * 2. Package built-in: <package>/schemas/<name>/schema.yaml
45
+ * Resolution order (when projectRoot is provided):
46
+ * 1. Project-local: <projectRoot>/openspec/schemas/<name>/schema.yaml
47
+ * 2. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
48
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
49
+ *
50
+ * When projectRoot is not provided, only user override and package built-in are checked
51
+ * (backward compatible behavior).
40
52
  *
41
53
  * @param name - Schema name (e.g., "spec-driven")
54
+ * @param projectRoot - Optional project root directory for project-local schema resolution
42
55
  * @returns The path to the schema directory, or null if not found
43
56
  */
44
- export function getSchemaDir(name) {
45
- // 1. Check user override directory
57
+ export function getSchemaDir(name, projectRoot) {
58
+ // 1. Check project-local directory (if projectRoot provided)
59
+ if (projectRoot) {
60
+ const projectDir = path.join(getProjectSchemasDir(projectRoot), name);
61
+ const projectSchemaPath = path.join(projectDir, 'schema.yaml');
62
+ if (fs.existsSync(projectSchemaPath)) {
63
+ return projectDir;
64
+ }
65
+ }
66
+ // 2. Check user override directory
46
67
  const userDir = path.join(getUserSchemasDir(), name);
47
68
  const userSchemaPath = path.join(userDir, 'schema.yaml');
48
69
  if (fs.existsSync(userSchemaPath)) {
49
70
  return userDir;
50
71
  }
51
- // 2. Check package built-in directory
72
+ // 3. Check package built-in directory
52
73
  const packageDir = path.join(getPackageSchemasDir(), name);
53
74
  const packageSchemaPath = path.join(packageDir, 'schema.yaml');
54
75
  if (fs.existsSync(packageSchemaPath)) {
@@ -59,20 +80,25 @@ export function getSchemaDir(name) {
59
80
  /**
60
81
  * Resolves a schema name to a SchemaYaml object.
61
82
  *
62
- * Resolution order:
63
- * 1. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
64
- * 2. Package built-in: <package>/schemas/<name>/schema.yaml
83
+ * Resolution order (when projectRoot is provided):
84
+ * 1. Project-local: <projectRoot>/openspec/schemas/<name>/schema.yaml
85
+ * 2. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
86
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
87
+ *
88
+ * When projectRoot is not provided, only user override and package built-in are checked
89
+ * (backward compatible behavior).
65
90
  *
66
91
  * @param name - Schema name (e.g., "spec-driven")
92
+ * @param projectRoot - Optional project root directory for project-local schema resolution
67
93
  * @returns The resolved schema object
68
94
  * @throws Error if schema is not found in any location
69
95
  */
70
- export function resolveSchema(name) {
96
+ export function resolveSchema(name, projectRoot) {
71
97
  // Normalize name (remove .yaml extension if provided)
72
98
  const normalizedName = name.replace(/\.ya?ml$/, '');
73
- const schemaDir = getSchemaDir(normalizedName);
99
+ const schemaDir = getSchemaDir(normalizedName, projectRoot);
74
100
  if (!schemaDir) {
75
- const availableSchemas = listSchemas();
101
+ const availableSchemas = listSchemas(projectRoot);
76
102
  throw new Error(`Schema '${normalizedName}' not found. Available schemas: ${availableSchemas.join(', ')}`);
77
103
  }
78
104
  const schemaPath = path.join(schemaDir, 'schema.yaml');
@@ -98,9 +124,11 @@ export function resolveSchema(name) {
98
124
  }
99
125
  /**
100
126
  * Lists all available schema names.
101
- * Combines user override and package built-in schemas.
127
+ * Combines project-local, user override, and package built-in schemas.
128
+ *
129
+ * @param projectRoot - Optional project root directory for project-local schema resolution
102
130
  */
103
- export function listSchemas() {
131
+ export function listSchemas(projectRoot) {
104
132
  const schemas = new Set();
105
133
  // Add package built-in schemas
106
134
  const packageDir = getPackageSchemasDir();
@@ -126,20 +154,62 @@ export function listSchemas() {
126
154
  }
127
155
  }
128
156
  }
157
+ // Add project-local schemas (if projectRoot provided)
158
+ if (projectRoot) {
159
+ const projectDir = getProjectSchemasDir(projectRoot);
160
+ if (fs.existsSync(projectDir)) {
161
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
162
+ if (entry.isDirectory()) {
163
+ const schemaPath = path.join(projectDir, entry.name, 'schema.yaml');
164
+ if (fs.existsSync(schemaPath)) {
165
+ schemas.add(entry.name);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
129
171
  return Array.from(schemas).sort();
130
172
  }
131
173
  /**
132
174
  * Lists all available schemas with their descriptions and artifact lists.
133
175
  * Useful for agent skills to present schema selection to users.
176
+ *
177
+ * @param projectRoot - Optional project root directory for project-local schema resolution
134
178
  */
135
- export function listSchemasWithInfo() {
179
+ export function listSchemasWithInfo(projectRoot) {
136
180
  const schemas = [];
137
181
  const seenNames = new Set();
138
- // Add user override schemas first (they take precedence)
182
+ // Add project-local schemas first (highest priority, if projectRoot provided)
183
+ if (projectRoot) {
184
+ const projectDir = getProjectSchemasDir(projectRoot);
185
+ if (fs.existsSync(projectDir)) {
186
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
187
+ if (entry.isDirectory()) {
188
+ const schemaPath = path.join(projectDir, entry.name, 'schema.yaml');
189
+ if (fs.existsSync(schemaPath)) {
190
+ try {
191
+ const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
192
+ schemas.push({
193
+ name: entry.name,
194
+ description: schema.description || '',
195
+ artifacts: schema.artifacts.map((a) => a.id),
196
+ source: 'project',
197
+ });
198
+ seenNames.add(entry.name);
199
+ }
200
+ catch {
201
+ // Skip invalid schemas
202
+ }
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+ // Add user override schemas (if not overridden by project)
139
209
  const userDir = getUserSchemasDir();
140
210
  if (fs.existsSync(userDir)) {
141
211
  for (const entry of fs.readdirSync(userDir, { withFileTypes: true })) {
142
- if (entry.isDirectory()) {
212
+ if (entry.isDirectory() && !seenNames.has(entry.name)) {
143
213
  const schemaPath = path.join(userDir, entry.name, 'schema.yaml');
144
214
  if (fs.existsSync(schemaPath)) {
145
215
  try {
@@ -159,7 +229,7 @@ export function listSchemasWithInfo() {
159
229
  }
160
230
  }
161
231
  }
162
- // Add package built-in schemas (if not overridden)
232
+ // Add package built-in schemas (if not overridden by project or user)
163
233
  const packageDir = getPackageSchemasDir();
164
234
  if (fs.existsSync(packageDir)) {
165
235
  for (const entry of fs.readdirSync(packageDir, { withFileTypes: true })) {
@@ -152,6 +152,18 @@ export const COMMAND_REGISTRY = [
152
152
  },
153
153
  ],
154
154
  },
155
+ {
156
+ name: 'feedback',
157
+ description: 'Submit feedback about OpenSpec',
158
+ acceptsPositional: true,
159
+ flags: [
160
+ {
161
+ name: 'body',
162
+ description: 'Detailed description for the feedback',
163
+ takesValue: true,
164
+ },
165
+ ],
166
+ },
155
167
  {
156
168
  name: 'change',
157
169
  description: 'Manage OpenSpec change proposals (deprecated)',
@@ -364,5 +376,81 @@ export const COMMAND_REGISTRY = [
364
376
  },
365
377
  ],
366
378
  },
379
+ {
380
+ name: 'schema',
381
+ description: 'Manage workflow schemas',
382
+ flags: [],
383
+ subcommands: [
384
+ {
385
+ name: 'which',
386
+ description: 'Show where a schema resolves from',
387
+ acceptsPositional: true,
388
+ positionalType: 'schema-name',
389
+ flags: [
390
+ COMMON_FLAGS.json,
391
+ {
392
+ name: 'all',
393
+ description: 'List all schemas with their resolution sources',
394
+ },
395
+ ],
396
+ },
397
+ {
398
+ name: 'validate',
399
+ description: 'Validate a schema structure and templates',
400
+ acceptsPositional: true,
401
+ positionalType: 'schema-name',
402
+ flags: [
403
+ COMMON_FLAGS.json,
404
+ {
405
+ name: 'verbose',
406
+ description: 'Show detailed validation steps',
407
+ },
408
+ ],
409
+ },
410
+ {
411
+ name: 'fork',
412
+ description: 'Copy an existing schema to project for customization',
413
+ acceptsPositional: true,
414
+ positionalType: 'schema-name',
415
+ flags: [
416
+ COMMON_FLAGS.json,
417
+ {
418
+ name: 'force',
419
+ description: 'Overwrite existing destination',
420
+ },
421
+ ],
422
+ },
423
+ {
424
+ name: 'init',
425
+ description: 'Create a new project-local schema',
426
+ acceptsPositional: true,
427
+ flags: [
428
+ COMMON_FLAGS.json,
429
+ {
430
+ name: 'description',
431
+ description: 'Schema description',
432
+ takesValue: true,
433
+ },
434
+ {
435
+ name: 'artifacts',
436
+ description: 'Comma-separated artifact IDs',
437
+ takesValue: true,
438
+ },
439
+ {
440
+ name: 'default',
441
+ description: 'Set as project default schema',
442
+ },
443
+ {
444
+ name: 'no-default',
445
+ description: 'Do not prompt to set as default',
446
+ },
447
+ {
448
+ name: 'force',
449
+ description: 'Overwrite existing schema',
450
+ },
451
+ ],
452
+ },
453
+ ],
454
+ },
367
455
  ];
368
456
  //# sourceMappingURL=command-registry.js.map
@@ -55,9 +55,10 @@ export interface CommandDefinition {
55
55
  * - 'change-or-spec-id': Complete with both changes and specs
56
56
  * - 'path': Complete with file paths
57
57
  * - 'shell': Complete with supported shell names
58
+ * - 'schema-name': Complete with available schema names
58
59
  * - undefined: No specific completion
59
60
  */
60
- positionalType?: 'change-id' | 'spec-id' | 'change-or-spec-id' | 'path' | 'shell';
61
+ positionalType?: 'change-id' | 'spec-id' | 'change-or-spec-id' | 'path' | 'shell' | 'schema-name';
61
62
  }
62
63
  /**
63
64
  * Interface for shell-specific completion script generators
@@ -0,0 +1,36 @@
1
+ import type { ProjectConfig } from './project-config.js';
2
+ /**
3
+ * Check if an error is an ExitPromptError (user cancelled with Ctrl+C).
4
+ * Used instead of instanceof check since @inquirer modules use dynamic imports.
5
+ */
6
+ export declare function isExitPromptError(error: unknown): boolean;
7
+ /**
8
+ * Result of interactive config creation prompts.
9
+ */
10
+ export interface ConfigPromptResult {
11
+ /** Whether to create config file */
12
+ createConfig: boolean;
13
+ /** Selected schema name */
14
+ schema?: string;
15
+ /** Project context (optional) */
16
+ context?: string;
17
+ /** Per-artifact rules (optional) */
18
+ rules?: Record<string, string[]>;
19
+ }
20
+ /**
21
+ * Prompt user to create project config interactively.
22
+ * Used by experimental setup command.
23
+ *
24
+ * @param projectRoot - Optional project root for project-local schema resolution
25
+ * @returns Config prompt result
26
+ * @throws ExitPromptError if user cancels (Ctrl+C)
27
+ */
28
+ export declare function promptForConfig(projectRoot?: string): Promise<ConfigPromptResult>;
29
+ /**
30
+ * Serialize config to YAML string with proper multi-line formatting.
31
+ *
32
+ * @param config - Partial config object (schema required, context/rules optional)
33
+ * @returns YAML string ready to write to file
34
+ */
35
+ export declare function serializeConfig(config: Partial<ProjectConfig>): string;
36
+ //# sourceMappingURL=config-prompts.d.ts.map