imhcode 2.0.3 → 2.0.5
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/bin/imhcode.js +114 -67
- package/package.json +1 -1
package/bin/imhcode.js
CHANGED
|
@@ -2377,15 +2377,37 @@ function detectSprintDocs(cwd) {
|
|
|
2377
2377
|
return fs.readdirSync(docsDir).some(f => /^sprint-\d+$/i.test(f));
|
|
2378
2378
|
}
|
|
2379
2379
|
|
|
2380
|
+
function isSprintComplete(cwd, sprintNum) {
|
|
2381
|
+
const progressPath = path.join(cwd, DOCS_DIR, `sprint-${sprintNum}`, 'progress.md');
|
|
2382
|
+
if (!fs.existsSync(progressPath)) return false;
|
|
2383
|
+
try {
|
|
2384
|
+
const content = fs.readFileSync(progressPath, 'utf8');
|
|
2385
|
+
return !/-\s*\[\s*\]/i.test(content);
|
|
2386
|
+
} catch {
|
|
2387
|
+
return false;
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2380
2391
|
function detectCurrentSprint(cwd) {
|
|
2381
2392
|
const docsDir = path.join(cwd, DOCS_DIR);
|
|
2382
2393
|
if (!fs.existsSync(docsDir)) return 1;
|
|
2383
|
-
|
|
2394
|
+
|
|
2395
|
+
const sprintNums = [];
|
|
2384
2396
|
for (const f of fs.readdirSync(docsDir)) {
|
|
2385
2397
|
const m = f.match(/^sprint-(\d+)$/i);
|
|
2386
|
-
if (m)
|
|
2398
|
+
if (m) sprintNums.push(parseInt(m[1], 10));
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
if (sprintNums.length === 0) return 1;
|
|
2402
|
+
sprintNums.sort((a, b) => a - b);
|
|
2403
|
+
|
|
2404
|
+
for (const num of sprintNums) {
|
|
2405
|
+
if (!isSprintComplete(cwd, num)) {
|
|
2406
|
+
return num;
|
|
2407
|
+
}
|
|
2387
2408
|
}
|
|
2388
|
-
|
|
2409
|
+
|
|
2410
|
+
return sprintNums[sprintNums.length - 1];
|
|
2389
2411
|
}
|
|
2390
2412
|
|
|
2391
2413
|
function detectLastSprint(cwd) {
|
|
@@ -3063,9 +3085,9 @@ async function runTuiCommand() {
|
|
|
3063
3085
|
|
|
3064
3086
|
// Step 2: Requirements
|
|
3065
3087
|
if (state.hasConfig && !state.hasStart) {
|
|
3066
|
-
items.push({ id: 'write', name: 'Write Requirements', desc: '⚠️
|
|
3088
|
+
items.push({ id: 'write', name: 'Write Requirements', desc: '⚠️ Input requirements & scope (Required)', highlight: true });
|
|
3067
3089
|
} else if (state.hasConfig) {
|
|
3068
|
-
items.push({ id: 'write', name: 'Write Requirements', desc: '
|
|
3090
|
+
items.push({ id: 'write', name: 'Write Requirements', desc: 'Input requirements & scope answers' });
|
|
3069
3091
|
}
|
|
3070
3092
|
|
|
3071
3093
|
// Step 3: Plan & Brainstorm
|
|
@@ -3170,14 +3192,14 @@ async function runTuiCommand() {
|
|
|
3170
3192
|
const infoLeft = ` Project: ${projectName}`;
|
|
3171
3193
|
const infoRight = `Path: ${cwd.length > 35 ? '...' + cwd.slice(-32) : cwd} `;
|
|
3172
3194
|
const paddingInfo = width - 4 - infoLeft.length - infoRight.length;
|
|
3173
|
-
console.log(ANSI.cyan + ` │` + ANSI.reset + ANSI.bold + infoLeft + ' '.repeat(paddingInfo) + ANSI.dim + infoRight + ANSI.cyan + `│` + ANSI.reset);
|
|
3195
|
+
console.log(ANSI.cyan + ` │` + ANSI.reset + ANSI.bold + infoLeft + ' '.repeat(Math.max(0, paddingInfo)) + ANSI.dim + infoRight + ANSI.cyan + `│` + ANSI.reset);
|
|
3174
3196
|
|
|
3175
3197
|
const statusLine = ` Status: ${statusStr}`;
|
|
3176
3198
|
const engineLine = `Engine: ${engineStr} `;
|
|
3177
3199
|
const statusClean = statusLine.replace(/\x1b\[[0-9;]*m/g, '');
|
|
3178
3200
|
const engineClean = engineLine.replace(/\x1b\[[0-9;]*m/g, '');
|
|
3179
3201
|
const paddingStatus = width - 4 - statusClean.length - engineClean.length;
|
|
3180
|
-
console.log(ANSI.cyan + ` │` + ANSI.reset + statusLine + ' '.repeat(paddingStatus) + ANSI.dim + engineLine + ANSI.cyan + `│` + ANSI.reset);
|
|
3202
|
+
console.log(ANSI.cyan + ` │` + ANSI.reset + statusLine + ' '.repeat(Math.max(0, paddingStatus)) + ANSI.dim + engineLine + ANSI.cyan + `│` + ANSI.reset);
|
|
3181
3203
|
|
|
3182
3204
|
console.log(ANSI.cyan + ` ├${'─'.repeat(width - 4)}┤` + ANSI.reset);
|
|
3183
3205
|
|
|
@@ -3225,7 +3247,7 @@ async function runTuiCommand() {
|
|
|
3225
3247
|
function centerText(text, width) {
|
|
3226
3248
|
const cleanText = text.replace(/\x1b\[[0-9;]*m/g, '');
|
|
3227
3249
|
const padding = Math.max(0, Math.floor((width - cleanText.length) / 2));
|
|
3228
|
-
return ' '.repeat(padding) + text + ' '.repeat(width - cleanText.length - padding);
|
|
3250
|
+
return ' '.repeat(padding) + text + ' '.repeat(Math.max(0, width - cleanText.length - padding));
|
|
3229
3251
|
}
|
|
3230
3252
|
|
|
3231
3253
|
// Set up standard input listener
|
|
@@ -3346,69 +3368,94 @@ async function runTuiCommand() {
|
|
|
3346
3368
|
process.stdin.pause();
|
|
3347
3369
|
process.stdout.write(ANSI.showCursor + '\n');
|
|
3348
3370
|
|
|
3349
|
-
|
|
3350
|
-
console.log('
|
|
3351
|
-
console.log(' [1] Open docs/start.md in default terminal editor (nano, vi, notepad)');
|
|
3352
|
-
console.log(' [2] Open docs/start.md in VS Code (code)');
|
|
3353
|
-
console.log(' [3] Edit project description directly in terminal');
|
|
3371
|
+
console.log(ANSI.cyan + '\n🕌 IMH-Code — Write Requirements' + ANSI.reset);
|
|
3372
|
+
console.log('Enter your project description below (press Enter on empty line to finish):\n');
|
|
3354
3373
|
|
|
3355
|
-
const
|
|
3356
|
-
const
|
|
3357
|
-
rlEdit.close();
|
|
3358
|
-
|
|
3359
|
-
const startMdPath = path.join(cwd, START_MD);
|
|
3374
|
+
const lines = [];
|
|
3375
|
+
const rlInput = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3360
3376
|
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
} else if (choice === '3') {
|
|
3371
|
-
console.log('\nEnter your new project description below (press Enter on empty line to finish):\n');
|
|
3372
|
-
const lines = [];
|
|
3373
|
-
const rlInput = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3374
|
-
while (true) {
|
|
3375
|
-
const line = await new Promise(res => rlInput.question('> ', res));
|
|
3376
|
-
if (line.trim() === '') break;
|
|
3377
|
-
lines.push(line);
|
|
3378
|
-
}
|
|
3377
|
+
while (true) {
|
|
3378
|
+
const line = await new Promise(res => rlInput.question('> ', res));
|
|
3379
|
+
if (line.trim() === '') break;
|
|
3380
|
+
lines.push(line);
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
const desc = lines.join('\n');
|
|
3384
|
+
if (desc.trim() === '') {
|
|
3385
|
+
console.log('⚠️ No requirements entered. Aborting.');
|
|
3379
3386
|
rlInput.close();
|
|
3380
|
-
|
|
3381
|
-
if (
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
}
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3387
|
+
inSubMode = false;
|
|
3388
|
+
if (isRaw) process.stdin.setRawMode(true);
|
|
3389
|
+
process.stdin.resume();
|
|
3390
|
+
renderMenu();
|
|
3391
|
+
break;
|
|
3392
|
+
}
|
|
3393
|
+
|
|
3394
|
+
// Ask for backend
|
|
3395
|
+
let backend = 'yes';
|
|
3396
|
+
while (true) {
|
|
3397
|
+
const ans = await new Promise(res => rlInput.question('\nDo you need a backend API / server-side logic? (yes/no/unsure) [default: yes]: ', res));
|
|
3398
|
+
const cleanAns = ans.trim().toLowerCase();
|
|
3399
|
+
if (cleanAns === '') { backend = 'yes'; break; }
|
|
3400
|
+
if (['yes', 'no', 'unsure'].includes(cleanAns)) { backend = cleanAns; break; }
|
|
3401
|
+
console.log('❌ Invalid input. Please enter yes, no, or unsure.');
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
// Ask for mobile
|
|
3405
|
+
let mobile = 'no';
|
|
3406
|
+
while (true) {
|
|
3407
|
+
const ans = await new Promise(res => rlInput.question('Do you need a mobile app (iOS/Android)? (yes/no) [default: no]: ', res));
|
|
3408
|
+
const cleanAns = ans.trim().toLowerCase();
|
|
3409
|
+
if (cleanAns === '') { mobile = 'no'; break; }
|
|
3410
|
+
if (['yes', 'no'].includes(cleanAns)) { mobile = cleanAns; break; }
|
|
3411
|
+
console.log('❌ Invalid input. Please enter yes or no.');
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
rlInput.close();
|
|
3415
|
+
|
|
3416
|
+
// Write start.md template
|
|
3417
|
+
const startMdPath = path.join(cwd, START_MD);
|
|
3418
|
+
const startMdContent = [
|
|
3419
|
+
'# 🕌 IMH-Code — Project Start',
|
|
3420
|
+
'',
|
|
3421
|
+
'> **Imam Hussain Coding Harness Platform**',
|
|
3422
|
+
'',
|
|
3423
|
+
'---',
|
|
3424
|
+
'',
|
|
3425
|
+
'## ⚡ Quick Scope Check',
|
|
3426
|
+
'',
|
|
3427
|
+
'**Do you need a backend API / server-side logic?**',
|
|
3428
|
+
`> **Answer:** ${backend}`,
|
|
3429
|
+
'',
|
|
3430
|
+
'**Do you need a mobile app (iOS/Android)?**',
|
|
3431
|
+
`> **Answer:** ${mobile}`,
|
|
3432
|
+
'',
|
|
3433
|
+
'---',
|
|
3434
|
+
'',
|
|
3435
|
+
'## 📝 Your Project Description',
|
|
3436
|
+
'',
|
|
3437
|
+
'<!-- WRITE_PROMPT_HERE -->',
|
|
3438
|
+
desc,
|
|
3439
|
+
'<!-- END_PROMPT -->',
|
|
3440
|
+
'',
|
|
3441
|
+
'---',
|
|
3442
|
+
'',
|
|
3443
|
+
'## 🚀 Next Step',
|
|
3444
|
+
'',
|
|
3445
|
+
'After filling in the scope and your description, run:',
|
|
3446
|
+
'',
|
|
3447
|
+
'```bash',
|
|
3448
|
+
'imhcode plan',
|
|
3449
|
+
'```'
|
|
3450
|
+
].join('\n');
|
|
3451
|
+
|
|
3452
|
+
// Ensure directories exist
|
|
3453
|
+
const docsDir = path.dirname(startMdPath);
|
|
3454
|
+
if (!fs.existsSync(docsDir)) {
|
|
3455
|
+
fs.mkdirSync(docsDir, { recursive: true });
|
|
3411
3456
|
}
|
|
3457
|
+
fs.writeFileSync(startMdPath, startMdContent, 'utf8');
|
|
3458
|
+
console.log('\n✅ Requirements updated successfully in docs/start.md!');
|
|
3412
3459
|
|
|
3413
3460
|
inSubMode = false;
|
|
3414
3461
|
if (isRaw) process.stdin.setRawMode(true);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imhcode",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "IMH-Code — Imam Hussain Coding Harness Platform. A fast-first multi-agent AI coding framework with intelligent model routing. 19 generic role-based agents (planner, nextjs-executor, laravel-executor, etc.), configurable testing strategy, and 7 token-saving optimizations for rapid MVP development.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|