imhcode 2.0.5 → 3.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.
- package/bin/imhcode.js +294 -96
- package/dist/orchestrator/executor.d.ts +6 -1
- package/dist/orchestrator/executor.d.ts.map +1 -1
- package/dist/orchestrator/executor.js +73 -16
- package/dist/orchestrator/executor.js.map +1 -1
- package/dist/orchestrator/index.d.ts +9 -1
- package/dist/orchestrator/index.d.ts.map +1 -1
- package/dist/orchestrator/index.js +59 -12
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/orchestrator/types.d.ts +1 -1
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/orchestrator/executor.ts +80 -15
- package/src/orchestrator/index.ts +62 -13
- package/src/orchestrator/types.ts +1 -1
package/bin/imhcode.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* imhcode agent list → List all discovered agents
|
|
13
13
|
* imhcode agent inspect <id> → Show full manifest + loaded skills
|
|
14
14
|
* imhcode agent run <id> "<task>" → Run agent (dry-run by default)
|
|
15
|
-
* --engine <cli> → Override engine (claude|opencode|codex|agy|qwen|mimo)
|
|
15
|
+
* --engine <cli> → Override engine (claude|opencode|codex|codex-fugu|agy|qwen|mimo)
|
|
16
16
|
* -m, --model <model> → Override model
|
|
17
17
|
* --live → Call real LLM
|
|
18
18
|
* --output <path> → Custom session output directory
|
|
@@ -40,6 +40,88 @@ const BRAINSTORM_MD = path.join(DOCS_DIR, 'brainstorming.md');
|
|
|
40
40
|
const BRIEF_MD = path.join(DOCS_DIR, 'PROJECT_BRIEF.md');
|
|
41
41
|
const CONTEXT_MD = path.join(LOCAL_DIR_NAME, 'context.md');
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Ranked priority lists per category.
|
|
45
|
+
* The algorithm scores each available model against these lists
|
|
46
|
+
* and selects the highest-ranked match found in the installed engines.
|
|
47
|
+
*/
|
|
48
|
+
const MODEL_PRIORITY_RANKS = {
|
|
49
|
+
frontend: [
|
|
50
|
+
// Engine Model substring to match (lowercase, no hyphens/dots)
|
|
51
|
+
['mimo', 'mimov25pro'],
|
|
52
|
+
['mimo', 'mimov25'],
|
|
53
|
+
['opencode', 'mimov25pro'],
|
|
54
|
+
['opencode', 'mimov25'],
|
|
55
|
+
['codex', 'gpt55'],
|
|
56
|
+
['codex', 'gpt5'],
|
|
57
|
+
['agy', 'claudeopus46'],
|
|
58
|
+
['agy', 'claudeopus'],
|
|
59
|
+
['opencode', 'gemini35flash'],
|
|
60
|
+
['opencode', 'gemini25pro'],
|
|
61
|
+
['claude', 'claudeopus46'],
|
|
62
|
+
['claude', 'opus'],
|
|
63
|
+
],
|
|
64
|
+
backend: [
|
|
65
|
+
['opencode', 'deepseekv4pro'],
|
|
66
|
+
['opencode', 'deepseekv4'],
|
|
67
|
+
['opencode', 'kimik27code'],
|
|
68
|
+
['opencode', 'kimik2'],
|
|
69
|
+
['opencode', 'qwen3coder480b'],
|
|
70
|
+
['opencode', 'qwen3coder'],
|
|
71
|
+
['codex', 'gpt55'],
|
|
72
|
+
['codex', 'gpt5'],
|
|
73
|
+
['opencode', 'gptoss120b'],
|
|
74
|
+
['qwen', 'qwen3codermax'],
|
|
75
|
+
['qwen', 'qwen3coder'],
|
|
76
|
+
['claude', 'claudesonnet46'],
|
|
77
|
+
['claude', 'sonnet'],
|
|
78
|
+
],
|
|
79
|
+
planning: [
|
|
80
|
+
['agy', 'claudeopus46'],
|
|
81
|
+
['agy', 'claudeopus'],
|
|
82
|
+
['claude', 'claudeopus46'],
|
|
83
|
+
['claude', 'opus'],
|
|
84
|
+
['codex', 'gpt55'],
|
|
85
|
+
['codex', 'gpt5'],
|
|
86
|
+
['opencode', 'gemini31propreview'],
|
|
87
|
+
['opencode', 'gemini31pro'],
|
|
88
|
+
['opencode', 'deepseekv4pro'],
|
|
89
|
+
],
|
|
90
|
+
testing: [
|
|
91
|
+
['codex-fugu', 'fuguultra'],
|
|
92
|
+
['codex-fugu', 'fugu'],
|
|
93
|
+
['codex', 'gpt55'],
|
|
94
|
+
['codex', 'gpt5'],
|
|
95
|
+
['agy', 'gptoss120bmedium'],
|
|
96
|
+
['agy', 'gptoss120b'],
|
|
97
|
+
['agy', 'claudeopus46'],
|
|
98
|
+
['agy', 'claudeopus'],
|
|
99
|
+
['opencode', 'deepseekv4pro'],
|
|
100
|
+
['claude', 'claudeopus46'],
|
|
101
|
+
],
|
|
102
|
+
review: [
|
|
103
|
+
['codex-fugu', 'fuguultra'],
|
|
104
|
+
['codex-fugu', 'fugu'],
|
|
105
|
+
['codex', 'gpt55'],
|
|
106
|
+
['codex', 'gpt5'],
|
|
107
|
+
['agy', 'claudesonnet46'],
|
|
108
|
+
['agy', 'claudesonnet'],
|
|
109
|
+
['opencode', 'gptoss120b'],
|
|
110
|
+
['claude', 'claudesonnet46'],
|
|
111
|
+
['opencode', 'deepseekv4pro'],
|
|
112
|
+
],
|
|
113
|
+
fast: [
|
|
114
|
+
['opencode', 'deepseekv4flash'],
|
|
115
|
+
['opencode', 'deepseekv4flash'],
|
|
116
|
+
['opencode', 'gemini35flash'],
|
|
117
|
+
['codex', 'gpt54mini'],
|
|
118
|
+
['codex', 'gptmini'],
|
|
119
|
+
['qwen', 'qwen3coderflash'],
|
|
120
|
+
['claude', 'claudehaiku35'],
|
|
121
|
+
['claude', 'haiku'],
|
|
122
|
+
],
|
|
123
|
+
};
|
|
124
|
+
|
|
43
125
|
// ─── Entry Point ───────────────────────────────────────────────────────────────
|
|
44
126
|
|
|
45
127
|
const args = process.argv.slice(2);
|
|
@@ -155,7 +237,7 @@ function printGeneralHelp() {
|
|
|
155
237
|
${CLI_CMD} agent inspect <id> → Show agent manifest + loaded skills
|
|
156
238
|
${CLI_CMD} agent run <id> "<task>" → Run agent (dry-run by default)
|
|
157
239
|
--live → Call real LLM
|
|
158
|
-
--engine <cli> → Override engine (claude|opencode|codex|agy|qwen|mimo)
|
|
240
|
+
--engine <cli> → Override engine (claude|opencode|codex|codex-fugu|agy|qwen|mimo)
|
|
159
241
|
-m, --model <model> → Override model
|
|
160
242
|
--output <path> → Save session to custom path
|
|
161
243
|
|
|
@@ -1017,6 +1099,132 @@ async function runInit() {
|
|
|
1017
1099
|
console.log(` Created docs/start.md (write your project here)`);
|
|
1018
1100
|
}
|
|
1019
1101
|
|
|
1102
|
+
const globalConfigPath = path.join(GLOBAL_DIR, 'global.config.json');
|
|
1103
|
+
let useGlobal = false;
|
|
1104
|
+
let globalConfig = null;
|
|
1105
|
+
|
|
1106
|
+
if (fs.existsSync(globalConfigPath)) {
|
|
1107
|
+
try {
|
|
1108
|
+
globalConfig = JSON.parse(fs.readFileSync(globalConfigPath, 'utf8'));
|
|
1109
|
+
} catch {}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
const isInteractive = process.stdout.isTTY;
|
|
1113
|
+
|
|
1114
|
+
if (globalConfig && isInteractive) {
|
|
1115
|
+
console.log(`\n🕌 Found saved global default configuration:`);
|
|
1116
|
+
console.log(` Primary Engine: ${globalConfig.primary_engine} (${globalConfig.default_model || 'auto'})`);
|
|
1117
|
+
console.log(` Testing Route: ${globalConfig.model_routing?.testing?.model || 'auto'} via ${globalConfig.model_routing?.testing?.engine || 'auto'}`);
|
|
1118
|
+
console.log(` Review Route: ${globalConfig.model_routing?.review?.model || 'auto'} via ${globalConfig.model_routing?.review?.engine || 'auto'}`);
|
|
1119
|
+
|
|
1120
|
+
const ans = await askQuestion('\nUse default global engine and model routing? [Y/n] ');
|
|
1121
|
+
if (ans.toLowerCase() !== 'n' && ans.toLowerCase() !== 'no') {
|
|
1122
|
+
useGlobal = true;
|
|
1123
|
+
}
|
|
1124
|
+
} else if (globalConfig) {
|
|
1125
|
+
useGlobal = true;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
if (useGlobal && globalConfig) {
|
|
1129
|
+
console.log('\n✅ Applying global default configuration...');
|
|
1130
|
+
|
|
1131
|
+
const dirsToCreate = [
|
|
1132
|
+
DOCS_DIR,
|
|
1133
|
+
LOCAL_DIR_NAME,
|
|
1134
|
+
path.join(LOCAL_DIR_NAME, 'commands'),
|
|
1135
|
+
path.join(LOCAL_DIR_NAME, 'sessions'),
|
|
1136
|
+
];
|
|
1137
|
+
for (const dir of dirsToCreate) {
|
|
1138
|
+
const dirPath = path.join(cwd, dir);
|
|
1139
|
+
if (!fs.existsSync(dirPath)) {
|
|
1140
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
1141
|
+
console.log(` Created local directory: ${dir}`);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
const startMdPath = path.join(cwd, START_MD);
|
|
1146
|
+
if (!fs.existsSync(startMdPath)) {
|
|
1147
|
+
const startMdContent = [
|
|
1148
|
+
'# 🕌 IMH-Code — Project Start',
|
|
1149
|
+
'',
|
|
1150
|
+
'> **Imam Hussain Coding Harness Platform**',
|
|
1151
|
+
'> Answer the scope questions below, write your description, then run `imhcode plan`.',
|
|
1152
|
+
'',
|
|
1153
|
+
'---',
|
|
1154
|
+
'',
|
|
1155
|
+
'## ⚡ Quick Scope Check',
|
|
1156
|
+
'',
|
|
1157
|
+
'**Do you need a backend API / server-side logic?**',
|
|
1158
|
+
'> **Answer:** yes *(change to: yes / no / unsure)*',
|
|
1159
|
+
'',
|
|
1160
|
+
'**Do you need a mobile app (iOS/Android)?**',
|
|
1161
|
+
'> **Answer:** no *(change to: yes / no)*',
|
|
1162
|
+
'',
|
|
1163
|
+
'---',
|
|
1164
|
+
'',
|
|
1165
|
+
'## 📝 Your Project Description',
|
|
1166
|
+
'',
|
|
1167
|
+
'Write your complete project idea below. Be as detailed as possible.',
|
|
1168
|
+
'Include: what you\'re building, who it\'s for, key features, preferred stack,',
|
|
1169
|
+
'design preferences, integrations needed, business constraints.',
|
|
1170
|
+
'',
|
|
1171
|
+
'<!-- WRITE_PROMPT_HERE -->',
|
|
1172
|
+
'I want to build a SaaS dashboard for managing hotel room bookings with real-time availability,',
|
|
1173
|
+
'a Next.js frontend, Laravel API backend, and PostgreSQL database. Target users are hotel managers.',
|
|
1174
|
+
'Key features: room calendar, booking CRUD, guest management, reporting, email notifications.',
|
|
1175
|
+
'<!-- END_PROMPT -->',
|
|
1176
|
+
'',
|
|
1177
|
+
'---',
|
|
1178
|
+
'',
|
|
1179
|
+
'## 🚀 Next Step',
|
|
1180
|
+
'',
|
|
1181
|
+
'After filling in the scope and your description, run:',
|
|
1182
|
+
'',
|
|
1183
|
+
'```bash',
|
|
1184
|
+
'imhcode plan',
|
|
1185
|
+
'```',
|
|
1186
|
+
'',
|
|
1187
|
+
'IMH-Code will invoke your configured **planning AI model** (e.g. Claude Opus, GPT-5.5)',
|
|
1188
|
+
'to generate `docs/brainstorming.md` with smart, project-specific questions and answers.',
|
|
1189
|
+
].join('\n');
|
|
1190
|
+
fs.writeFileSync(startMdPath, startMdContent, 'utf8');
|
|
1191
|
+
console.log(` Created docs/start.md (write your project here)`);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
const localGitignore = path.join(cwd, '.gitignore');
|
|
1195
|
+
if (!fs.existsSync(localGitignore)) {
|
|
1196
|
+
const gitignoreTemplate = path.join(packageRoot, '.gitignore.template');
|
|
1197
|
+
if (fs.existsSync(gitignoreTemplate)) {
|
|
1198
|
+
fs.copyFileSync(gitignoreTemplate, localGitignore);
|
|
1199
|
+
console.log(` Created local .gitignore`);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
registerCliGlobally(imhcodeScriptPath);
|
|
1204
|
+
|
|
1205
|
+
const configPath = path.join(cwd, CONFIG_FILE);
|
|
1206
|
+
fs.writeFileSync(configPath, JSON.stringify(globalConfig, null, 2), 'utf8');
|
|
1207
|
+
console.log(`\n💾 Configuration saved: ${configPath}`);
|
|
1208
|
+
|
|
1209
|
+
console.log(`\n✅ ${PLATFORM_NAME} initialized successfully!`);
|
|
1210
|
+
console.log(`─`.repeat(60));
|
|
1211
|
+
console.log(`\n🕌 HOW TO BUILD WITH IMH-CODE:\n`);
|
|
1212
|
+
console.log(` 1. Open docs/start.md → Answer scope questions + write your description`);
|
|
1213
|
+
console.log(` 2. Run: imhcode plan`);
|
|
1214
|
+
console.log(` → Your planning AI generates brainstorming.md`);
|
|
1215
|
+
console.log(` 3. Open docs/brainstorming.md → Review/edit AI-recommended answers`);
|
|
1216
|
+
console.log(` 4. Run: imhcode plan`);
|
|
1217
|
+
console.log(` → Your planning AI generates sprint plans with correct agent routing`);
|
|
1218
|
+
console.log(` 5. Run: imhcode execute 1 → Sprint 1 (frontend tasks)`);
|
|
1219
|
+
console.log(` 6. Run: imhcode execute 2 → Sprint 2 (backend tasks)`);
|
|
1220
|
+
console.log(` 7. Run: imhcode test → Final testing + security + SEO`);
|
|
1221
|
+
console.log(` 8. Run: imhcode report → Generate PROJECT_REPORT.md`);
|
|
1222
|
+
console.log(`\n Run "imhcode --help" for all commands.`);
|
|
1223
|
+
console.log(`─`.repeat(60));
|
|
1224
|
+
console.log('');
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1020
1228
|
// Create .gitignore
|
|
1021
1229
|
const localGitignore = path.join(cwd, '.gitignore');
|
|
1022
1230
|
if (!fs.existsSync(localGitignore)) {
|
|
@@ -1028,7 +1236,7 @@ async function runInit() {
|
|
|
1028
1236
|
}
|
|
1029
1237
|
|
|
1030
1238
|
registerCliGlobally(imhcodeScriptPath);
|
|
1031
|
-
ensureCavemanAndGraphify();
|
|
1239
|
+
ensureCavemanAndGraphify(globalConfig?.skills_configured);
|
|
1032
1240
|
|
|
1033
1241
|
// ── Interactive Engine & Model Setup ────────────────────────────────────────
|
|
1034
1242
|
console.log('\n🔍 Scanning for local coding assistant CLIs...');
|
|
@@ -1037,12 +1245,11 @@ async function runInit() {
|
|
|
1037
1245
|
|
|
1038
1246
|
if (foundEngines.length === 0) {
|
|
1039
1247
|
console.warn('\n⚠️ No local coding assistant CLIs detected.');
|
|
1040
|
-
console.warn(' Supported: claude, opencode, codex, agy (Antigravity), qwen (QwenCode), mimo (MimoCode)');
|
|
1248
|
+
console.warn(' Supported: claude, opencode, codex, codex-fugu, agy (Antigravity), qwen (QwenCode), mimo (MimoCode)');
|
|
1041
1249
|
console.warn(' Install one and re-run "imhcode" to configure model routing.\n');
|
|
1042
1250
|
}
|
|
1043
1251
|
|
|
1044
1252
|
let primaryEngine = 'claude';
|
|
1045
|
-
const isInteractive = process.stdout.isTTY;
|
|
1046
1253
|
|
|
1047
1254
|
if (isInteractive && foundEngines.length > 0) {
|
|
1048
1255
|
console.log('\nFound the following local coding assistant CLIs:');
|
|
@@ -1114,6 +1321,18 @@ async function runInit() {
|
|
|
1114
1321
|
fs.writeFileSync(configPath, JSON.stringify(configData, null, 2), 'utf8');
|
|
1115
1322
|
console.log(`\n💾 Configuration saved: ${configPath}`);
|
|
1116
1323
|
|
|
1324
|
+
// Save to global config defaults as well
|
|
1325
|
+
const globalConfigData = {
|
|
1326
|
+
...configData,
|
|
1327
|
+
skills_configured: true,
|
|
1328
|
+
};
|
|
1329
|
+
try {
|
|
1330
|
+
fs.writeFileSync(globalConfigPath, JSON.stringify(globalConfigData, null, 2), 'utf8');
|
|
1331
|
+
console.log(`💾 Global defaults saved: ${globalConfigPath}`);
|
|
1332
|
+
} catch (e) {
|
|
1333
|
+
console.warn(`⚠️ Could not save global default configuration: ${e.message}`);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1117
1336
|
// Print final guide
|
|
1118
1337
|
console.log(`\n✅ ${PLATFORM_NAME} initialized successfully!`);
|
|
1119
1338
|
console.log(`─`.repeat(60));
|
|
@@ -1132,87 +1351,8 @@ async function runInit() {
|
|
|
1132
1351
|
console.log(`─`.repeat(60));
|
|
1133
1352
|
console.log('');
|
|
1134
1353
|
}
|
|
1135
|
-
|
|
1136
1354
|
// ─── Fix 4: Model Routing Setup Wizard (Ranked Scoring Algorithm) ─────────────
|
|
1137
1355
|
|
|
1138
|
-
/**
|
|
1139
|
-
* Ranked priority lists per category.
|
|
1140
|
-
* The algorithm scores each available model against these lists
|
|
1141
|
-
* and selects the highest-ranked match found in the installed engines.
|
|
1142
|
-
*/
|
|
1143
|
-
const MODEL_PRIORITY_RANKS = {
|
|
1144
|
-
frontend: [
|
|
1145
|
-
// Engine Model substring to match (lowercase, no hyphens/dots)
|
|
1146
|
-
['mimo', 'mimov25pro'],
|
|
1147
|
-
['mimo', 'mimov25'],
|
|
1148
|
-
['opencode', 'mimov25pro'],
|
|
1149
|
-
['opencode', 'mimov25'],
|
|
1150
|
-
['codex', 'gpt55'],
|
|
1151
|
-
['codex', 'gpt5'],
|
|
1152
|
-
['agy', 'claudeopus46'],
|
|
1153
|
-
['agy', 'claudeopus'],
|
|
1154
|
-
['opencode', 'gemini35flash'],
|
|
1155
|
-
['opencode', 'gemini25pro'],
|
|
1156
|
-
['claude', 'claudeopus46'],
|
|
1157
|
-
['claude', 'opus'],
|
|
1158
|
-
],
|
|
1159
|
-
backend: [
|
|
1160
|
-
['opencode', 'deepseekv4pro'],
|
|
1161
|
-
['opencode', 'deepseekv4'],
|
|
1162
|
-
['opencode', 'kimik27code'],
|
|
1163
|
-
['opencode', 'kimik2'],
|
|
1164
|
-
['opencode', 'qwen3coder480b'],
|
|
1165
|
-
['opencode', 'qwen3coder'],
|
|
1166
|
-
['codex', 'gpt55'],
|
|
1167
|
-
['codex', 'gpt5'],
|
|
1168
|
-
['opencode', 'gptoss120b'],
|
|
1169
|
-
['qwen', 'qwen3codermax'],
|
|
1170
|
-
['qwen', 'qwen3coder'],
|
|
1171
|
-
['claude', 'claudesonnet46'],
|
|
1172
|
-
['claude', 'sonnet'],
|
|
1173
|
-
],
|
|
1174
|
-
planning: [
|
|
1175
|
-
['agy', 'claudeopus46'],
|
|
1176
|
-
['agy', 'claudeopus'],
|
|
1177
|
-
['claude', 'claudeopus46'],
|
|
1178
|
-
['claude', 'opus'],
|
|
1179
|
-
['codex', 'gpt55'],
|
|
1180
|
-
['codex', 'gpt5'],
|
|
1181
|
-
['opencode', 'gemini31propreview'],
|
|
1182
|
-
['opencode', 'gemini31pro'],
|
|
1183
|
-
['opencode', 'deepseekv4pro'],
|
|
1184
|
-
],
|
|
1185
|
-
testing: [
|
|
1186
|
-
['codex', 'gpt55'],
|
|
1187
|
-
['codex', 'gpt5'],
|
|
1188
|
-
['agy', 'gptoss120bmedium'],
|
|
1189
|
-
['agy', 'gptoss120b'],
|
|
1190
|
-
['agy', 'claudeopus46'],
|
|
1191
|
-
['agy', 'claudeopus'],
|
|
1192
|
-
['opencode', 'deepseekv4pro'],
|
|
1193
|
-
['claude', 'claudeopus46'],
|
|
1194
|
-
],
|
|
1195
|
-
review: [
|
|
1196
|
-
['codex', 'gpt55'],
|
|
1197
|
-
['codex', 'gpt5'],
|
|
1198
|
-
['agy', 'claudesonnet46'],
|
|
1199
|
-
['agy', 'claudesonnet'],
|
|
1200
|
-
['opencode', 'gptoss120b'],
|
|
1201
|
-
['claude', 'claudesonnet46'],
|
|
1202
|
-
['opencode', 'deepseekv4pro'],
|
|
1203
|
-
],
|
|
1204
|
-
fast: [
|
|
1205
|
-
['opencode', 'deepseekv4flash'],
|
|
1206
|
-
['opencode', 'deepseekv4flash'],
|
|
1207
|
-
['opencode', 'gemini35flash'],
|
|
1208
|
-
['codex', 'gpt54mini'],
|
|
1209
|
-
['codex', 'gptmini'],
|
|
1210
|
-
['qwen', 'qwen3coderflash'],
|
|
1211
|
-
['claude', 'claudehaiku35'],
|
|
1212
|
-
['claude', 'haiku'],
|
|
1213
|
-
],
|
|
1214
|
-
};
|
|
1215
|
-
|
|
1216
1356
|
/**
|
|
1217
1357
|
* Normalize a model/engine string for fuzzy matching:
|
|
1218
1358
|
* lowercase, remove hyphens, dots, underscores, spaces.
|
|
@@ -2633,11 +2773,40 @@ function scanAssistantCLIs() {
|
|
|
2633
2773
|
claude: { name: 'Claude Code', path: resolveBinary('claude', ['~/.local/bin/claude', '/usr/local/bin/claude', '/opt/homebrew/bin/claude']), models: [], modelsCmd: b => `"${b}" --list-models 2>/dev/null || echo ''` },
|
|
2634
2774
|
opencode: { name: 'OpenCode', path: resolveBinary('opencode', ['~/.opencode/bin/opencode', '/usr/local/bin/opencode']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null` },
|
|
2635
2775
|
codex: { name: 'Codex (OpenAI)', path: resolveBinary('codex', ['~/Library/PhpWebStudy/env/node/bin/codex', '/usr/local/bin/codex']), models: [], modelsCmd: b => `"${b}" debug models 2>/dev/null` },
|
|
2776
|
+
'codex-fugu': { name: 'Codex Fugu', path: resolveBinary('codex-fugu', ['~/.local/bin/codex-fugu', '/usr/local/bin/codex-fugu', '/opt/homebrew/bin/codex-fugu']), models: [], modelsCmd: b => `"${b}" debug models 2>/dev/null || echo ''` },
|
|
2636
2777
|
agy: { name: 'Antigravity CLI (agy)', path: resolveBinary('agy', ['~/.local/bin/agy', '/usr/local/bin/agy', '/opt/homebrew/bin/agy']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
|
|
2637
2778
|
qwen: { name: 'QwenCode (qwen)', path: resolveBinary('qwen', ['~/.local/bin/qwen', '/usr/local/bin/qwen', '/opt/homebrew/bin/qwen']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
|
|
2638
2779
|
mimo: { name: 'MimoCode (mimo)', path: resolveBinary('mimo', ['~/.local/bin/mimo', '/usr/local/bin/mimo', '/opt/homebrew/bin/mimo', '~/.mimo/bin/mimo']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
|
|
2639
2780
|
};
|
|
2640
2781
|
|
|
2782
|
+
// Scan for agy2, agy3, agy4, etc.
|
|
2783
|
+
for (let i = 2; i <= 10; i++) {
|
|
2784
|
+
const key = `agy${i}`;
|
|
2785
|
+
const binaryPath = resolveBinary(key, [
|
|
2786
|
+
`~/.local/bin/${key}`,
|
|
2787
|
+
`/usr/local/bin/${key}`,
|
|
2788
|
+
`/opt/homebrew/bin/${key}`,
|
|
2789
|
+
]);
|
|
2790
|
+
if (binaryPath) {
|
|
2791
|
+
engines[key] = {
|
|
2792
|
+
name: `Antigravity CLI (${key})`,
|
|
2793
|
+
path: binaryPath,
|
|
2794
|
+
models: [],
|
|
2795
|
+
modelsCmd: b => `"${b}" models 2>/dev/null || echo ''`
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
const fallbackModels = {
|
|
2801
|
+
claude: ['claude-3-5-sonnet', 'claude-3-opus', 'claude-3-5-haiku', 'claude-opus-4-6', 'claude-sonnet-4-6', 'claude-haiku-3-5', 'claude-sonnet-5', 'claude-fable-5', 'claude-opus-4-8', 'opus', 'sonnet', 'haiku'],
|
|
2802
|
+
opencode: ['mimo-vl-v2.5-pro', 'deepseek-v4-pro', 'deepseek-v4-flash', 'gemini-3.5-flash', 'kimi-k2.7-code', 'qwen-3-coder-480b', 'gpt-oss-120b'],
|
|
2803
|
+
codex: ['gpt-5.5', 'gpt-5.4-mini', 'gpt-mini'],
|
|
2804
|
+
'codex-fugu': ['fugu', 'fugu-ultra'],
|
|
2805
|
+
agy: ['claude-opus-4-6', 'gemini-3.5-flash'],
|
|
2806
|
+
qwen: ['qwen3-coder-max', 'qwen3-coder-flash'],
|
|
2807
|
+
mimo: ['mimo-vl-v2.5-pro', 'mimo-vl-v2.5']
|
|
2808
|
+
};
|
|
2809
|
+
|
|
2641
2810
|
for (const [key, eng] of Object.entries(engines)) {
|
|
2642
2811
|
if (!eng.path) continue;
|
|
2643
2812
|
try {
|
|
@@ -2652,6 +2821,11 @@ function scanAssistantCLIs() {
|
|
|
2652
2821
|
}
|
|
2653
2822
|
if (models.length > 0) eng.models = models;
|
|
2654
2823
|
} catch { eng.models = []; }
|
|
2824
|
+
|
|
2825
|
+
const baseKey = key.startsWith('agy') ? 'agy' : key;
|
|
2826
|
+
if (eng.models.length === 0 && fallbackModels[baseKey]) {
|
|
2827
|
+
eng.models = fallbackModels[baseKey];
|
|
2828
|
+
}
|
|
2655
2829
|
}
|
|
2656
2830
|
|
|
2657
2831
|
return engines;
|
|
@@ -2725,7 +2899,11 @@ function registerCliGlobally(imhcodeScriptPath) {
|
|
|
2725
2899
|
}
|
|
2726
2900
|
}
|
|
2727
2901
|
|
|
2728
|
-
function ensureCavemanAndGraphify() {
|
|
2902
|
+
function ensureCavemanAndGraphify(skillsAlreadyConfigured) {
|
|
2903
|
+
if (skillsAlreadyConfigured) {
|
|
2904
|
+
console.log('\n🔍 Token-saving skills already configured globally. Skipping installation checks.');
|
|
2905
|
+
return;
|
|
2906
|
+
}
|
|
2729
2907
|
console.log('\n🔍 Checking token-saving skills...');
|
|
2730
2908
|
let skillsInstalled = false;
|
|
2731
2909
|
try { execSync('npx --no-install skills --version', { stdio: 'ignore' }); skillsInstalled = true; } catch { /* not installed */ }
|
|
@@ -3129,7 +3307,17 @@ async function runTuiCommand() {
|
|
|
3129
3307
|
|
|
3130
3308
|
function detectProjectState(dir) {
|
|
3131
3309
|
const hasConfig = fs.existsSync(path.join(dir, CONFIG_FILE));
|
|
3132
|
-
|
|
3310
|
+
let hasStart = fs.existsSync(path.join(dir, START_MD));
|
|
3311
|
+
if (hasStart) {
|
|
3312
|
+
try {
|
|
3313
|
+
const content = fs.readFileSync(path.join(dir, START_MD), 'utf8');
|
|
3314
|
+
if (content.includes('hotel room bookings with real-time availability')) {
|
|
3315
|
+
hasStart = false; // default template hasn't been edited/replaced yet
|
|
3316
|
+
}
|
|
3317
|
+
} catch {
|
|
3318
|
+
hasStart = false;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3133
3321
|
const hasBrainstorm = fs.existsSync(path.join(dir, BRAINSTORM_MD));
|
|
3134
3322
|
const hasSprints = detectSprintDocs(dir);
|
|
3135
3323
|
|
|
@@ -3369,21 +3557,29 @@ async function runTuiCommand() {
|
|
|
3369
3557
|
process.stdout.write(ANSI.showCursor + '\n');
|
|
3370
3558
|
|
|
3371
3559
|
console.log(ANSI.cyan + '\n🕌 IMH-Code — Write Requirements' + ANSI.reset);
|
|
3372
|
-
console.log('Enter your project description below
|
|
3560
|
+
console.log('Enter your project description below. When done, type /submit or a single . on a new line to finish:\n');
|
|
3373
3561
|
|
|
3374
3562
|
const lines = [];
|
|
3375
3563
|
const rlInput = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3376
3564
|
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3565
|
+
await new Promise(resolve => {
|
|
3566
|
+
rlInput.on('line', (line) => {
|
|
3567
|
+
if (line.trim() === '/submit' || line.trim() === '.') {
|
|
3568
|
+
resolve();
|
|
3569
|
+
return;
|
|
3570
|
+
}
|
|
3571
|
+
lines.push(line);
|
|
3572
|
+
});
|
|
3573
|
+
rlInput.on('close', () => {
|
|
3574
|
+
resolve();
|
|
3575
|
+
});
|
|
3576
|
+
});
|
|
3382
3577
|
|
|
3383
3578
|
const desc = lines.join('\n');
|
|
3579
|
+
rlInput.close();
|
|
3580
|
+
|
|
3384
3581
|
if (desc.trim() === '') {
|
|
3385
3582
|
console.log('⚠️ No requirements entered. Aborting.');
|
|
3386
|
-
rlInput.close();
|
|
3387
3583
|
inSubMode = false;
|
|
3388
3584
|
if (isRaw) process.stdin.setRawMode(true);
|
|
3389
3585
|
process.stdin.resume();
|
|
@@ -3391,10 +3587,12 @@ async function runTuiCommand() {
|
|
|
3391
3587
|
break;
|
|
3392
3588
|
}
|
|
3393
3589
|
|
|
3590
|
+
const rlQuestions = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3591
|
+
|
|
3394
3592
|
// Ask for backend
|
|
3395
3593
|
let backend = 'yes';
|
|
3396
3594
|
while (true) {
|
|
3397
|
-
const ans = await new Promise(res =>
|
|
3595
|
+
const ans = await new Promise(res => rlQuestions.question('\nDo you need a backend API / server-side logic? (yes/no/unsure) [default: yes]: ', res));
|
|
3398
3596
|
const cleanAns = ans.trim().toLowerCase();
|
|
3399
3597
|
if (cleanAns === '') { backend = 'yes'; break; }
|
|
3400
3598
|
if (['yes', 'no', 'unsure'].includes(cleanAns)) { backend = cleanAns; break; }
|
|
@@ -3404,14 +3602,14 @@ async function runTuiCommand() {
|
|
|
3404
3602
|
// Ask for mobile
|
|
3405
3603
|
let mobile = 'no';
|
|
3406
3604
|
while (true) {
|
|
3407
|
-
const ans = await new Promise(res =>
|
|
3605
|
+
const ans = await new Promise(res => rlQuestions.question('Do you need a mobile app (iOS/Android)? (yes/no) [default: no]: ', res));
|
|
3408
3606
|
const cleanAns = ans.trim().toLowerCase();
|
|
3409
3607
|
if (cleanAns === '') { mobile = 'no'; break; }
|
|
3410
3608
|
if (['yes', 'no'].includes(cleanAns)) { mobile = cleanAns; break; }
|
|
3411
3609
|
console.log('❌ Invalid input. Please enter yes or no.');
|
|
3412
3610
|
}
|
|
3413
3611
|
|
|
3414
|
-
|
|
3612
|
+
rlQuestions.close();
|
|
3415
3613
|
|
|
3416
3614
|
// Write start.md template
|
|
3417
3615
|
const startMdPath = path.join(cwd, START_MD);
|
|
@@ -27,8 +27,13 @@ export declare class CodexCLIAdapter implements EngineAdapter {
|
|
|
27
27
|
readonly name = "codex";
|
|
28
28
|
run(prompt: string, model: string): Promise<string>;
|
|
29
29
|
}
|
|
30
|
+
export declare class CodexFuguCLIAdapter implements EngineAdapter {
|
|
31
|
+
readonly name = "codex-fugu";
|
|
32
|
+
run(prompt: string, model: string): Promise<string>;
|
|
33
|
+
}
|
|
30
34
|
export declare class AgyCLIAdapter implements EngineAdapter {
|
|
31
|
-
readonly name
|
|
35
|
+
readonly name: string;
|
|
36
|
+
constructor(name?: string);
|
|
32
37
|
run(prompt: string, model: string): Promise<string>;
|
|
33
38
|
}
|
|
34
39
|
export declare class QwenCodeCLIAdapter implements EngineAdapter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/orchestrator/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAoF7C,qBAAa,aAAc,YAAW,aAAa;IACjD,QAAQ,CAAC,IAAI,aAAa;IAEpB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAe3D;AAID,qBAAa,oBAAqB,YAAW,aAAa;IACxD,QAAQ,CAAC,IAAI,YAAY;IAEnB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/orchestrator/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAoF7C,qBAAa,aAAc,YAAW,aAAa;IACjD,QAAQ,CAAC,IAAI,aAAa;IAEpB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAe3D;AAID,qBAAa,oBAAqB,YAAW,aAAa;IACxD,QAAQ,CAAC,IAAI,YAAY;IAEnB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAkB1D;AAID,qBAAa,kBAAmB,YAAW,aAAa;IACtD,QAAQ,CAAC,IAAI,cAAc;IAErB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAwB1D;AAID,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,IAAI,WAAW;IAElB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAmC1D;AAID,qBAAa,mBAAoB,YAAW,aAAa;IACvD,QAAQ,CAAC,IAAI,gBAAgB;IAEvB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAoC1D;AAOD,qBAAa,aAAc,YAAW,aAAa;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,GAAE,MAAc;IAI1B,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAkB1D;AAOD,qBAAa,kBAAmB,YAAW,aAAa;IACtD,QAAQ,CAAC,IAAI,UAAU;IAEjB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAe1D;AAQD,qBAAa,kBAAmB,YAAW,aAAa;IACtD,QAAQ,CAAC,IAAI,UAAU;IAEjB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAgB1D;AAID,wBAAgB,UAAU,CACxB,IAAI,EAAE,OAAO,EACb,eAAe,CAAC,EAAE,MAAM,GACvB,aAAa,CAkGf"}
|