Skip to content

Commit aa3073d

Browse files
committed
refactor(cli): lazy-load command chunks via dynamic import
- Split src/cli.ts into bootstrap + main + cmd-index/query/agents - Entry index.mjs shrinks (~40kB -> ~7kB); tsdown emits separate chunks - --help / version / agents init avoid loading indexer path until needed
1 parent 7476569 commit aa3073d

9 files changed

Lines changed: 246 additions & 190 deletions

File tree

docs/architecture.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ A local SQLite database (`.codemap.db`) indexes the project tree and stores stru
1010

1111
## Layering
1212

13-
| Layer | Role |
14-
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
15-
| **`cli.ts`** | Parses argv (`--root`, `--config`, `query`, `agents init`, `--files`, `--full`, `--help`, `version` / `--version`), wires bootstrap → `runCodemapIndex` / `printQueryResult`. |
16-
| **`api.ts`** | Public programmatic surface: `createCodemap()`, `Codemap` (`query`, `index`), re-exports `runCodemapIndex` for advanced use. |
17-
| **`application/`** | Use cases: `run-index.ts` (incremental / full / targeted orchestration), `index-engine.ts` (collect files, git diff, `indexFiles`, workers via `worker-pool.ts`). |
18-
| **`adapters/`** | `LanguageAdapter` registry; built-ins call `parser.ts` / `css-parser.ts` / `markers.ts` from `parse-worker-core`. |
19-
| **`runtime.ts` / `config.ts` / `db.ts` / …** | Config, SQLite, resolver, workers. |
13+
| Layer | Role |
14+
| -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
15+
| **`cli/`** (`bootstrap`, `main`, `cmd-*`) | Parses argv; **dynamic `import()`** loads only the command chunk (`cmd-index`, `cmd-query`, `cmd-agents`) so `--help` / `version` / `agents init` avoid the indexer. |
16+
| **`api.ts`** | Public programmatic surface: `createCodemap()`, `Codemap` (`query`, `index`), re-exports `runCodemapIndex` for advanced use. |
17+
| **`application/`** | Use cases: `run-index.ts` (incremental / full / targeted orchestration), `index-engine.ts` (collect files, git diff, `indexFiles`, workers via `worker-pool.ts`). |
18+
| **`adapters/`** | `LanguageAdapter` registry; built-ins call `parser.ts` / `css-parser.ts` / `markers.ts` from `parse-worker-core`. |
19+
| **`runtime.ts` / `config.ts` / `db.ts` / …** | Config, SQLite, resolver, workers. |
2020

21-
`index.ts` is the package entry: re-exports the public API and runs `cli.ts` only when executed as the main module (Node/Bun `codemap` binary).
21+
`index.ts` is the package entry: re-exports the public API and runs `cli/main` only when executed as the main module (Node/Bun `codemap` binary).
2222

2323
### Full rebuild (parallel)
2424

@@ -89,7 +89,7 @@ A local SQLite database (`.codemap.db`) indexes the project tree and stores stru
8989
| File | Purpose |
9090
| ----------------- | ------------------------------------------------------------------------------------------------ |
9191
| `index.ts` | Package entry — re-exports `api` / `config`, runs CLI when main |
92-
| `cli.ts` | CLI — argv parsing, `query`, `agents init`, `--files`, `version`, index modes |
92+
| `cli/` | CLI — bootstrap argv, lazy command modules, `query` / `agents init` / index modes |
9393
| `api.ts` | Programmatic API — `createCodemap`, `Codemap`, `runCodemapIndex` |
9494
| `application/` | Indexing use cases and engine (`run-index`, `index-engine`, types) |
9595
| `worker-pool.ts` | Parallel parse workers (Bun / Node) |

src/cli.ts

Lines changed: 0 additions & 180 deletions
This file was deleted.

src/cli/bootstrap.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { resolve } from "node:path";
2+
3+
import { CODEMAP_VERSION } from "../version";
4+
5+
/** Printed for `codemap --help` / `-h` (must run before config or DB access). */
6+
export function printCliUsage(): void {
7+
console.log(`Usage: codemap [options] [command]
8+
9+
Index (default): update .codemap.db for the project root (\`--root\` or cwd).
10+
codemap [--root DIR] [--config FILE] [--full]
11+
codemap [--root DIR] [--config FILE] --files <paths...>
12+
13+
Query:
14+
codemap query "<SQL>"
15+
16+
Agents:
17+
codemap agents init [--force]
18+
19+
Other:
20+
codemap version
21+
codemap --version, -V
22+
23+
Environment: CODEMAP_ROOT (same as --root)
24+
25+
Options:
26+
--full Full rebuild
27+
--help, -h Show this help
28+
`);
29+
}
30+
31+
export function printVersion(): void {
32+
console.log(CODEMAP_VERSION);
33+
}
34+
35+
/**
36+
* Reject unknown flags/args for index mode before config or DB access.
37+
* Prevents typos like `--versiond` from falling through to incremental index.
38+
*/
39+
export function validateIndexModeArgs(rest: string[]): void {
40+
if (rest.length === 0) return;
41+
if (rest[0] === "query") return;
42+
43+
if (rest[0] === "agents") {
44+
if (rest[1] === "init") return;
45+
console.error(
46+
`codemap: unknown agents command "${rest[1] ?? "(missing)"}". Expected: codemap agents init [--force]`,
47+
);
48+
process.exit(1);
49+
}
50+
51+
let i = 0;
52+
while (i < rest.length) {
53+
const a = rest[i];
54+
if (a === "--full") {
55+
i++;
56+
continue;
57+
}
58+
if (a === "--files") {
59+
i++;
60+
while (i < rest.length && !rest[i].startsWith("-")) i++;
61+
continue;
62+
}
63+
if (a.startsWith("-")) {
64+
console.error(`codemap: unknown option "${a}"`);
65+
console.error("Run codemap --help for usage.");
66+
process.exit(1);
67+
}
68+
console.error(`codemap: unexpected argument "${a}"`);
69+
console.error("Run codemap --help for usage.");
70+
process.exit(1);
71+
}
72+
}
73+
74+
export function parseBootstrapArgs(argv: string[]) {
75+
const envRoot = process.env.CODEMAP_ROOT ?? process.env.CODEMAP_TEST_BENCH;
76+
let root = envRoot ? resolve(envRoot) : undefined;
77+
let configFile: string | undefined;
78+
const rest: string[] = [];
79+
for (let i = 0; i < argv.length; i++) {
80+
const a = argv[i];
81+
if (a === "--root" && argv[i + 1]) {
82+
root = resolve(argv[++i]);
83+
continue;
84+
}
85+
if (a === "--config" && argv[i + 1]) {
86+
configFile = resolve(argv[++i]);
87+
continue;
88+
}
89+
rest.push(a);
90+
}
91+
if (!root) root = process.cwd();
92+
return { root, configFile, rest };
93+
}

src/cli/cmd-agents.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { runAgentsInit } from "../agents-init";
2+
3+
export function runAgentsInitCmd(opts: {
4+
projectRoot: string;
5+
force: boolean;
6+
}): boolean {
7+
return runAgentsInit(opts);
8+
}

src/cli/cmd-index.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { extname } from "node:path";
2+
3+
import { VALID_EXTENSIONS } from "../application/index-engine";
4+
import { runCodemapIndex } from "../application/run-index";
5+
import { loadUserConfig, resolveCodemapConfig } from "../config";
6+
import { closeDb, openDb } from "../db";
7+
import { configureResolver } from "../resolver";
8+
import { getProjectRoot, getTsconfigPath, initCodemap } from "../runtime";
9+
10+
export async function runIndexCmd(opts: {
11+
root: string;
12+
configFile: string | undefined;
13+
rest: string[];
14+
}): Promise<void> {
15+
const user = await loadUserConfig(opts.root, opts.configFile);
16+
initCodemap(resolveCodemapConfig(opts.root, user));
17+
configureResolver(getProjectRoot(), getTsconfigPath());
18+
19+
const args = opts.rest;
20+
const db = openDb();
21+
try {
22+
if (args[0] === "--files" && args.length > 1) {
23+
const targetFiles = args.slice(1).filter((f) => {
24+
const ext = extname(f);
25+
if (!VALID_EXTENSIONS.has(ext)) {
26+
console.warn(` Skipping ${f}: unsupported extension "${ext}"`);
27+
return false;
28+
}
29+
return true;
30+
});
31+
if (targetFiles.length > 0) {
32+
await runCodemapIndex(db, {
33+
mode: "files",
34+
files: targetFiles,
35+
});
36+
}
37+
} else {
38+
const fullRebuild = args.includes("--full");
39+
await runCodemapIndex(db, {
40+
mode: fullRebuild ? "full" : "incremental",
41+
});
42+
}
43+
} finally {
44+
closeDb(db);
45+
}
46+
}

src/cli/cmd-query.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { printQueryResult } from "../application/index-engine";
2+
import { loadUserConfig, resolveCodemapConfig } from "../config";
3+
import { configureResolver } from "../resolver";
4+
import { getProjectRoot, getTsconfigPath, initCodemap } from "../runtime";
5+
6+
export async function runQueryCmd(opts: {
7+
root: string;
8+
configFile: string | undefined;
9+
sql: string;
10+
}): Promise<void> {
11+
const user = await loadUserConfig(opts.root, opts.configFile);
12+
initCodemap(resolveCodemapConfig(opts.root, user));
13+
configureResolver(getProjectRoot(), getTsconfigPath());
14+
printQueryResult(opts.sql);
15+
}

src/cli/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export { main } from "./main.js";
2+
export {
3+
parseBootstrapArgs,
4+
printCliUsage,
5+
printVersion,
6+
validateIndexModeArgs,
7+
} from "./bootstrap.js";

0 commit comments

Comments
 (0)