@leejungkiin/awkit 1.7.4 → 1.7.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/README.md +42 -5
- package/bin/awk.js +579 -15
- package/core/GEMINI.md +4 -0
- package/core/GEMINI.md.bak +4 -0
- package/core/GreetingEngine/index.js +225 -0
- package/core/GreetingEngine/locales/en.json +6 -0
- package/core/GreetingEngine/locales/ja.json +6 -0
- package/core/GreetingEngine/locales/vi.json +6 -0
- package/core/GreetingEngine/test.js +37 -0
- package/docs/PRD.md +57 -0
- package/docs/brainstorm_multi_agent_cli.md +211 -0
- package/docs/history/PRD.v1.md +55 -0
- package/docs/history/PRD.v2.md +57 -0
- package/docs/history/memoizedfibonacci_spec.v1.md +127 -0
- package/docs/specs/greetingapp_spec.md +97 -0
- package/docs/specs/memoizedfibonacci_spec.md +211 -0
- package/package.json +1 -1
- package/scripts/multi-model-pipeline.js +292 -50
- package/scripts/qwen-exec.js +147 -0
- package/skills/claude-planner/SKILL.md +24 -0
- package/skills/codex-conductor/SKILL.md +25 -1
- package/skills/qwen-conductor/SKILL.md +100 -0
- package/workflows/multi-agent-pipeline.md +52 -0
package/bin/awk.js
CHANGED
|
@@ -1945,6 +1945,22 @@ function cmdStatus() {
|
|
|
1945
1945
|
}
|
|
1946
1946
|
|
|
1947
1947
|
log('');
|
|
1948
|
+
|
|
1949
|
+
// ── GitNexus Info ──────────────────────────────────────────────────────
|
|
1950
|
+
const cwd = process.cwd();
|
|
1951
|
+
const gitnexusDir = path.join(cwd, '.gitnexus');
|
|
1952
|
+
if (fs.existsSync(gitnexusDir)) {
|
|
1953
|
+
const registry = readGitnexusRegistry();
|
|
1954
|
+
const match = registry.find(r => r.path === cwd);
|
|
1955
|
+
if (match) {
|
|
1956
|
+
const stats = match.stats || {};
|
|
1957
|
+
log(`${C.bold}GitNexus Info:${C.reset}`);
|
|
1958
|
+
log(` Active repo: ${C.green}${match.name}${C.reset} (${stats.nodes || 0} nodes, ${stats.edges || 0} relations)`);
|
|
1959
|
+
log(` Tip: Run 'awkit index' to refresh index or 'awkit status gn' for details.`);
|
|
1960
|
+
log('');
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1948
1964
|
log(`${C.gray}Tip: 'awkit sync' = harvest (pull live→repo) + install (push repo→live)${C.reset}`);
|
|
1949
1965
|
log('');
|
|
1950
1966
|
}
|
|
@@ -2026,6 +2042,63 @@ function cmdBuild() {
|
|
|
2026
2042
|
}
|
|
2027
2043
|
}
|
|
2028
2044
|
|
|
2045
|
+
// ─── Run: Safe project-specific run/start script execution ──────────────────
|
|
2046
|
+
|
|
2047
|
+
function cmdRun(runArgs = []) {
|
|
2048
|
+
log('');
|
|
2049
|
+
log(`${C.cyan}${C.bold}🚀 AWK Run Control${C.reset}`);
|
|
2050
|
+
log('');
|
|
2051
|
+
|
|
2052
|
+
const pjPath = path.join(process.cwd(), '.project-identity');
|
|
2053
|
+
const pj = readJsonFile(pjPath, {});
|
|
2054
|
+
|
|
2055
|
+
if (!pj.automation || !pj.automation.run) {
|
|
2056
|
+
warn('No run configuration found in .project-identity under "automation.run".');
|
|
2057
|
+
log('Skipping run...');
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
const { enabled, command } = pj.automation.run;
|
|
2062
|
+
|
|
2063
|
+
if (!enabled) {
|
|
2064
|
+
warn('Run is disabled for this project (automation.run.enabled is false).');
|
|
2065
|
+
log('Skipping run...');
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
if (!command) {
|
|
2070
|
+
err('Run command is not configured in .project-identity (automation.run.command is empty).');
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
const fullCommand = runArgs.length > 0 ? `${command} ${runArgs.join(' ')}` : command;
|
|
2075
|
+
|
|
2076
|
+
info(`Running command: ${C.bold}${fullCommand}${C.reset}`);
|
|
2077
|
+
try {
|
|
2078
|
+
execSync(fullCommand, { stdio: 'inherit' });
|
|
2079
|
+
} catch (e) {
|
|
2080
|
+
log('');
|
|
2081
|
+
err(`Run failed: ${e.message}`);
|
|
2082
|
+
process.exit(e.status || 1);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
function cmdTask(taskArgs = []) {
|
|
2087
|
+
try {
|
|
2088
|
+
execSync(`symphony task ${taskArgs.join(' ')}`, { stdio: 'inherit' });
|
|
2089
|
+
} catch (e) {
|
|
2090
|
+
process.exit(e.status || 1);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
function cmdProject(projectArgs = []) {
|
|
2095
|
+
try {
|
|
2096
|
+
execSync(`symphony project ${projectArgs.join(' ')}`, { stdio: 'inherit' });
|
|
2097
|
+
} catch (e) {
|
|
2098
|
+
process.exit(e.status || 1);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2029
2102
|
async function cmdAdmin() {
|
|
2030
2103
|
info('Mở Symphony Dashboard...');
|
|
2031
2104
|
try {
|
|
@@ -2115,6 +2188,59 @@ async function cmdRestart() {
|
|
|
2115
2188
|
}
|
|
2116
2189
|
}
|
|
2117
2190
|
|
|
2191
|
+
function cmdGreet(args) {
|
|
2192
|
+
let name = 'Guest';
|
|
2193
|
+
let lang = 'en';
|
|
2194
|
+
let timezone = undefined;
|
|
2195
|
+
|
|
2196
|
+
for (let i = 0; i < args.length; i++) {
|
|
2197
|
+
const arg = args[i];
|
|
2198
|
+
if (arg === '--help' || arg === '-h') {
|
|
2199
|
+
log('');
|
|
2200
|
+
log(`${C.cyan}${C.bold}👋 awkit greet — Personalized greetings${C.reset}`);
|
|
2201
|
+
log('');
|
|
2202
|
+
log('Usage:');
|
|
2203
|
+
log(' awkit greet [options]');
|
|
2204
|
+
log('');
|
|
2205
|
+
log('Options:');
|
|
2206
|
+
log(' -n, --name <name> Name of the person to greet (default: "Guest")');
|
|
2207
|
+
log(' -l, --lang <lang> Language code (en, vi, ja) (default: "en")');
|
|
2208
|
+
log(' -t, --timezone <tz> Timezone string (default: system timezone)');
|
|
2209
|
+
log(' -h, --help Show this help message');
|
|
2210
|
+
log('');
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
if ((arg === '--name' || arg === '-n') && args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
2214
|
+
name = args[i + 1];
|
|
2215
|
+
i++;
|
|
2216
|
+
} else if (arg.startsWith('--name=')) {
|
|
2217
|
+
name = arg.split('=')[1];
|
|
2218
|
+
} else if ((arg === '--lang' || arg === '-l') && args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
2219
|
+
lang = args[i + 1];
|
|
2220
|
+
i++;
|
|
2221
|
+
} else if (arg.startsWith('--lang=')) {
|
|
2222
|
+
lang = arg.split('=')[1];
|
|
2223
|
+
} else if ((arg === '--timezone' || arg === '-t') && args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
2224
|
+
timezone = args[i + 1];
|
|
2225
|
+
i++;
|
|
2226
|
+
} else if (arg.startsWith('--timezone=')) {
|
|
2227
|
+
timezone = arg.split('=')[1];
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
try {
|
|
2232
|
+
const GreetingEngine = require('../core/GreetingEngine');
|
|
2233
|
+
const result = GreetingEngine.generateGreeting({ name, lang, timezone });
|
|
2234
|
+
if (result.status === 'success') {
|
|
2235
|
+
log(result.data.message);
|
|
2236
|
+
} else {
|
|
2237
|
+
err('Failed to generate greeting');
|
|
2238
|
+
}
|
|
2239
|
+
} catch (e) {
|
|
2240
|
+
err('Failed to execute Greeting Engine: ' + e.message);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2118
2244
|
function cmdHelp() {
|
|
2119
2245
|
const line = `${C.gray}${'─'.repeat(56)}${C.reset}`;
|
|
2120
2246
|
log('');
|
|
@@ -2138,9 +2264,13 @@ function cmdHelp() {
|
|
|
2138
2264
|
if (identity.automation && identity.automation.build && identity.automation.build.enabled) {
|
|
2139
2265
|
bCmd = identity.automation.build.command || 'Enabled';
|
|
2140
2266
|
}
|
|
2267
|
+
let rCmd = 'Disabled';
|
|
2268
|
+
if (identity.automation && identity.automation.run && identity.automation.run.enabled) {
|
|
2269
|
+
rCmd = identity.automation.run.command || 'Enabled';
|
|
2270
|
+
}
|
|
2141
2271
|
|
|
2142
2272
|
log(`${C.cyan}👉 Active Project: ${icon} ${C.bold}${name}${C.reset}`);
|
|
2143
|
-
log(` [${pType} | Build Control: ${bCmd === 'Disabled' ? C.yellow + 'Manual' : C.green + bCmd}${C.reset}]`);
|
|
2273
|
+
log(` [${pType} | Build Control: ${bCmd === 'Disabled' ? C.yellow + 'Manual' : C.green + bCmd} | Run Control: ${rCmd === 'Disabled' ? C.yellow + 'Manual' : C.green + rCmd}${C.reset}]`);
|
|
2144
2274
|
log(` Run ${C.green}awkit identity${C.reset} for full configuration details.`);
|
|
2145
2275
|
log('');
|
|
2146
2276
|
} catch (_) {}
|
|
@@ -2158,6 +2288,10 @@ function cmdHelp() {
|
|
|
2158
2288
|
log(` ${C.green}credentials list${C.reset} List stored API keys`);
|
|
2159
2289
|
log(` ${C.green}credentials set${C.reset} <k> <v> Set API key (e.g., gemini_api_key, openrouter_api_key)`);
|
|
2160
2290
|
log(` ${C.green}set-openrouter${C.reset} <key> Shorthand for setting OpenRouter API Key`);
|
|
2291
|
+
log(` ${C.green}config-global list${C.reset} List all global configurations`);
|
|
2292
|
+
log(` ${C.green}config-global set${C.reset} <k> <v> Set global configuration`);
|
|
2293
|
+
log(` ${C.green}config-global audio${C.reset} <on|off> Turn audio alerts on/off globally`);
|
|
2294
|
+
log(` ${C.green}config audio${C.reset} <on|off> Shorthand to turn audio alerts on/off globally`);
|
|
2161
2295
|
log('');
|
|
2162
2296
|
|
|
2163
2297
|
// Project Init
|
|
@@ -2169,6 +2303,7 @@ function cmdHelp() {
|
|
|
2169
2303
|
log(` ${C.gray} CODEBASE.md, thiết lập router (AGENTS.md, CLAUDE.md)${C.reset}`);
|
|
2170
2304
|
log(` ${C.green}identity${C.reset} Show project identity & active configurations (alias: config)`);
|
|
2171
2305
|
log(` ${C.green}build${C.reset} Run project build based on .project-identity config`);
|
|
2306
|
+
log(` ${C.green}run${C.reset} [args] Run project-specific start/dev commands based on config`);
|
|
2172
2307
|
log('');
|
|
2173
2308
|
|
|
2174
2309
|
// Maintenance
|
|
@@ -2195,10 +2330,21 @@ function cmdHelp() {
|
|
|
2195
2330
|
log(` ${C.green}sync${C.reset} Full sync: harvest + install (one shot)`);
|
|
2196
2331
|
log('');
|
|
2197
2332
|
|
|
2333
|
+
// GreetingApp
|
|
2334
|
+
log(`${C.bold}👋 GreetingApp${C.reset}`);
|
|
2335
|
+
log(line);
|
|
2336
|
+
log(` ${C.green}greet${C.reset} [options] Generate personalized dynamic greeting`);
|
|
2337
|
+
log(` ${C.gray} -n, --name <name>${C.reset} User name to greet (default: Guest)`);
|
|
2338
|
+
log(` ${C.gray} -l, --lang <lang>${C.reset} Language code: en, vi, ja (default: en)`);
|
|
2339
|
+
log(` ${C.gray} -t, --timezone <tz>${C.reset} Timezone parameter`);
|
|
2340
|
+
log('');
|
|
2341
|
+
|
|
2198
2342
|
// Symphony
|
|
2199
2343
|
log(`${C.bold}🎶 Symphony${C.reset}`);
|
|
2200
2344
|
log(line);
|
|
2201
2345
|
log(` ${C.green}admin${C.reset} Khởi động Symphony Dashboard`);
|
|
2346
|
+
log(` ${C.green}task${C.reset} [args] Manage Symphony tasks directly`);
|
|
2347
|
+
log(` ${C.green}project${C.reset} [args] Manage Symphony projects directly`);
|
|
2202
2348
|
log('');
|
|
2203
2349
|
|
|
2204
2350
|
// Packs
|
|
@@ -2222,11 +2368,23 @@ function cmdHelp() {
|
|
|
2222
2368
|
log('');
|
|
2223
2369
|
|
|
2224
2370
|
// Pipeline
|
|
2225
|
-
log(`${C.bold}🔗 Pipeline${C.reset}`);
|
|
2371
|
+
log(`${C.bold}🔗 Pipeline & Sub-Agents${C.reset}`);
|
|
2226
2372
|
log(line);
|
|
2227
|
-
log(` ${C.green}pipeline plan${C.reset} <Feature> Lập kế hoạch kiến trúc (
|
|
2228
|
-
log(` ${C.green}pipeline ui${C.reset} <Feature> Thiết kế shell & GUI assets (Codex)`);
|
|
2229
|
-
log(` ${C.green}pipeline code${C.reset} <Feature> Thực thi viết code & review (Gemini
|
|
2373
|
+
log(` ${C.green}pipeline plan${C.reset} <Feature> Lập kế hoạch kiến trúc (Claude / Gemini fallback)`);
|
|
2374
|
+
log(` ${C.green}pipeline ui${C.reset} <Feature> Thiết kế shell & GUI assets (Codex / Gemini fallback)`);
|
|
2375
|
+
log(` ${C.green}pipeline code${C.reset} <Feature> Thực thi viết code & review (Qwen / Gemini fallback)`);
|
|
2376
|
+
log('');
|
|
2377
|
+
log(` ${C.bold}🤖 Multi-Agent Collaborative System${C.reset}`);
|
|
2378
|
+
log(` AWKit integrates third-party CLI agents to optimize reasoning quality & costs:`);
|
|
2379
|
+
log(` • ${C.cyan}Claude Code${C.reset} ➜ Architect planning & complex reasoning (Gate 2/4)`);
|
|
2380
|
+
log(` • ${C.cyan}Codex CLI${C.reset} ➜ UI shell design, asset generation & reviews (Gate 2.5/5)`);
|
|
2381
|
+
log(` • ${C.cyan}Qwen Coder${C.reset} ➜ Fast local boilerplate code execution (Gate 4)`);
|
|
2382
|
+
log(` • ${C.cyan}Gemini Flash${C.reset} ➜ Central coordination, active context & fallback router`);
|
|
2383
|
+
log('');
|
|
2384
|
+
log(` To query or configure active runners and alerts:`);
|
|
2385
|
+
log(` - Run ${C.green}awkit config list${C.reset} to show current settings`);
|
|
2386
|
+
log(` - Run ${C.green}awkit config runners${C.reset} to check paths & binary availability`);
|
|
2387
|
+
log(` - Run ${C.green}awkit config <runner> <on|off>${C.reset} to toggle specific runner`);
|
|
2230
2388
|
log('');
|
|
2231
2389
|
|
|
2232
2390
|
// Trello
|
|
@@ -2252,15 +2410,16 @@ function cmdHelp() {
|
|
|
2252
2410
|
log('');
|
|
2253
2411
|
|
|
2254
2412
|
// GitNexus
|
|
2255
|
-
log(`${C.bold}🔍 GitNexus${C.reset}`);
|
|
2413
|
+
log(`${C.bold}🔍 GitNexus (Shortcuts: index, clean, list)${C.reset}`);
|
|
2256
2414
|
log(line);
|
|
2257
|
-
log(` ${C.green}
|
|
2258
|
-
log(` ${C.green}
|
|
2259
|
-
log(` ${C.green}
|
|
2260
|
-
log(` ${C.green}
|
|
2415
|
+
log(` ${C.green}index${C.reset} Index/refresh current codebase (alias: analyze)`);
|
|
2416
|
+
log(` ${C.green}list${C.reset} List all indexed repositories`);
|
|
2417
|
+
log(` ${C.green}status gn${C.reset} Show current project index info (or 'gn status')`);
|
|
2418
|
+
log(` ${C.green}clean${C.reset} Interactive cleanup of old indexes`);
|
|
2419
|
+
log(` ${C.green}clean${C.reset} ${C.gray}<name...>${C.reset} Remove specific repo(s) by name`);
|
|
2261
2420
|
log(` ${C.gray} --stale${C.reset} Auto-remove repos with missing paths`);
|
|
2262
2421
|
log(` ${C.gray} --all${C.reset} Remove all except current project`);
|
|
2263
|
-
log(` ${C.gray} Alias: gn${C.reset}`);
|
|
2422
|
+
log(` ${C.gray} Alias: gn / gitnexus${C.reset}`);
|
|
2264
2423
|
log('');
|
|
2265
2424
|
|
|
2266
2425
|
// Available packs
|
|
@@ -4172,9 +4331,34 @@ function cmdGitnexus(args) {
|
|
|
4172
4331
|
break;
|
|
4173
4332
|
}
|
|
4174
4333
|
|
|
4334
|
+
case 'index':
|
|
4335
|
+
case 'analyze':
|
|
4336
|
+
case 'build': {
|
|
4337
|
+
const cwd = process.cwd();
|
|
4338
|
+
const usePnpm = fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'));
|
|
4339
|
+
const indexCmd = usePnpm ? 'pnpm' : 'npx';
|
|
4340
|
+
const indexArgs = usePnpm ? ['dlx', 'gitnexus', 'analyze'] : ['-y', 'gitnexus', 'analyze'];
|
|
4341
|
+
|
|
4342
|
+
info(`Indexing codebase with GitNexus (${usePnpm ? 'pnpm' : 'npx'})...`);
|
|
4343
|
+
dim(`Running: ${indexCmd} ${indexArgs.join(' ')}`);
|
|
4344
|
+
|
|
4345
|
+
const result = spawnSync(indexCmd, indexArgs, {
|
|
4346
|
+
cwd,
|
|
4347
|
+
stdio: 'inherit',
|
|
4348
|
+
shell: true
|
|
4349
|
+
});
|
|
4350
|
+
|
|
4351
|
+
if (result.status === 0) {
|
|
4352
|
+
ok('GitNexus index successfully refreshed! ✨');
|
|
4353
|
+
} else {
|
|
4354
|
+
err(`GitNexus indexing failed with exit code ${result.status}`);
|
|
4355
|
+
}
|
|
4356
|
+
break;
|
|
4357
|
+
}
|
|
4358
|
+
|
|
4175
4359
|
default:
|
|
4176
4360
|
err(`Unknown gitnexus sub-command: ${sub}`);
|
|
4177
|
-
log(` Available: list, status, clean`);
|
|
4361
|
+
log(` Available: index, list, status, clean`);
|
|
4178
4362
|
break;
|
|
4179
4363
|
}
|
|
4180
4364
|
}
|
|
@@ -4352,6 +4536,14 @@ function cmdIdentity(args = []) {
|
|
|
4352
4536
|
} else {
|
|
4353
4537
|
log(` ${C.bold}Build Control:${C.reset} ${C.yellow}Not Configured (Manual Mode)${C.reset}`);
|
|
4354
4538
|
}
|
|
4539
|
+
if (identity.automation && identity.automation.run) {
|
|
4540
|
+
const r = identity.automation.run;
|
|
4541
|
+
const statusStr = r.enabled ? `${C.green}Enabled (Safe Auto-Run via awkit run)${C.reset}` : `${C.yellow}Disabled / Manual Only${C.reset}`;
|
|
4542
|
+
log(` ${C.bold}Run Control:${C.reset} ${statusStr}`);
|
|
4543
|
+
log(` ${C.bold}Run Command:${C.reset} ${C.cyan}${r.command || 'N/A'}${C.reset}`);
|
|
4544
|
+
} else {
|
|
4545
|
+
log(` ${C.bold}Run Control:${C.reset} ${C.yellow}Not Configured (Manual Mode)${C.reset}`);
|
|
4546
|
+
}
|
|
4355
4547
|
log('');
|
|
4356
4548
|
|
|
4357
4549
|
// Automation Gates
|
|
@@ -4488,6 +4680,335 @@ function cmdServe(args) {
|
|
|
4488
4680
|
});
|
|
4489
4681
|
}
|
|
4490
4682
|
|
|
4683
|
+
const GLOBAL_CONFIG_PATH = path.join(HOME, '.awkit_config.json');
|
|
4684
|
+
|
|
4685
|
+
function readGlobalConfig() {
|
|
4686
|
+
const defaultConf = {
|
|
4687
|
+
audioAlerts: true,
|
|
4688
|
+
runners: {
|
|
4689
|
+
claude: true,
|
|
4690
|
+
codex: true,
|
|
4691
|
+
qwen: true
|
|
4692
|
+
}
|
|
4693
|
+
};
|
|
4694
|
+
if (!fs.existsSync(GLOBAL_CONFIG_PATH)) return defaultConf;
|
|
4695
|
+
try {
|
|
4696
|
+
const parsed = JSON.parse(fs.readFileSync(GLOBAL_CONFIG_PATH, 'utf8'));
|
|
4697
|
+
return {
|
|
4698
|
+
...defaultConf,
|
|
4699
|
+
...parsed,
|
|
4700
|
+
runners: {
|
|
4701
|
+
...defaultConf.runners,
|
|
4702
|
+
...(parsed.runners || {})
|
|
4703
|
+
}
|
|
4704
|
+
};
|
|
4705
|
+
} catch (_) {
|
|
4706
|
+
return defaultConf;
|
|
4707
|
+
}
|
|
4708
|
+
}
|
|
4709
|
+
|
|
4710
|
+
function writeGlobalConfig(config) {
|
|
4711
|
+
try {
|
|
4712
|
+
fs.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
4713
|
+
return true;
|
|
4714
|
+
} catch (e) {
|
|
4715
|
+
err(`Failed to write global config: ${e.message}`);
|
|
4716
|
+
return false;
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
|
|
4720
|
+
function findClaudePath() {
|
|
4721
|
+
let localConfig = {};
|
|
4722
|
+
try {
|
|
4723
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4724
|
+
if (fs.existsSync(p)) {
|
|
4725
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4726
|
+
}
|
|
4727
|
+
} catch (_) {}
|
|
4728
|
+
|
|
4729
|
+
if (localConfig.automation?.multiAgent?.runners?.claude) {
|
|
4730
|
+
const p = localConfig.automation.multiAgent.runners.claude;
|
|
4731
|
+
if (fs.existsSync(p)) return p;
|
|
4732
|
+
}
|
|
4733
|
+
const homeClaude = path.join(os.homedir(), '.claude', 'local', 'claude');
|
|
4734
|
+
if (fs.existsSync(homeClaude)) return homeClaude;
|
|
4735
|
+
|
|
4736
|
+
try {
|
|
4737
|
+
const shell = process.env.SHELL || '/bin/zsh';
|
|
4738
|
+
const shellCmd = shell.endsWith('zsh') ? 'zsh -lc "which claude"' : 'bash -lc "which claude"';
|
|
4739
|
+
const detected = execSync(shellCmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
4740
|
+
if (detected && fs.existsSync(detected)) return detected;
|
|
4741
|
+
} catch (_) {}
|
|
4742
|
+
|
|
4743
|
+
return 'claude';
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
function findCodexPath() {
|
|
4747
|
+
let localConfig = {};
|
|
4748
|
+
try {
|
|
4749
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4750
|
+
if (fs.existsSync(p)) {
|
|
4751
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4752
|
+
}
|
|
4753
|
+
} catch (_) {}
|
|
4754
|
+
|
|
4755
|
+
if (localConfig.automation?.multiAgent?.runners?.codex) {
|
|
4756
|
+
const p = localConfig.automation.multiAgent.runners.codex;
|
|
4757
|
+
if (fs.existsSync(p)) return p;
|
|
4758
|
+
}
|
|
4759
|
+
try {
|
|
4760
|
+
const shell = process.env.SHELL || '/bin/zsh';
|
|
4761
|
+
const shellCmd = shell.endsWith('zsh') ? 'zsh -lc "which codex"' : 'bash -lc "which codex"';
|
|
4762
|
+
const detected = execSync(shellCmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
4763
|
+
if (detected && fs.existsSync(detected)) return detected;
|
|
4764
|
+
} catch (_) {}
|
|
4765
|
+
return 'codex';
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
function findQwenPath() {
|
|
4769
|
+
let localConfig = {};
|
|
4770
|
+
try {
|
|
4771
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4772
|
+
if (fs.existsSync(p)) {
|
|
4773
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4774
|
+
}
|
|
4775
|
+
} catch (_) {}
|
|
4776
|
+
|
|
4777
|
+
if (localConfig.automation?.multiAgent?.runners?.qwen) {
|
|
4778
|
+
const p = localConfig.automation.multiAgent.runners.qwen;
|
|
4779
|
+
if (fs.existsSync(p)) return p;
|
|
4780
|
+
}
|
|
4781
|
+
try {
|
|
4782
|
+
const shell = process.env.SHELL || '/bin/zsh';
|
|
4783
|
+
const shellCmd = shell.endsWith('zsh') ? 'zsh -lc "which qwen"' : 'bash -lc "which qwen"';
|
|
4784
|
+
const detected = execSync(shellCmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
4785
|
+
if (detected && fs.existsSync(detected)) return detected;
|
|
4786
|
+
} catch (_) {}
|
|
4787
|
+
return 'qwen';
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4790
|
+
function isRunnerEnabled(runnerName) {
|
|
4791
|
+
let localConfig = {};
|
|
4792
|
+
try {
|
|
4793
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4794
|
+
if (fs.existsSync(p)) {
|
|
4795
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4796
|
+
}
|
|
4797
|
+
} catch (_) {}
|
|
4798
|
+
|
|
4799
|
+
const localVal = localConfig.automation?.multiAgent?.runnersEnabled?.[runnerName];
|
|
4800
|
+
if (localVal !== undefined) return localVal;
|
|
4801
|
+
|
|
4802
|
+
const globalConfig = readGlobalConfig();
|
|
4803
|
+
const globalVal = globalConfig.runners?.[runnerName];
|
|
4804
|
+
if (globalVal !== undefined) return globalVal;
|
|
4805
|
+
|
|
4806
|
+
return true;
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
function isRunnerAvailable(runnerName) {
|
|
4810
|
+
if (!isRunnerEnabled(runnerName)) return false;
|
|
4811
|
+
let p;
|
|
4812
|
+
if (runnerName === 'claude') p = findClaudePath();
|
|
4813
|
+
else if (runnerName === 'codex') p = findCodexPath();
|
|
4814
|
+
else if (runnerName === 'qwen') p = findQwenPath();
|
|
4815
|
+
else return false;
|
|
4816
|
+
|
|
4817
|
+
if (fs.existsSync(p)) return true;
|
|
4818
|
+
try {
|
|
4819
|
+
execSync(`which ${p} || command -v ${p}`, { stdio: 'ignore' });
|
|
4820
|
+
return true;
|
|
4821
|
+
} catch (_) {
|
|
4822
|
+
return false;
|
|
4823
|
+
}
|
|
4824
|
+
}
|
|
4825
|
+
|
|
4826
|
+
function cmdGlobalConfig(args = []) {
|
|
4827
|
+
const sub = args[0];
|
|
4828
|
+
if (sub === 'audio') {
|
|
4829
|
+
const config = readGlobalConfig();
|
|
4830
|
+
const action = args[1];
|
|
4831
|
+
if (!action) {
|
|
4832
|
+
info(`Audio Alerts: ${config.audioAlerts ? 'ON' : 'OFF'}`);
|
|
4833
|
+
return;
|
|
4834
|
+
}
|
|
4835
|
+
if (action === 'on' || action === 'true' || action === '1') {
|
|
4836
|
+
config.audioAlerts = true;
|
|
4837
|
+
if (writeGlobalConfig(config)) {
|
|
4838
|
+
ok('Audio alerts turned ON globally.');
|
|
4839
|
+
}
|
|
4840
|
+
} else if (action === 'off' || action === 'false' || action === '0') {
|
|
4841
|
+
config.audioAlerts = false;
|
|
4842
|
+
if (writeGlobalConfig(config)) {
|
|
4843
|
+
ok('Audio alerts turned OFF globally.');
|
|
4844
|
+
}
|
|
4845
|
+
} else {
|
|
4846
|
+
err(`Invalid audio option: ${action}. Use 'on' or 'off'.`);
|
|
4847
|
+
}
|
|
4848
|
+
return;
|
|
4849
|
+
}
|
|
4850
|
+
|
|
4851
|
+
if (sub === 'claude' || sub === 'codex' || sub === 'qwen') {
|
|
4852
|
+
const config = readGlobalConfig();
|
|
4853
|
+
const action = args[1];
|
|
4854
|
+
if (!action) {
|
|
4855
|
+
info(`${sub.toUpperCase()} Runner: ${config.runners?.[sub] !== false ? 'ON' : 'OFF'}`);
|
|
4856
|
+
return;
|
|
4857
|
+
}
|
|
4858
|
+
if (action === 'on' || action === 'true' || action === '1') {
|
|
4859
|
+
config.runners = config.runners || {};
|
|
4860
|
+
config.runners[sub] = true;
|
|
4861
|
+
if (writeGlobalConfig(config)) {
|
|
4862
|
+
ok(`${sub.toUpperCase()} runner turned ON globally.`);
|
|
4863
|
+
}
|
|
4864
|
+
} else if (action === 'off' || action === 'false' || action === '0') {
|
|
4865
|
+
config.runners = config.runners || {};
|
|
4866
|
+
config.runners[sub] = false;
|
|
4867
|
+
if (writeGlobalConfig(config)) {
|
|
4868
|
+
ok(`${sub.toUpperCase()} runner turned OFF globally.`);
|
|
4869
|
+
}
|
|
4870
|
+
} else {
|
|
4871
|
+
err(`Invalid runner option: ${action}. Use 'on' or 'off'.`);
|
|
4872
|
+
}
|
|
4873
|
+
return;
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4876
|
+
if (sub === 'runners' || sub === 'runner') {
|
|
4877
|
+
const line = `${C.gray}${'─'.repeat(60)}${C.reset}`;
|
|
4878
|
+
log('');
|
|
4879
|
+
log(`${C.cyan}${C.bold}🏃 RUNNER AGENTS STATUS${C.reset}`);
|
|
4880
|
+
log(line);
|
|
4881
|
+
|
|
4882
|
+
const runners = ['claude', 'codex', 'qwen'];
|
|
4883
|
+
for (const r of runners) {
|
|
4884
|
+
const enabled = isRunnerEnabled(r);
|
|
4885
|
+
const path = r === 'claude' ? findClaudePath() : (r === 'codex' ? findCodexPath() : findQwenPath());
|
|
4886
|
+
const available = isRunnerAvailable(r);
|
|
4887
|
+
|
|
4888
|
+
const statusStr = enabled ? `${C.green}ON${C.reset}` : `${C.red}OFF${C.reset}`;
|
|
4889
|
+
const availStr = available ? `${C.green}✅ Available${C.reset}` : `${C.red}❌ Unavailable${C.reset}`;
|
|
4890
|
+
|
|
4891
|
+
log(` ● ${C.bold}${r.padEnd(8)}${C.reset} Status: [${statusStr}] Path: ${path.padEnd(30)} [${availStr}]`);
|
|
4892
|
+
}
|
|
4893
|
+
log('');
|
|
4894
|
+
return;
|
|
4895
|
+
}
|
|
4896
|
+
|
|
4897
|
+
if (sub === 'models' || sub === 'model') {
|
|
4898
|
+
const line = `${C.gray}${'─'.repeat(60)}${C.reset}`;
|
|
4899
|
+
log('');
|
|
4900
|
+
log(`${C.cyan}${C.bold}🤖 MODEL ROUTING POLICY${C.reset}`);
|
|
4901
|
+
log(line);
|
|
4902
|
+
|
|
4903
|
+
let localConfig = {};
|
|
4904
|
+
let projectLoaded = false;
|
|
4905
|
+
try {
|
|
4906
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4907
|
+
if (fs.existsSync(p)) {
|
|
4908
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4909
|
+
projectLoaded = true;
|
|
4910
|
+
}
|
|
4911
|
+
} catch (_) {}
|
|
4912
|
+
|
|
4913
|
+
if (projectLoaded) {
|
|
4914
|
+
log(` Project: ${C.green}${C.bold}${localConfig.projectName || 'Active Project'}${C.reset}`);
|
|
4915
|
+
const policy = localConfig.modelPolicy || {};
|
|
4916
|
+
log(` Routing Mode: ${C.cyan}${policy.mode || 'auto'}${C.reset}`);
|
|
4917
|
+
log(` Default Tier: ${C.cyan}${policy.defaultTier || 'STANDARD'}${C.reset}`);
|
|
4918
|
+
|
|
4919
|
+
if (policy.tierOverrides && Object.keys(policy.tierOverrides).length > 0) {
|
|
4920
|
+
log(` Tier Overrides:`);
|
|
4921
|
+
for (const [pattern, tier] of Object.entries(policy.tierOverrides)) {
|
|
4922
|
+
log(` * ${pattern.padEnd(20)} ➜ ${C.yellow}${tier}${C.reset}`);
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
} else {
|
|
4926
|
+
log(` No project loaded in current directory.`);
|
|
4927
|
+
}
|
|
4928
|
+
|
|
4929
|
+
log(line);
|
|
4930
|
+
log(` ${C.bold}Default Models:${C.reset}`);
|
|
4931
|
+
log(` * Standard execution: ${C.green}gemini-3.5-flash${C.reset} (Fast & cost-efficient)`);
|
|
4932
|
+
log(` * Heavy / Spec tasks: ${C.green}gemini-3.1-pro${C.reset} (High reasoning quality)`);
|
|
4933
|
+
log(` * Light tasks: ${C.green}gemini-3.1-flash-lite${C.reset} (Ultra-low latency)`);
|
|
4934
|
+
log('');
|
|
4935
|
+
return;
|
|
4936
|
+
}
|
|
4937
|
+
|
|
4938
|
+
if (!sub || sub === 'list') {
|
|
4939
|
+
const config = readGlobalConfig();
|
|
4940
|
+
const line = `${C.gray}${'─'.repeat(60)}${C.reset}`;
|
|
4941
|
+
log('');
|
|
4942
|
+
log(`${C.cyan}${C.bold}⚙️ AWK CLI CONFIGURATION${C.reset}`);
|
|
4943
|
+
log(line);
|
|
4944
|
+
|
|
4945
|
+
const formatBool = (val) => val !== false ? `${C.green}ON${C.reset}` : `${C.red}OFF${C.reset}`;
|
|
4946
|
+
|
|
4947
|
+
log(` ${C.bold}audioAlerts${C.reset.padEnd(20)} ${formatBool(config.audioAlerts).padEnd(15)} Play speech and chimes on complete`);
|
|
4948
|
+
log(` ${C.bold}runners.claude${C.reset.padEnd(20)} ${formatBool(config.runners?.claude).padEnd(15)} Use Claude Code CLI for planning`);
|
|
4949
|
+
log(` ${C.bold}runners.codex${C.reset.padEnd(20)} ${formatBool(config.runners?.codex).padEnd(15)} Use Codex CLI for UI and assets`);
|
|
4950
|
+
log(` ${C.bold}runners.qwen${C.reset.padEnd(20)} ${formatBool(config.runners?.qwen).padEnd(15)} Use Qwen Coder CLI for execution`);
|
|
4951
|
+
log(line);
|
|
4952
|
+
log(`💡 To toggle, run: ${C.cyan}awkit config <param> <on|off>${C.reset}`);
|
|
4953
|
+
log(` Example: ${C.cyan}awkit config claude off${C.reset}`);
|
|
4954
|
+
log('');
|
|
4955
|
+
return;
|
|
4956
|
+
}
|
|
4957
|
+
|
|
4958
|
+
if (sub === 'get' && args[1]) {
|
|
4959
|
+
const config = readGlobalConfig();
|
|
4960
|
+
const key = args[1];
|
|
4961
|
+
let val;
|
|
4962
|
+
if (key.includes('.')) {
|
|
4963
|
+
val = key.split('.').reduce((acc, part) => acc && acc[part], config);
|
|
4964
|
+
} else {
|
|
4965
|
+
val = config[key];
|
|
4966
|
+
}
|
|
4967
|
+
if (val !== undefined) {
|
|
4968
|
+
console.log(val);
|
|
4969
|
+
} else {
|
|
4970
|
+
err(`Key "${key}" not found in global config.`);
|
|
4971
|
+
}
|
|
4972
|
+
return;
|
|
4973
|
+
}
|
|
4974
|
+
|
|
4975
|
+
if (sub === 'set' && args[1] && args[2] !== undefined) {
|
|
4976
|
+
const config = readGlobalConfig();
|
|
4977
|
+
const key = args[1];
|
|
4978
|
+
let val = args[2];
|
|
4979
|
+
if (val === 'true') val = true;
|
|
4980
|
+
if (val === 'false') val = false;
|
|
4981
|
+
|
|
4982
|
+
if (key.includes('.')) {
|
|
4983
|
+
const parts = key.split('.');
|
|
4984
|
+
let current = config;
|
|
4985
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
4986
|
+
current[parts[i]] = current[parts[i]] || {};
|
|
4987
|
+
current = current[parts[i]];
|
|
4988
|
+
}
|
|
4989
|
+
current[parts[parts.length - 1]] = val;
|
|
4990
|
+
} else {
|
|
4991
|
+
config[key] = val;
|
|
4992
|
+
}
|
|
4993
|
+
|
|
4994
|
+
if (writeGlobalConfig(config)) {
|
|
4995
|
+
ok(`Global config updated: "${key}" = ${val}`);
|
|
4996
|
+
}
|
|
4997
|
+
return;
|
|
4998
|
+
}
|
|
4999
|
+
|
|
5000
|
+
err('Usage:');
|
|
5001
|
+
log(' awkit config list');
|
|
5002
|
+
log(' awkit config get <key>');
|
|
5003
|
+
log(' awkit config set <key> <value>');
|
|
5004
|
+
log(' awkit config audio <on|off>');
|
|
5005
|
+
log(' awkit config claude <on|off>');
|
|
5006
|
+
log(' awkit config codex <on|off>');
|
|
5007
|
+
log(' awkit config qwen <on|off>');
|
|
5008
|
+
log(' awkit config runners');
|
|
5009
|
+
log(' awkit config models');
|
|
5010
|
+
}
|
|
5011
|
+
|
|
4491
5012
|
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
4492
5013
|
|
|
4493
5014
|
const [, , command, ...args] = process.argv;
|
|
@@ -4498,6 +5019,15 @@ const [, , command, ...args] = process.argv;
|
|
|
4498
5019
|
case 'build':
|
|
4499
5020
|
cmdBuild();
|
|
4500
5021
|
break;
|
|
5022
|
+
case 'run':
|
|
5023
|
+
cmdRun(args);
|
|
5024
|
+
break;
|
|
5025
|
+
case 'task':
|
|
5026
|
+
cmdTask(args);
|
|
5027
|
+
break;
|
|
5028
|
+
case 'project':
|
|
5029
|
+
cmdProject(args);
|
|
5030
|
+
break;
|
|
4501
5031
|
case 'init':
|
|
4502
5032
|
await cmdInit(args.includes('--force'));
|
|
4503
5033
|
break;
|
|
@@ -4514,7 +5044,11 @@ const [, , command, ...args] = process.argv;
|
|
|
4514
5044
|
cmdSync();
|
|
4515
5045
|
break;
|
|
4516
5046
|
case 'status':
|
|
4517
|
-
|
|
5047
|
+
if (args[0] === 'gn' || args[0] === 'gitnexus') {
|
|
5048
|
+
cmdGitnexus(['status']);
|
|
5049
|
+
} else {
|
|
5050
|
+
cmdStatus();
|
|
5051
|
+
}
|
|
4518
5052
|
break;
|
|
4519
5053
|
case 'harvest':
|
|
4520
5054
|
cmdHarvest(args.includes('--dry-run'));
|
|
@@ -4562,6 +5096,16 @@ const [, , command, ...args] = process.argv;
|
|
|
4562
5096
|
case 'creds':
|
|
4563
5097
|
cmdCredentials(args);
|
|
4564
5098
|
break;
|
|
5099
|
+
case 'index':
|
|
5100
|
+
case 'analyze':
|
|
5101
|
+
cmdGitnexus(['index', ...args]);
|
|
5102
|
+
break;
|
|
5103
|
+
case 'clean':
|
|
5104
|
+
cmdGitnexus(['clean', ...args]);
|
|
5105
|
+
break;
|
|
5106
|
+
case 'list':
|
|
5107
|
+
cmdGitnexus(['list', ...args]);
|
|
5108
|
+
break;
|
|
4565
5109
|
case 'set-openrouter': {
|
|
4566
5110
|
const key = args[0];
|
|
4567
5111
|
if (!key) {
|
|
@@ -4603,11 +5147,31 @@ const [, , command, ...args] = process.argv;
|
|
|
4603
5147
|
case 'restart':
|
|
4604
5148
|
await cmdRestart();
|
|
4605
5149
|
break;
|
|
5150
|
+
case 'greet':
|
|
5151
|
+
cmdGreet(args);
|
|
5152
|
+
break;
|
|
5153
|
+
case 'config-global':
|
|
5154
|
+
cmdGlobalConfig(args);
|
|
5155
|
+
break;
|
|
4606
5156
|
case 'identity':
|
|
4607
5157
|
case 'config':
|
|
4608
|
-
case 'project':
|
|
4609
|
-
|
|
5158
|
+
case 'project': {
|
|
5159
|
+
const isGlobalSub = command === 'config' && (
|
|
5160
|
+
args.length === 0 ||
|
|
5161
|
+
['audio', 'claude', 'codex', 'qwen', 'runners', 'runner', 'models', 'model', 'list', 'get', 'set'].includes(args[0])
|
|
5162
|
+
);
|
|
5163
|
+
if (isGlobalSub) {
|
|
5164
|
+
// If there are no arguments but a project identity exists, show project identity as default
|
|
5165
|
+
if (args.length === 0 && fs.existsSync(path.join(process.cwd(), '.project-identity'))) {
|
|
5166
|
+
cmdIdentity(args);
|
|
5167
|
+
} else {
|
|
5168
|
+
cmdGlobalConfig(args);
|
|
5169
|
+
}
|
|
5170
|
+
} else {
|
|
5171
|
+
cmdIdentity(args);
|
|
5172
|
+
}
|
|
4610
5173
|
break;
|
|
5174
|
+
}
|
|
4611
5175
|
case 'help':
|
|
4612
5176
|
case '--help':
|
|
4613
5177
|
case '-h':
|