@ekkos/cli 1.3.7 → 1.3.8

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/dist/index.js CHANGED
@@ -38,24 +38,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  };
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  const commander_1 = require("commander");
41
- const init_1 = require("./commands/init");
42
- const test_1 = require("./commands/test");
43
- const status_1 = require("./commands/status");
41
+ // The `run` command is the default (bare `ekkos`), so it stays eager.
42
+ // `dashboardCommand` is eager because `run --dashboard` spawns `ekkos dashboard` in tmux.
43
+ // All other command modules are loaded lazily inside .action() callbacks.
44
44
  const run_1 = require("./commands/run");
45
- const gemini_1 = require("./commands/gemini");
46
- const test_claude_1 = require("./commands/test-claude");
47
- const doctor_1 = require("./commands/doctor");
48
- const stream_1 = require("./commands/stream");
49
- const claw_1 = require("./commands/claw");
50
- // DEPRECATED: Hooks removed in hookless architecture migration
51
- // hooksInstall, hooksVerify, hooksStatus no longer called — `hooks` command prints a deprecation notice.
52
- const state_1 = require("./utils/state");
53
- const index_1 = require("./commands/usage/index");
54
45
  const dashboard_1 = require("./commands/dashboard");
55
- const swarm_1 = require("./commands/swarm");
56
- const swarm_dashboard_1 = require("./commands/swarm-dashboard");
57
- const swarm_setup_1 = require("./commands/swarm-setup");
58
- const scan_1 = require("./commands/scan");
59
46
  const chalk_1 = __importDefault(require("chalk"));
60
47
  const fs = __importStar(require("fs"));
61
48
  const path = __importStar(require("path"));
@@ -79,6 +66,7 @@ commander_1.program
79
66
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos')} ${chalk_1.default.gray('Start Claude Code with ekkOS memory (default)')}`,
80
67
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos codex')} ${chalk_1.default.gray('Start Codex (OpenAI) mode')}`,
81
68
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos daemon start')} ${chalk_1.default.gray('Start the background mobile sync service')}`,
69
+ ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos docs watch')} ${chalk_1.default.gray('Keep local ekkOS_CONTEXT.md files updated on disk')}`,
82
70
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos connect gemini')} ${chalk_1.default.gray('Securely store your Gemini API key in the cloud')}`,
83
71
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos agent create --path ./repo')} ${chalk_1.default.gray('Spawn a headless remote agent in a directory')}`,
84
72
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos run --dashboard')} ${chalk_1.default.gray('Launch Claude with live usage dashboard')}`,
@@ -151,6 +139,7 @@ commander_1.program
151
139
  commands: [
152
140
  { name: 'init', desc: 'First-time setup — authenticate and configure IDEs' },
153
141
  { name: 'scan', desc: 'Scan repo structure and seed ekkOS system registry' },
142
+ { name: 'docs', desc: 'Watch and regenerate local ekkOS_CONTEXT.md files' },
154
143
  { name: 'status', desc: 'Show overall system status (Memory, Sync Daemon, Auth)' },
155
144
  { name: 'doctor', desc: 'Check system prerequisites and fix runaway processes' },
156
145
  ],
@@ -232,7 +221,7 @@ commander_1.program
232
221
  .option('-q, --quick', 'Quick setup: auto-detect IDE, use defaults, only prompt for API key if missing')
233
222
  .option('--skip-hooks', '[DEPRECATED] Hooks are no longer deployed; this flag is a no-op')
234
223
  .option('--skip-skills', 'Skip skills deployment')
235
- .action(init_1.init);
224
+ .action(async (options) => { const { init } = await Promise.resolve().then(() => __importStar(require('./commands/init'))); await init(options); });
236
225
  // Scan command — discover repo systems and seed registry
237
226
  commander_1.program
238
227
  .command('scan')
@@ -240,21 +229,45 @@ commander_1.program
240
229
  .option('-c, --compile', 'Trigger a compile pass after seeding')
241
230
  .option('-n, --dry-run', 'Show discovered systems without seeding')
242
231
  .option('-p, --path <path>', 'Path to scan (default: current directory)')
243
- .action((options) => {
244
- (0, scan_1.scan)({
232
+ .action(async (options) => {
233
+ const { scan } = await Promise.resolve().then(() => __importStar(require('./commands/scan')));
234
+ scan({
245
235
  compile: options.compile,
246
236
  dryRun: options.dryRun,
247
237
  path: options.path,
248
238
  });
249
239
  });
240
+ // Local living docs command
241
+ const docsCmd = commander_1.program
242
+ .command('docs')
243
+ .description('Manage local ekkOS_CONTEXT.md living docs');
244
+ docsCmd
245
+ .command('watch')
246
+ .description('Watch the local workspace and keep ekkOS_CONTEXT.md files current on disk')
247
+ .option('-p, --path <path>', 'Path to watch (default: current directory)')
248
+ .option('--timezone <iana-tz>', 'IANA timezone for timestamps (default: local machine timezone)')
249
+ .option('--poll-interval-ms <ms>', 'Polling interval fallback in milliseconds', (value) => parseInt(value, 10))
250
+ .option('--debounce-ms <ms>', 'Debounce window before recompiling in milliseconds', (value) => parseInt(value, 10))
251
+ .option('--no-seed', 'Do not seed the platform registry while watching')
252
+ .action(async (options) => {
253
+ const { watchLivingDocs } = await Promise.resolve().then(() => __importStar(require('./commands/living-docs')));
254
+ watchLivingDocs({
255
+ path: options.path,
256
+ timeZone: options.timezone,
257
+ pollIntervalMs: options.pollIntervalMs,
258
+ debounceMs: options.debounceMs,
259
+ noSeed: options.seed === false,
260
+ });
261
+ });
250
262
  // Status command
251
263
  commander_1.program
252
264
  .command('status')
253
265
  .description('Show live session metrics and memory status')
254
266
  .option('-w, --watch', 'Watch mode — refresh session panel every 2s')
255
267
  .option('--json', 'Output raw metrics JSON (no memory API call)')
256
- .action((options) => {
257
- (0, status_1.status)({ watch: options.watch, json: options.json });
268
+ .action(async (options) => {
269
+ const { status } = await Promise.resolve().then(() => __importStar(require('./commands/status')));
270
+ status({ watch: options.watch, json: options.json });
258
271
  });
259
272
  // OpenClaw integration commands
260
273
  const clawCmd = commander_1.program
@@ -267,8 +280,9 @@ clawCmd
267
280
  .option('--proxy-url <url>', 'Expected ekkOS proxy URL (default: https://proxy.ekkos.dev)')
268
281
  .option('--model <model>', 'Expected primary OpenClaw model (default: ekkos-proxy/claude-sonnet-4-6)')
269
282
  .option('--workspace <path>', 'Expected OpenClaw workspace path')
270
- .action((options) => {
271
- (0, claw_1.clawStatus)({
283
+ .action(async (options) => {
284
+ const { clawStatus } = await Promise.resolve().then(() => __importStar(require('./commands/claw')));
285
+ clawStatus({
272
286
  json: options.json,
273
287
  proxyUrl: options.proxyUrl,
274
288
  model: options.model,
@@ -284,8 +298,9 @@ clawCmd
284
298
  .option('--proxy-url <url>', 'Target ekkOS proxy URL')
285
299
  .option('--model <model>', 'Target primary OpenClaw model')
286
300
  .option('--workspace <path>', 'Expected OpenClaw workspace path for status verification')
287
- .action((options) => {
288
- (0, claw_1.clawUpgrade)({
301
+ .action(async (options) => {
302
+ const { clawUpgrade } = await Promise.resolve().then(() => __importStar(require('./commands/claw')));
303
+ clawUpgrade({
289
304
  apply: options.apply,
290
305
  force: options.force,
291
306
  json: options.json,
@@ -298,7 +313,7 @@ clawCmd
298
313
  commander_1.program
299
314
  .command('test')
300
315
  .description('Test connection to ekkOS memory')
301
- .action(test_1.test);
316
+ .action(async () => { const { test } = await Promise.resolve().then(() => __importStar(require('./commands/test'))); await test(); });
302
317
  // Run command - launches Claude Code with ekkOS proxy
303
318
  commander_1.program
304
319
  .command('run')
@@ -332,8 +347,9 @@ commander_1.program
332
347
  .option('-s, --session <name>', 'Session name')
333
348
  .option('-v, --verbose', 'Show debug output')
334
349
  .option('--skip-proxy', 'Skip API proxy (use direct Gemini API)')
335
- .action((options) => {
336
- (0, gemini_1.gemini)({
350
+ .action(async (options) => {
351
+ const { gemini } = await Promise.resolve().then(() => __importStar(require('./commands/gemini')));
352
+ gemini({
337
353
  session: options.session,
338
354
  verbose: options.verbose,
339
355
  noProxy: options.skipProxy,
@@ -346,8 +362,9 @@ commander_1.program
346
362
  .option('--no-proxy', 'Skip proxy too (completely vanilla Claude)')
347
363
  .option('--no-hooks', 'Temporarily disable all hooks during test')
348
364
  .option('-v, --verbose', 'Show debug output')
349
- .action((options) => {
350
- (0, test_claude_1.testClaude)({
365
+ .action(async (options) => {
366
+ const { testClaude } = await Promise.resolve().then(() => __importStar(require('./commands/test-claude')));
367
+ testClaude({
351
368
  noProxy: options.proxy === false,
352
369
  noHooks: options.hooks === false,
353
370
  verbose: options.verbose,
@@ -359,8 +376,9 @@ commander_1.program
359
376
  .description('Check system prerequisites for ekkOS (Node, PTY, Claude, MCP)')
360
377
  .option('-f, --fix', 'Attempt safe auto-fixes and show commands for manual fixes')
361
378
  .option('-j, --json', 'Output machine-readable JSON report')
362
- .action((options) => {
363
- (0, doctor_1.doctor)({ fix: options.fix, json: options.json });
379
+ .action(async (options) => {
380
+ const { doctor } = await Promise.resolve().then(() => __importStar(require('./commands/doctor')));
381
+ doctor({ fix: options.fix, json: options.json });
364
382
  });
365
383
  // Stream command - stream capture status and management
366
384
  const streamCmd = commander_1.program
@@ -372,8 +390,9 @@ streamCmd
372
390
  .option('-s, --session <id>', 'Session ID to check')
373
391
  .option('-w, --watch', 'Watch mode - refresh every second')
374
392
  .option('-j, --json', 'Output machine-readable JSON')
375
- .action((options) => {
376
- (0, stream_1.streamStatus)({
393
+ .action(async (options) => {
394
+ const { streamStatus } = await Promise.resolve().then(() => __importStar(require('./commands/stream')));
395
+ streamStatus({
377
396
  session: options.session,
378
397
  watch: options.watch,
379
398
  json: options.json
@@ -382,8 +401,9 @@ streamCmd
382
401
  streamCmd
383
402
  .command('list')
384
403
  .description('List all sessions with stream data')
385
- .action(() => {
386
- (0, stream_1.streamList)();
404
+ .action(async () => {
405
+ const { streamList } = await Promise.resolve().then(() => __importStar(require('./commands/stream')));
406
+ streamList();
387
407
  });
388
408
  // DEPRECATED: Hooks removed in hookless architecture migration
389
409
  // The `hooks` command prints a deprecation notice directing users to `ekkos run`.
@@ -400,17 +420,28 @@ commander_1.program
400
420
  console.log(chalk_1.default.gray(' the ekkOS proxy — no shell hooks required.'));
401
421
  console.log('');
402
422
  });
403
- // Usage command - track Claude Code token usage and costs (powered by ccusage)
404
- (0, index_1.registerUsageCommand)(commander_1.program);
405
- // Dashboard command - live TUI for monitoring session usage
423
+ // Usage command lightweight stub, heavy handler loaded lazily
424
+ commander_1.program
425
+ .command('usage')
426
+ .description('Token usage and cost tracking (daily, weekly, monthly, session)')
427
+ .allowUnknownOption()
428
+ .action(async () => {
429
+ const { registerUsageCommand } = await Promise.resolve().then(() => __importStar(require('./commands/usage/index')));
430
+ const { Command } = await Promise.resolve().then(() => __importStar(require('commander')));
431
+ const usageProgram = new Command('ekkos');
432
+ registerUsageCommand(usageProgram);
433
+ usageProgram.parse(['node', 'ekkos', 'usage', ...process.argv.slice(3)]);
434
+ });
435
+ // Dashboard command — eager because `run --dashboard` spawns `ekkos dashboard` in tmux
406
436
  commander_1.program.addCommand(dashboard_1.dashboardCommand);
407
437
  // Sessions command - list active Claude Code sessions (swarm support)
408
438
  commander_1.program
409
439
  .command('sessions')
410
440
  .description('List active Claude Code sessions (for swarm/multi-session support)')
411
441
  .option('-j, --json', 'Output machine-readable JSON')
412
- .action((options) => {
413
- const sessions = (0, state_1.getActiveSessions)();
442
+ .action(async (options) => {
443
+ const { getActiveSessions } = await Promise.resolve().then(() => __importStar(require('./utils/state')));
444
+ const sessions = getActiveSessions();
414
445
  if (options.json) {
415
446
  console.log(JSON.stringify(sessions, null, 2));
416
447
  return;
@@ -450,7 +481,8 @@ commander_1.program
450
481
  console.log(chalk_1.default.gray('Running init with your options...'));
451
482
  console.log('');
452
483
  // Forward to init
453
- await (0, init_1.init)({
484
+ const { init } = await Promise.resolve().then(() => __importStar(require('./commands/init')));
485
+ await init({
454
486
  ide: options.ide,
455
487
  key: options.key
456
488
  });
@@ -462,19 +494,19 @@ const swarmCmd = commander_1.program
462
494
  swarmCmd
463
495
  .command('status')
464
496
  .description('Show Q-table stats (states, visits, epsilon, top actions)')
465
- .action(swarm_1.swarmStatus);
497
+ .action(async () => { const { swarmStatus } = await Promise.resolve().then(() => __importStar(require('./commands/swarm'))); swarmStatus(); });
466
498
  swarmCmd
467
499
  .command('reset')
468
500
  .description('Clear Q-table from Redis (routing reverts to static rules)')
469
- .action(swarm_1.swarmReset);
501
+ .action(async () => { const { swarmReset } = await Promise.resolve().then(() => __importStar(require('./commands/swarm'))); swarmReset(); });
470
502
  swarmCmd
471
503
  .command('export')
472
504
  .description('Export Q-table to .swarm/q-learning-model.json')
473
- .action(swarm_1.swarmExport);
505
+ .action(async () => { const { swarmExport } = await Promise.resolve().then(() => __importStar(require('./commands/swarm'))); swarmExport(); });
474
506
  swarmCmd
475
507
  .command('import')
476
508
  .description('Import Q-table from .swarm/q-learning-model.json into Redis')
477
- .action(swarm_1.swarmImport);
509
+ .action(async () => { const { swarmImport } = await Promise.resolve().then(() => __importStar(require('./commands/swarm'))); swarmImport(); });
478
510
  swarmCmd
479
511
  .command('launch')
480
512
  .description('Launch parallel workers on a decomposed task (opens wizard if --task is omitted)')
@@ -485,13 +517,14 @@ swarmCmd
485
517
  .option('--no-queen', 'Skip launching the Python Queen coordinator')
486
518
  .option('--queen-strategy <strategy>', 'Queen strategy (adaptive-default, hierarchical-cascade, mesh-consensus)')
487
519
  .option('-v, --verbose', 'Show debug output')
488
- .action((options) => {
489
- // Auto-open wizard when --task is missing
520
+ .action(async (options) => {
490
521
  if (!options.task) {
491
- (0, swarm_setup_1.swarmSetup)();
522
+ const { swarmSetup } = await Promise.resolve().then(() => __importStar(require('./commands/swarm-setup')));
523
+ swarmSetup();
492
524
  return;
493
525
  }
494
- (0, swarm_1.swarmLaunch)({
526
+ const { swarmLaunch } = await Promise.resolve().then(() => __importStar(require('./commands/swarm')));
527
+ swarmLaunch({
495
528
  workers: options.workers || 4,
496
529
  task: options.task,
497
530
  bypass: options.bypass !== false,
@@ -504,10 +537,15 @@ swarmCmd
504
537
  swarmCmd
505
538
  .command('setup')
506
539
  .description('Interactive TUI wizard for configuring and launching a swarm')
507
- .action(() => {
508
- (0, swarm_setup_1.swarmSetup)();
540
+ .action(async () => { const { swarmSetup } = await Promise.resolve().then(() => __importStar(require('./commands/swarm-setup'))); swarmSetup(); });
541
+ swarmCmd
542
+ .command('swarm-dashboard')
543
+ .description('Live swarm dashboard')
544
+ .allowUnknownOption()
545
+ .action(async () => {
546
+ const { swarmDashboardCommand } = await Promise.resolve().then(() => __importStar(require('./commands/swarm-dashboard')));
547
+ swarmDashboardCommand.parse(process.argv.slice(3));
509
548
  });
510
- swarmCmd.addCommand(swarm_dashboard_1.swarmDashboardCommand);
511
549
  // --- Remote & Agent Wrapper Helpers ---
512
550
  function runRemoteCommand(command, ...args) {
513
551
  const isAgent = command === 'agent';
@@ -91,8 +91,24 @@ function resolveSessionName(name) {
91
91
  if (fs.existsSync(activeSessionsPath)) {
92
92
  try {
93
93
  const sessions = JSON.parse(fs.readFileSync(activeSessionsPath, 'utf-8'));
94
- // Find first entry with a valid UUID sessionId (skip "unknown" or empty)
95
- const match = sessions.find(s => s.sessionName === name && s.sessionId && s.sessionId !== 'unknown' && s.sessionId.length > 8);
94
+ // Find first entry with a valid UUID sessionId (skip "unknown" or empty).
95
+ // Also skip entries whose PID is dead (stale from prior runs / restarts).
96
+ const match = sessions.find(s => {
97
+ if (s.sessionName !== name)
98
+ return false;
99
+ if (!s.sessionId || s.sessionId === 'unknown' || s.sessionId.length <= 8)
100
+ return false;
101
+ // Prune dead PIDs — prevents stale cross-binding after restart
102
+ if (s.pid > 1) {
103
+ try {
104
+ process.kill(s.pid, 0);
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+ return true;
111
+ });
96
112
  if (match) {
97
113
  return {
98
114
  uuid: match.sessionId,
@@ -12,3 +12,7 @@ export { SyncEngine, createSyncEngine, } from './sync-engine';
12
12
  export type { SyncResult, } from './sync-engine';
13
13
  export { generateLocalEmbedding, cosineSimilarity, searchByEmbedding, isEmbeddingAvailable, } from './local-embeddings';
14
14
  export type { SimilarityResult, } from './local-embeddings';
15
+ export { detectStack, } from './stack-detection';
16
+ export type { StackInfo, } from './stack-detection';
17
+ export { LANGUAGE_CONFIGS, BASE_KEY_FILES, BASE_EXCLUDED_DIRS, getKeyFilesForStack, getExcludedDirsForStack, getPromptHintsForStack, getSourceExtensionsForStack, getSystemBoundaryMarkersForStack, } from './language-config';
18
+ export type { LanguageConfig, } from './language-config';
@@ -6,7 +6,7 @@
6
6
  * Provides offline-capable memory, fallback logic, sync, and local embeddings.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.isEmbeddingAvailable = exports.searchByEmbedding = exports.cosineSimilarity = exports.generateLocalEmbedding = exports.createSyncEngine = exports.SyncEngine = exports.OFFLINE_CAPABLE_TOOLS = exports.isOfflineFallbackReady = exports.callWithFallback = exports.localStore = exports.LocalMemoryStore = void 0;
9
+ exports.getSystemBoundaryMarkersForStack = exports.getSourceExtensionsForStack = exports.getPromptHintsForStack = exports.getExcludedDirsForStack = exports.getKeyFilesForStack = exports.BASE_EXCLUDED_DIRS = exports.BASE_KEY_FILES = exports.LANGUAGE_CONFIGS = exports.detectStack = exports.isEmbeddingAvailable = exports.searchByEmbedding = exports.cosineSimilarity = exports.generateLocalEmbedding = exports.createSyncEngine = exports.SyncEngine = exports.OFFLINE_CAPABLE_TOOLS = exports.isOfflineFallbackReady = exports.callWithFallback = exports.localStore = exports.LocalMemoryStore = void 0;
10
10
  // SQLite memory store (Phase 6A)
11
11
  var sqlite_store_1 = require("./sqlite-store");
12
12
  Object.defineProperty(exports, "LocalMemoryStore", { enumerable: true, get: function () { return sqlite_store_1.LocalMemoryStore; } });
@@ -26,3 +26,16 @@ Object.defineProperty(exports, "generateLocalEmbedding", { enumerable: true, get
26
26
  Object.defineProperty(exports, "cosineSimilarity", { enumerable: true, get: function () { return local_embeddings_1.cosineSimilarity; } });
27
27
  Object.defineProperty(exports, "searchByEmbedding", { enumerable: true, get: function () { return local_embeddings_1.searchByEmbedding; } });
28
28
  Object.defineProperty(exports, "isEmbeddingAvailable", { enumerable: true, get: function () { return local_embeddings_1.isEmbeddingAvailable; } });
29
+ // Stack detection (Living Docs V4 — Phase 4)
30
+ var stack_detection_1 = require("./stack-detection");
31
+ Object.defineProperty(exports, "detectStack", { enumerable: true, get: function () { return stack_detection_1.detectStack; } });
32
+ // Language configuration (Living Docs V4 — Phase 4)
33
+ var language_config_1 = require("./language-config");
34
+ Object.defineProperty(exports, "LANGUAGE_CONFIGS", { enumerable: true, get: function () { return language_config_1.LANGUAGE_CONFIGS; } });
35
+ Object.defineProperty(exports, "BASE_KEY_FILES", { enumerable: true, get: function () { return language_config_1.BASE_KEY_FILES; } });
36
+ Object.defineProperty(exports, "BASE_EXCLUDED_DIRS", { enumerable: true, get: function () { return language_config_1.BASE_EXCLUDED_DIRS; } });
37
+ Object.defineProperty(exports, "getKeyFilesForStack", { enumerable: true, get: function () { return language_config_1.getKeyFilesForStack; } });
38
+ Object.defineProperty(exports, "getExcludedDirsForStack", { enumerable: true, get: function () { return language_config_1.getExcludedDirsForStack; } });
39
+ Object.defineProperty(exports, "getPromptHintsForStack", { enumerable: true, get: function () { return language_config_1.getPromptHintsForStack; } });
40
+ Object.defineProperty(exports, "getSourceExtensionsForStack", { enumerable: true, get: function () { return language_config_1.getSourceExtensionsForStack; } });
41
+ Object.defineProperty(exports, "getSystemBoundaryMarkersForStack", { enumerable: true, get: function () { return language_config_1.getSystemBoundaryMarkersForStack; } });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Language Configuration — data-driven config for each language ecosystem
3
+ *
4
+ * Pure functions with zero dependencies. Provides key files, excluded dirs,
5
+ * source extensions, system boundary markers, and Gemini prompt hints
6
+ * for each supported language.
7
+ *
8
+ * Living Docs V4 — Phase 4: Language-Adapted Discovery
9
+ */
10
+ import type { StackInfo } from './stack-detection.js';
11
+ export interface LanguageConfig {
12
+ /** Key file names to prioritize reading (for both CLI and server compiler) */
13
+ keyFiles: string[];
14
+ /** Directories to exclude from scanning */
15
+ excludedDirs: string[];
16
+ /** File extensions that count as source files */
17
+ sourceExtensions: string[];
18
+ /** Files that mark a system boundary */
19
+ systemBoundaryMarkers: string[];
20
+ /** Prompt hints for Gemini (what to ask about) */
21
+ promptHints: {
22
+ architecture: string[];
23
+ buildSystem: string[];
24
+ deployTarget: string[];
25
+ testFramework: string[];
26
+ conventions: string[];
27
+ };
28
+ }
29
+ export declare const BASE_KEY_FILES: string[];
30
+ export declare const BASE_EXCLUDED_DIRS: string[];
31
+ export declare const LANGUAGE_CONFIGS: Record<string, LanguageConfig>;
32
+ /**
33
+ * Get the merged key files list for a detected stack.
34
+ * Returns BASE_KEY_FILES + language-specific files (deduplicated).
35
+ */
36
+ export declare function getKeyFilesForStack(stack: StackInfo): string[];
37
+ /**
38
+ * Get the merged excluded dirs for a detected stack.
39
+ * Returns BASE_EXCLUDED_DIRS + language-specific dirs.
40
+ */
41
+ export declare function getExcludedDirsForStack(stack: StackInfo): Set<string>;
42
+ /**
43
+ * Get prompt hints for the Gemini compiler.
44
+ * Falls back to TypeScript hints for unknown languages.
45
+ */
46
+ export declare function getPromptHintsForStack(stack: StackInfo): LanguageConfig['promptHints'];
47
+ /**
48
+ * Get the source extensions for a detected stack.
49
+ */
50
+ export declare function getSourceExtensionsForStack(stack: StackInfo): Set<string>;
51
+ /**
52
+ * Get system boundary markers for a detected stack.
53
+ * These are files that indicate a "system root" directory.
54
+ */
55
+ export declare function getSystemBoundaryMarkersForStack(stack: StackInfo): string[];