@iservu-inc/adf-cli 0.14.5 → 0.16.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.
- package/.project/chats/current/SESSION-STATUS.md +25 -279
- package/.project/docs/AI-MODEL-SOURCES.md +217 -249
- package/.project/docs/AI-PROVIDER-INTEGRATION.md +1 -1
- package/.project/docs/PHASE-6-ADVANCED-LEARNING.md +46 -0
- package/.project/docs/ROADMAP.md +72 -157
- package/.project/docs/designs/CUSTOM-ARTIFACT-UPLOAD.md +259 -0
- package/.project/docs/designs/LEARNING-RULES-EXCHANGE.md +77 -0
- package/CHANGELOG.md +2054 -2995
- package/README.md +5 -8
- package/bin/adf.js +84 -4
- package/conductor/tracks/session_resume_review_20260113/plan.md +18 -0
- package/conductor/tracks.md +4 -0
- package/gemini.md +3 -0
- package/lib/ai/ai-client.js +9 -9
- package/lib/ai/ai-config.js +14 -14
- package/lib/commands/import.js +439 -0
- package/lib/commands/init.js +8 -4
- package/lib/frameworks/interviewer.js +281 -89
- package/lib/frameworks/progress-tracker.js +18 -0
- package/lib/generators/antigravity-generator.js +6 -5
- package/lib/generators/opencode-generator.js +42 -33
- package/lib/generators/tool-config-generator.js +24 -0
- package/lib/learning/learning-manager.js +107 -8
- package/lib/learning/rules-exporter.js +103 -0
- package/lib/learning/rules-importer.js +141 -0
- package/lib/utils/artifact-detector.js +253 -0
- package/package.json +1 -1
- package/tests/progress-tracker.test.js +16 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const ora = require('ora');
|
|
5
|
+
const inquirer = require('inquirer');
|
|
6
|
+
const { detectArtifactType, getArtifactTypes, isValidType } = require('../utils/artifact-detector');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Import Command
|
|
10
|
+
* Import existing markdown documentation into ADF
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Generate a session ID for imported artifacts
|
|
15
|
+
* @returns {string} - Session ID in format: {timestamp}_imported
|
|
16
|
+
*/
|
|
17
|
+
function generateSessionId() {
|
|
18
|
+
const now = new Date();
|
|
19
|
+
const timestamp = now.toISOString()
|
|
20
|
+
.replace(/[-:]/g, '')
|
|
21
|
+
.replace('T', '_')
|
|
22
|
+
.split('.')[0];
|
|
23
|
+
return `${timestamp}_imported`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Normalize markdown content with ADF metadata
|
|
28
|
+
* @param {string} content - Original content
|
|
29
|
+
* @param {string} type - Artifact type
|
|
30
|
+
* @param {string} sourcePath - Original source path
|
|
31
|
+
* @returns {string} - Normalized content
|
|
32
|
+
*/
|
|
33
|
+
function normalizeContent(content, type, sourcePath) {
|
|
34
|
+
// Check if frontmatter already exists
|
|
35
|
+
const hasFrontmatter = content.startsWith('---');
|
|
36
|
+
|
|
37
|
+
const adfMetadata = {
|
|
38
|
+
adf_type: type,
|
|
39
|
+
adf_imported: true,
|
|
40
|
+
adf_source: sourcePath,
|
|
41
|
+
adf_imported_at: new Date().toISOString()
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
if (hasFrontmatter) {
|
|
45
|
+
// Insert ADF metadata into existing frontmatter
|
|
46
|
+
return content.replace(/^---\s*\n/, `---\n${formatYamlMetadata(adfMetadata)}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Add new frontmatter
|
|
50
|
+
const frontmatter = `---\n${formatYamlMetadata(adfMetadata)}---\n\n`;
|
|
51
|
+
return frontmatter + content;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Format metadata as YAML
|
|
56
|
+
* @param {Object} metadata - Metadata object
|
|
57
|
+
* @returns {string} - YAML formatted string
|
|
58
|
+
*/
|
|
59
|
+
function formatYamlMetadata(metadata) {
|
|
60
|
+
return Object.entries(metadata)
|
|
61
|
+
.map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
|
|
62
|
+
.join('\n') + '\n';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create session directory structure
|
|
67
|
+
* @param {string} projectPath - Project root
|
|
68
|
+
* @param {string} sessionId - Session ID
|
|
69
|
+
* @returns {Object} - Paths object
|
|
70
|
+
*/
|
|
71
|
+
async function createSessionStructure(projectPath, sessionId) {
|
|
72
|
+
const sessionsDir = path.join(projectPath, '.adf', 'sessions');
|
|
73
|
+
const sessionPath = path.join(sessionsDir, sessionId);
|
|
74
|
+
const outputsPath = path.join(sessionPath, 'outputs');
|
|
75
|
+
const customPath = path.join(outputsPath, 'custom');
|
|
76
|
+
const sourcesPath = path.join(sessionPath, 'sources');
|
|
77
|
+
|
|
78
|
+
await fs.ensureDir(outputsPath);
|
|
79
|
+
await fs.ensureDir(customPath);
|
|
80
|
+
await fs.ensureDir(sourcesPath);
|
|
81
|
+
|
|
82
|
+
return { sessionPath, outputsPath, customPath, sourcesPath };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Create session metadata
|
|
87
|
+
* @param {string} sessionPath - Session directory path
|
|
88
|
+
* @param {Array} sourceFiles - List of source files
|
|
89
|
+
* @param {Array} artifactTypes - List of artifact types
|
|
90
|
+
* @param {string} projectPath - Project root path
|
|
91
|
+
*/
|
|
92
|
+
async function createSessionMetadata(sessionPath, sourceFiles, artifactTypes, projectPath) {
|
|
93
|
+
const metadata = {
|
|
94
|
+
framework: 'imported',
|
|
95
|
+
importedAt: new Date().toISOString(),
|
|
96
|
+
sourceFiles: sourceFiles.map(f => path.relative(projectPath, f)),
|
|
97
|
+
artifactTypes: [...new Set(artifactTypes)],
|
|
98
|
+
projectPath: projectPath
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
await fs.writeJson(path.join(sessionPath, '_metadata.json'), metadata, { spaces: 2 });
|
|
102
|
+
|
|
103
|
+
const progress = {
|
|
104
|
+
status: 'completed',
|
|
105
|
+
canResume: false,
|
|
106
|
+
importedArtifacts: sourceFiles.length,
|
|
107
|
+
completedBlocks: artifactTypes,
|
|
108
|
+
totalBlocks: artifactTypes.length,
|
|
109
|
+
totalQuestionsAnswered: 0,
|
|
110
|
+
lastUpdated: new Date().toISOString()
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
await fs.writeJson(path.join(sessionPath, '_progress.json'), progress, { spaces: 2 });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Resolve files from input arguments (handles globs and directories)
|
|
118
|
+
* @param {Array} inputs - File paths, directories, or glob patterns
|
|
119
|
+
* @returns {Promise<Array>} - Resolved file paths
|
|
120
|
+
*/
|
|
121
|
+
async function resolveFiles(inputs) {
|
|
122
|
+
const files = [];
|
|
123
|
+
|
|
124
|
+
for (const input of inputs) {
|
|
125
|
+
const fullPath = path.resolve(input);
|
|
126
|
+
|
|
127
|
+
if (!await fs.pathExists(fullPath)) {
|
|
128
|
+
console.warn(chalk.yellow(`⚠️ File not found: ${input}`));
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const stats = await fs.stat(fullPath);
|
|
133
|
+
|
|
134
|
+
if (stats.isDirectory()) {
|
|
135
|
+
// Scan directory for markdown files
|
|
136
|
+
const dirFiles = await fs.readdir(fullPath);
|
|
137
|
+
for (const file of dirFiles) {
|
|
138
|
+
if (file.endsWith('.md') || file.endsWith('.markdown')) {
|
|
139
|
+
files.push(path.join(fullPath, file));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
} else if (stats.isFile() && (fullPath.endsWith('.md') || fullPath.endsWith('.markdown'))) {
|
|
143
|
+
files.push(fullPath);
|
|
144
|
+
} else {
|
|
145
|
+
console.warn(chalk.yellow(`⚠️ Skipping non-markdown file: ${input}`));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return files;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Interactive type selection for a file
|
|
154
|
+
* @param {string} filePath - File path
|
|
155
|
+
* @param {Object} detection - Auto-detection result
|
|
156
|
+
* @returns {Promise<Object>} - Final type selection
|
|
157
|
+
*/
|
|
158
|
+
async function promptForType(filePath, detection) {
|
|
159
|
+
const types = getArtifactTypes();
|
|
160
|
+
const filename = path.basename(filePath);
|
|
161
|
+
|
|
162
|
+
console.log(chalk.cyan(`\n📄 ${filename}`));
|
|
163
|
+
|
|
164
|
+
if (detection.confidence > 0) {
|
|
165
|
+
console.log(chalk.gray(` Auto-detected: ${detection.config.name} (${detection.confidence}% confidence)`));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const choices = [
|
|
169
|
+
...Object.entries(types).map(([key, config]) => ({
|
|
170
|
+
name: `${config.name} → ${config.outputFile}`,
|
|
171
|
+
value: key
|
|
172
|
+
})),
|
|
173
|
+
{ name: chalk.yellow('Custom (specify name)'), value: 'custom' },
|
|
174
|
+
{ name: chalk.gray('Skip this file'), value: 'skip' }
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
// Pre-select detected type if high confidence
|
|
178
|
+
const defaultChoice = detection.confidence >= 60 ? detection.type : undefined;
|
|
179
|
+
|
|
180
|
+
const { selectedType } = await inquirer.prompt([
|
|
181
|
+
{
|
|
182
|
+
type: 'list',
|
|
183
|
+
name: 'selectedType',
|
|
184
|
+
message: `Select artifact type for ${filename}:`,
|
|
185
|
+
choices,
|
|
186
|
+
default: defaultChoice
|
|
187
|
+
}
|
|
188
|
+
]);
|
|
189
|
+
|
|
190
|
+
if (selectedType === 'skip') {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (selectedType === 'custom') {
|
|
195
|
+
const { customName } = await inquirer.prompt([
|
|
196
|
+
{
|
|
197
|
+
type: 'input',
|
|
198
|
+
name: 'customName',
|
|
199
|
+
message: 'Enter custom artifact name:',
|
|
200
|
+
default: filename.replace(/\.md$/, ''),
|
|
201
|
+
validate: input => input.trim().length > 0 || 'Name cannot be empty'
|
|
202
|
+
}
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
type: 'custom',
|
|
207
|
+
customName: customName.trim(),
|
|
208
|
+
outputFile: `custom/${customName.trim().toLowerCase().replace(/\s+/g, '-')}.md`
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
type: selectedType,
|
|
214
|
+
outputFile: types[selectedType].outputFile
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Main import function
|
|
220
|
+
* @param {Array} files - Files to import
|
|
221
|
+
* @param {Object} options - Command options
|
|
222
|
+
*/
|
|
223
|
+
async function importArtifacts(files, options = {}) {
|
|
224
|
+
const cwd = process.cwd();
|
|
225
|
+
const adfDir = path.join(cwd, '.adf');
|
|
226
|
+
|
|
227
|
+
// Ensure .adf directory exists
|
|
228
|
+
if (!await fs.pathExists(adfDir)) {
|
|
229
|
+
console.log(chalk.yellow('\n⚠️ No .adf directory found. Creating one...'));
|
|
230
|
+
await fs.ensureDir(adfDir);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Resolve all input files
|
|
234
|
+
const resolvedFiles = await resolveFiles(files);
|
|
235
|
+
|
|
236
|
+
if (resolvedFiles.length === 0) {
|
|
237
|
+
console.error(chalk.red('\n❌ No valid markdown files found to import.'));
|
|
238
|
+
console.log(chalk.yellow('Specify .md files, directories, or use glob patterns.\n'));
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log(chalk.cyan.bold(`\n📥 Importing ${resolvedFiles.length} file(s)...\n`));
|
|
243
|
+
|
|
244
|
+
// Dry run mode
|
|
245
|
+
if (options.dryRun) {
|
|
246
|
+
console.log(chalk.yellow.bold('DRY RUN - No changes will be made\n'));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Process each file
|
|
250
|
+
const imports = [];
|
|
251
|
+
const skipped = [];
|
|
252
|
+
|
|
253
|
+
for (const filePath of resolvedFiles) {
|
|
254
|
+
const detection = await detectArtifactType(filePath);
|
|
255
|
+
let finalType;
|
|
256
|
+
|
|
257
|
+
if (options.interactive) {
|
|
258
|
+
// Interactive mode - prompt for each file
|
|
259
|
+
finalType = await promptForType(filePath, detection);
|
|
260
|
+
if (!finalType) {
|
|
261
|
+
skipped.push(filePath);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
} else if (options.type) {
|
|
265
|
+
// Explicit type provided via --type flag
|
|
266
|
+
if (!isValidType(options.type)) {
|
|
267
|
+
console.error(chalk.red(`\n❌ Invalid artifact type: ${options.type}`));
|
|
268
|
+
console.log(chalk.yellow('Valid types: prd, architecture, stories, tasks, specification, constitution, plan, prp, custom\n'));
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (options.type === 'custom') {
|
|
273
|
+
const customName = options.name || path.basename(filePath, '.md');
|
|
274
|
+
finalType = {
|
|
275
|
+
type: 'custom',
|
|
276
|
+
customName,
|
|
277
|
+
outputFile: `custom/${customName.toLowerCase().replace(/\s+/g, '-')}.md`
|
|
278
|
+
};
|
|
279
|
+
} else {
|
|
280
|
+
const types = getArtifactTypes();
|
|
281
|
+
finalType = {
|
|
282
|
+
type: options.type,
|
|
283
|
+
outputFile: types[options.type].outputFile
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
// Auto-detection mode
|
|
288
|
+
if (detection.confidence < 50) {
|
|
289
|
+
console.log(chalk.yellow(`⚠️ Low confidence (${detection.confidence}%) for ${path.basename(filePath)}`));
|
|
290
|
+
console.log(chalk.gray(` Detected as: ${detection.config.name}`));
|
|
291
|
+
console.log(chalk.gray(` Use --interactive or --type to specify manually\n`));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
finalType = {
|
|
295
|
+
type: detection.type,
|
|
296
|
+
outputFile: detection.config.outputFile,
|
|
297
|
+
confidence: detection.confidence
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
imports.push({
|
|
302
|
+
sourcePath: filePath,
|
|
303
|
+
...finalType
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
if (!options.dryRun) {
|
|
307
|
+
console.log(chalk.green(`✓ ${path.basename(filePath)}`));
|
|
308
|
+
console.log(chalk.gray(` → ${finalType.outputFile} (${finalType.type})`));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (options.dryRun) {
|
|
313
|
+
console.log(chalk.cyan.bold('\nWould import:\n'));
|
|
314
|
+
for (const item of imports) {
|
|
315
|
+
console.log(chalk.green(` ${path.basename(item.sourcePath)}`));
|
|
316
|
+
console.log(chalk.gray(` → ${item.outputFile} (${item.type})`));
|
|
317
|
+
}
|
|
318
|
+
if (skipped.length > 0) {
|
|
319
|
+
console.log(chalk.yellow(`\nWould skip: ${skipped.length} file(s)\n`));
|
|
320
|
+
}
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (imports.length === 0) {
|
|
325
|
+
console.log(chalk.yellow('\nNo files to import after processing.\n'));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Create session
|
|
330
|
+
const spinner = ora('Creating import session...').start();
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
const sessionId = options.session === 'latest'
|
|
334
|
+
? await findLatestSession(cwd)
|
|
335
|
+
: options.session || generateSessionId();
|
|
336
|
+
|
|
337
|
+
const { sessionPath, outputsPath, customPath, sourcesPath } = await createSessionStructure(cwd, sessionId);
|
|
338
|
+
|
|
339
|
+
// Copy and normalize files
|
|
340
|
+
const artifactTypes = [];
|
|
341
|
+
|
|
342
|
+
for (const item of imports) {
|
|
343
|
+
// Read source
|
|
344
|
+
const content = await fs.readFile(item.sourcePath, 'utf-8');
|
|
345
|
+
|
|
346
|
+
// Normalize content
|
|
347
|
+
const normalized = options.noNormalize
|
|
348
|
+
? content
|
|
349
|
+
: normalizeContent(content, item.type, path.relative(cwd, item.sourcePath));
|
|
350
|
+
|
|
351
|
+
// Determine output path
|
|
352
|
+
let outputPath;
|
|
353
|
+
if (item.type === 'custom') {
|
|
354
|
+
outputPath = path.join(customPath, item.customName
|
|
355
|
+
? `${item.customName.toLowerCase().replace(/\s+/g, '-')}.md`
|
|
356
|
+
: path.basename(item.sourcePath));
|
|
357
|
+
} else {
|
|
358
|
+
outputPath = path.join(outputsPath, item.outputFile);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Write normalized content
|
|
362
|
+
await fs.ensureDir(path.dirname(outputPath));
|
|
363
|
+
await fs.writeFile(outputPath, normalized);
|
|
364
|
+
|
|
365
|
+
// Preserve original
|
|
366
|
+
const originalFilename = `original_${path.basename(item.sourcePath)}`;
|
|
367
|
+
await fs.copy(item.sourcePath, path.join(sourcesPath, originalFilename));
|
|
368
|
+
|
|
369
|
+
artifactTypes.push(item.type);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Create metadata
|
|
373
|
+
await createSessionMetadata(
|
|
374
|
+
sessionPath,
|
|
375
|
+
imports.map(i => i.sourcePath),
|
|
376
|
+
artifactTypes,
|
|
377
|
+
cwd
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
spinner.succeed(`Created import session: ${chalk.cyan(sessionId)}`);
|
|
381
|
+
|
|
382
|
+
console.log(chalk.gray(`\n Session: .adf/sessions/${sessionId}/`));
|
|
383
|
+
console.log(chalk.gray(` Artifacts: ${imports.length}`));
|
|
384
|
+
console.log(chalk.gray(` Types: ${[...new Set(artifactTypes)].join(', ')}`));
|
|
385
|
+
|
|
386
|
+
if (skipped.length > 0) {
|
|
387
|
+
console.log(chalk.yellow(` Skipped: ${skipped.length} file(s)`));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
console.log(chalk.green.bold('\n✓ Import complete!'));
|
|
391
|
+
console.log(chalk.gray(' Run "adf deploy <tool>" to deploy imported artifacts.\n'));
|
|
392
|
+
|
|
393
|
+
} catch (error) {
|
|
394
|
+
spinner.fail(`Import failed: ${error.message}`);
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Find the latest session ID
|
|
401
|
+
* @param {string} cwd - Current working directory
|
|
402
|
+
* @returns {Promise<string|null>} - Latest session ID or null
|
|
403
|
+
*/
|
|
404
|
+
async function findLatestSession(cwd) {
|
|
405
|
+
const sessionsDir = path.join(cwd, '.adf', 'sessions');
|
|
406
|
+
|
|
407
|
+
if (!await fs.pathExists(sessionsDir)) {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const sessions = await fs.readdir(sessionsDir);
|
|
412
|
+
if (sessions.length === 0) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Sort by timestamp (descending)
|
|
417
|
+
sessions.sort().reverse();
|
|
418
|
+
return sessions[0];
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Command handler
|
|
423
|
+
*/
|
|
424
|
+
async function importCommand(files, options) {
|
|
425
|
+
if (!files || files.length === 0) {
|
|
426
|
+
console.error(chalk.red('\n❌ Error: Please specify files to import.'));
|
|
427
|
+
console.log(chalk.yellow('Usage: adf import <files...> [options]'));
|
|
428
|
+
console.log(chalk.gray('\nExamples:'));
|
|
429
|
+
console.log(chalk.gray(' adf import ./docs/PRD.md'));
|
|
430
|
+
console.log(chalk.gray(' adf import ./docs/*.md --interactive'));
|
|
431
|
+
console.log(chalk.gray(' adf import ./design.md --type architecture\n'));
|
|
432
|
+
process.exit(1);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
await importArtifacts(files, options);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
module.exports = importCommand;
|
|
439
|
+
module.exports.importArtifacts = importArtifacts;
|
package/lib/commands/init.js
CHANGED
|
@@ -159,10 +159,14 @@ async function init(options) {
|
|
|
159
159
|
const interviewer = new Interviewer(existingSession.progress.framework || 'balanced', cwd, existingSession, aiConfig);
|
|
160
160
|
const sessionPath = await interviewer.start();
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
if (sessionPath === 'back') {
|
|
163
|
+
// User requested to go back to main menu
|
|
164
|
+
// Fall through to existing content check
|
|
165
|
+
} else {
|
|
166
|
+
console.log(chalk.green.bold('\n✨ Requirements gathering complete!\n'));
|
|
167
|
+
console.log(chalk.cyan(`📁 Session saved to: ${sessionPath}\n`));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
// Check if already initialized with actual content
|