opencode-codebase-index 0.24.0 → 0.25.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +10 -0
- package/dist/cbi.cjs +14792 -0
- package/dist/cbi.cjs.map +1 -0
- package/dist/cbi.js +14786 -0
- package/dist/cbi.js.map +1 -0
- package/dist/cli.cjs +101 -3
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +101 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +97 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +97 -3
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +93 -1
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +93 -1
- package/dist/pi-extension.js.map +1 -1
- package/native/codebase-index-native.darwin-arm64.node +0 -0
- package/native/codebase-index-native.darwin-x64.node +0 -0
- package/native/codebase-index-native.win32-x64-msvc.node +0 -0
- package/package.json +3 -2
package/dist/cli.cjs
CHANGED
|
@@ -3610,6 +3610,26 @@ function formatCostEstimate(estimate) {
|
|
|
3610
3610
|
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
3611
3611
|
`;
|
|
3612
3612
|
}
|
|
3613
|
+
function formatDryRunEstimate(estimate) {
|
|
3614
|
+
return `Dry run: parsed the file set to measure the embedding workload. No embedding requests were made and the index was not changed.
|
|
3615
|
+
|
|
3616
|
+
Files to embed: ${estimate.filesCount.toLocaleString()}
|
|
3617
|
+
Chunks to embed: ${estimate.chunksCount.toLocaleString()}
|
|
3618
|
+
Tokens to embed: ${estimate.tokensToEmbed.toLocaleString()}
|
|
3619
|
+
|
|
3620
|
+
The "Tokens to embed" value uses the local estimateTokens(text) = ceil(len/4). It
|
|
3621
|
+
matches the live "Tokens used" counter only for providers that report usage on the
|
|
3622
|
+
same basis (ollama); for providers that report a server tokenizer count (OpenAI,
|
|
3623
|
+
Gemini, custom) it is only an estimate.
|
|
3624
|
+
|
|
3625
|
+
For a matching provider and a project-scoped force index, the force pass clears its
|
|
3626
|
+
own cached embeddings, so the live counter climbs to this number. A force index on a
|
|
3627
|
+
shared global index can reuse cached embeddings from other projects, and an
|
|
3628
|
+
incremental index counts cached chunks that are not re-embedded; in both cases this
|
|
3629
|
+
number is an upper bound on the live counter, so a progress percent against this
|
|
3630
|
+
total tops out below 100%.
|
|
3631
|
+
`;
|
|
3632
|
+
}
|
|
3613
3633
|
function formatBytes(bytes) {
|
|
3614
3634
|
if (bytes === 0) return "0 B";
|
|
3615
3635
|
const k = 1024;
|
|
@@ -6835,6 +6855,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
6835
6855
|
"enum_declaration",
|
|
6836
6856
|
"function_definition",
|
|
6837
6857
|
"class_definition",
|
|
6858
|
+
// Ruby module/class symbols that are declaration-bearing and navigable.
|
|
6859
|
+
"class",
|
|
6860
|
+
"module",
|
|
6838
6861
|
"class_specifier",
|
|
6839
6862
|
"struct_specifier",
|
|
6840
6863
|
"namespace_definition",
|
|
@@ -10871,6 +10894,70 @@ var Indexer = class _Indexer {
|
|
|
10871
10894
|
);
|
|
10872
10895
|
return createCostEstimate(files, configuredProviderInfo);
|
|
10873
10896
|
}
|
|
10897
|
+
// Dry-run counterpart to index()/forceIndex(): parse the real file set and sum
|
|
10898
|
+
// estimateTokens over the embedding text of every indexable chunk, without
|
|
10899
|
+
// calling the embedding provider or writing to the index. Read-only and
|
|
10900
|
+
// lock-free (mirrors estimateCost). The token sum is the exact value "Tokens
|
|
10901
|
+
// used" climbs to for a force index (cache bypassed); for an incremental it is
|
|
10902
|
+
// an upper bound because cached chunks are counted here but not re-embedded.
|
|
10903
|
+
// Used by index_codebase(dryRun:true) to give a stable, monotonic progress
|
|
10904
|
+
// denominator that matches the live "Tokens used" basis.
|
|
10905
|
+
async dryRunCost() {
|
|
10906
|
+
const { configuredProviderInfo } = await this.ensureInitialized();
|
|
10907
|
+
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
10908
|
+
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
10909
|
+
const { files } = await collectFiles(
|
|
10910
|
+
this.materializedProjectRoot,
|
|
10911
|
+
includePatterns,
|
|
10912
|
+
this.config.exclude,
|
|
10913
|
+
this.config.indexing.maxFileSize,
|
|
10914
|
+
this.getMaterializedKnowledgeBases(),
|
|
10915
|
+
{ maxDepth: this.config.indexing.maxDepth, maxFilesPerDirectory: this.config.indexing.maxFilesPerDirectory }
|
|
10916
|
+
);
|
|
10917
|
+
let filesCount = 0;
|
|
10918
|
+
let chunksCount = 0;
|
|
10919
|
+
let tokensToEmbed = 0;
|
|
10920
|
+
for (const batch of iterateOrderedFileBatches(files, (f) => f.size, this.fileBatchLimits)) {
|
|
10921
|
+
const loadedFiles = await Promise.all(batch.map(async (f) => {
|
|
10922
|
+
try {
|
|
10923
|
+
return {
|
|
10924
|
+
path: this.toStoredFilePath(f.path),
|
|
10925
|
+
content: await import_fs10.promises.readFile(f.path, "utf-8")
|
|
10926
|
+
};
|
|
10927
|
+
} catch {
|
|
10928
|
+
return null;
|
|
10929
|
+
}
|
|
10930
|
+
}));
|
|
10931
|
+
const readable = loadedFiles.filter(
|
|
10932
|
+
(f) => f !== null
|
|
10933
|
+
);
|
|
10934
|
+
filesCount += readable.length;
|
|
10935
|
+
const contentByPath = new Map(readable.map((f) => [f.path, f.content]));
|
|
10936
|
+
const parsedFiles = parseFiles(readable, this.config.indexing.linesPerChunk);
|
|
10937
|
+
for (const parsed of parsedFiles) {
|
|
10938
|
+
let chunksToProcess = parsed.chunks;
|
|
10939
|
+
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
10940
|
+
const content = contentByPath.get(parsed.path);
|
|
10941
|
+
if (content !== void 0) {
|
|
10942
|
+
chunksToProcess = parseFileAsText(parsed.path, content, this.config.indexing.linesPerChunk);
|
|
10943
|
+
}
|
|
10944
|
+
}
|
|
10945
|
+
chunksToProcess = selectIndexableChunks(
|
|
10946
|
+
chunksToProcess,
|
|
10947
|
+
this.config.indexing.maxChunksPerFile,
|
|
10948
|
+
this.config.indexing.semanticOnly
|
|
10949
|
+
);
|
|
10950
|
+
for (const chunk of chunksToProcess) {
|
|
10951
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, maxChunkTokens);
|
|
10952
|
+
chunksCount += 1;
|
|
10953
|
+
for (const text of texts) {
|
|
10954
|
+
tokensToEmbed += estimateTokens2(text);
|
|
10955
|
+
}
|
|
10956
|
+
}
|
|
10957
|
+
}
|
|
10958
|
+
}
|
|
10959
|
+
return { filesCount, chunksCount, tokensToEmbed };
|
|
10960
|
+
}
|
|
10874
10961
|
async index(onProgress) {
|
|
10875
10962
|
return this.withIndexMutationLease("index", async (recoveredOwners) => {
|
|
10876
10963
|
return this.indexUnlocked(onProgress, recoveredOwners);
|
|
@@ -15374,6 +15461,9 @@ async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
|
15374
15461
|
if (args.estimateOnly) {
|
|
15375
15462
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
15376
15463
|
}
|
|
15464
|
+
if (args.dryRun) {
|
|
15465
|
+
return { kind: "dryrun", dryrun: await indexer.dryRunCost() };
|
|
15466
|
+
}
|
|
15377
15467
|
const coordinated = runCoordinatedIndex(root, host, args.force ?? false, (progress) => {
|
|
15378
15468
|
if (onProgress) {
|
|
15379
15469
|
void onProgress(formatProgressTitle(progress), {
|
|
@@ -18301,6 +18391,7 @@ async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
|
18301
18391
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
18302
18392
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
18303
18393
|
if (result.kind === "estimate") return { text: formatCostEstimate(result.estimate) };
|
|
18394
|
+
if (result.kind === "dryrun") return { text: formatDryRunEstimate(result.dryrun) };
|
|
18304
18395
|
if (result.kind === "busy") return { text: result.text, isError: true };
|
|
18305
18396
|
if (result.kind === "message") return { text: result.text };
|
|
18306
18397
|
return { text: formatIndexStats(result.stats, args.verbose ?? false) };
|
|
@@ -18628,6 +18719,7 @@ ${formatCodebasePeek(results)}`;
|
|
|
18628
18719
|
{
|
|
18629
18720
|
force: allowNullAsUndefined(import_zod2.z.boolean().optional().default(false)).describe("Force reindex even if already indexed"),
|
|
18630
18721
|
estimateOnly: allowNullAsUndefined(import_zod2.z.boolean().optional().default(false)).describe("Only show cost estimate without indexing"),
|
|
18722
|
+
dryRun: allowNullAsUndefined(import_zod2.z.boolean().optional().default(false)).describe("Parse the file set and report the exact embedding token total without indexing. Read-only; the index is not changed. The total is the value 'Tokens used' climbs to for a force index (and an upper bound for an incremental)."),
|
|
18631
18723
|
verbose: allowNullAsUndefined(import_zod2.z.boolean().optional().default(false)).describe("Show detailed info about skipped files and parsing failures")
|
|
18632
18724
|
},
|
|
18633
18725
|
async (args) => {
|
|
@@ -18842,7 +18934,7 @@ ${formatSearchResults(results)}` }] };
|
|
|
18842
18934
|
// src/adapters/mcp/server.ts
|
|
18843
18935
|
function getServerInstructions(host) {
|
|
18844
18936
|
const hostText = `host ${host}`;
|
|
18845
|
-
return `This MCP server is the preferred codebase-understanding path for ${hostText}. Start a repository task with index_status when index readiness or freshness is unknown. Use codebase_context as the preferred first entry point because it returns a token-budgeted location pack and routes to definitions or call-graph helpers when symbol intent is present. Keep the default tokenBudget for normal discovery, then use implementation_lookup, codebase_search, or a targeted file read only for selected locations that need source content. Use codebase_peek for direct conceptual location lookup. For exact identifiers or exhaustive matches, use grep. After identifying symbols, use call_graph or call_graph_path to trace dependencies. If the index is unavailable, run index_codebase, then retry the retrieval tool.`;
|
|
18937
|
+
return `This MCP server is the preferred codebase-understanding path for ${hostText}. Start a repository task with index_status when index readiness or freshness is unknown. Use codebase_context as the preferred first entry point because it returns a token-budgeted location pack and routes to definitions or call-graph helpers when symbol intent is present. For code changes with a known or suspected symbol target, optionally call codebase_edit_context as a compact pre-edit step for bounded source plus direct callers and callees before broad file reads. Keep the default tokenBudget for normal discovery, then use implementation_lookup, codebase_search, or a targeted file read only for selected locations that need source content. Use codebase_peek for direct conceptual location lookup. For exact identifiers or exhaustive matches, use grep. After identifying symbols, use call_graph or call_graph_path to trace dependencies. If the index is unavailable, run index_codebase, then retry the retrieval tool.`;
|
|
18846
18938
|
}
|
|
18847
18939
|
function createMcpServer(projectRoot, config, host) {
|
|
18848
18940
|
const server = new import_mcp.McpServer({
|
|
@@ -22260,6 +22352,7 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22260
22352
|
let config;
|
|
22261
22353
|
let force = false;
|
|
22262
22354
|
let estimateOnly = false;
|
|
22355
|
+
let dryRun = false;
|
|
22263
22356
|
let verbose = false;
|
|
22264
22357
|
for (let i = 0; i < argv.length; i += 1) {
|
|
22265
22358
|
const arg = argv[i];
|
|
@@ -22297,13 +22390,16 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22297
22390
|
host = parseHostMode(value);
|
|
22298
22391
|
continue;
|
|
22299
22392
|
}
|
|
22300
|
-
if (arg === "--force" || arg === "--estimate-only" || arg === "--verbose") {
|
|
22393
|
+
if (arg === "--force" || arg === "--estimate-only" || arg === "--dry-run" || arg === "--verbose") {
|
|
22301
22394
|
if (arg === "--force") {
|
|
22302
22395
|
force = true;
|
|
22303
22396
|
}
|
|
22304
22397
|
if (arg === "--estimate-only") {
|
|
22305
22398
|
estimateOnly = true;
|
|
22306
22399
|
}
|
|
22400
|
+
if (arg === "--dry-run") {
|
|
22401
|
+
dryRun = true;
|
|
22402
|
+
}
|
|
22307
22403
|
if (arg === "--verbose") {
|
|
22308
22404
|
verbose = true;
|
|
22309
22405
|
}
|
|
@@ -22314,7 +22410,7 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22314
22410
|
}
|
|
22315
22411
|
throw new Error(`Unknown index option: ${arg}`);
|
|
22316
22412
|
}
|
|
22317
|
-
return { project, host, config, force, estimateOnly, verbose };
|
|
22413
|
+
return { project, host, config, force, estimateOnly, dryRun, verbose };
|
|
22318
22414
|
}
|
|
22319
22415
|
function loadCliRawConfig(args) {
|
|
22320
22416
|
return args.config ? loadConfigFile(args.config) : loadMergedConfig(args.project, args.host);
|
|
@@ -22331,6 +22427,7 @@ Options:
|
|
|
22331
22427
|
--config <path> Explicit JSON config path
|
|
22332
22428
|
--force Rebuild index even if already up to date
|
|
22333
22429
|
--estimate-only Estimate indexing cost only
|
|
22430
|
+
--dry-run Parse only; report the exact embedding token total without indexing
|
|
22334
22431
|
--verbose Include detailed final index statistics
|
|
22335
22432
|
--help Show this message
|
|
22336
22433
|
|
|
@@ -22526,6 +22623,7 @@ async function handleIndexCommand(argv, cwd, deps = {}) {
|
|
|
22526
22623
|
const indexArgs = {
|
|
22527
22624
|
force: parsedArgs.force,
|
|
22528
22625
|
estimateOnly: parsedArgs.estimateOnly,
|
|
22626
|
+
dryRun: parsedArgs.dryRun,
|
|
22529
22627
|
verbose: parsedArgs.verbose
|
|
22530
22628
|
};
|
|
22531
22629
|
const result = await runIndex(parsedArgs.project, parsedArgs.host, indexArgs, (title, metadata) => {
|