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/index.cjs
CHANGED
|
@@ -6578,6 +6578,26 @@ function formatCostEstimate(estimate) {
|
|
|
6578
6578
|
\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
|
|
6579
6579
|
`;
|
|
6580
6580
|
}
|
|
6581
|
+
function formatDryRunEstimate(estimate) {
|
|
6582
|
+
return `Dry run: parsed the file set to measure the embedding workload. No embedding requests were made and the index was not changed.
|
|
6583
|
+
|
|
6584
|
+
Files to embed: ${estimate.filesCount.toLocaleString()}
|
|
6585
|
+
Chunks to embed: ${estimate.chunksCount.toLocaleString()}
|
|
6586
|
+
Tokens to embed: ${estimate.tokensToEmbed.toLocaleString()}
|
|
6587
|
+
|
|
6588
|
+
The "Tokens to embed" value uses the local estimateTokens(text) = ceil(len/4). It
|
|
6589
|
+
matches the live "Tokens used" counter only for providers that report usage on the
|
|
6590
|
+
same basis (ollama); for providers that report a server tokenizer count (OpenAI,
|
|
6591
|
+
Gemini, custom) it is only an estimate.
|
|
6592
|
+
|
|
6593
|
+
For a matching provider and a project-scoped force index, the force pass clears its
|
|
6594
|
+
own cached embeddings, so the live counter climbs to this number. A force index on a
|
|
6595
|
+
shared global index can reuse cached embeddings from other projects, and an
|
|
6596
|
+
incremental index counts cached chunks that are not re-embedded; in both cases this
|
|
6597
|
+
number is an upper bound on the live counter, so a progress percent against this
|
|
6598
|
+
total tops out below 100%.
|
|
6599
|
+
`;
|
|
6600
|
+
}
|
|
6581
6601
|
function formatBytes(bytes) {
|
|
6582
6602
|
if (bytes === 0) return "0 B";
|
|
6583
6603
|
const k = 1024;
|
|
@@ -8853,6 +8873,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
8853
8873
|
"enum_declaration",
|
|
8854
8874
|
"function_definition",
|
|
8855
8875
|
"class_definition",
|
|
8876
|
+
// Ruby module/class symbols that are declaration-bearing and navigable.
|
|
8877
|
+
"class",
|
|
8878
|
+
"module",
|
|
8856
8879
|
"class_specifier",
|
|
8857
8880
|
"struct_specifier",
|
|
8858
8881
|
"namespace_definition",
|
|
@@ -12453,6 +12476,70 @@ var Indexer = class _Indexer {
|
|
|
12453
12476
|
);
|
|
12454
12477
|
return createCostEstimate(files, configuredProviderInfo);
|
|
12455
12478
|
}
|
|
12479
|
+
// Dry-run counterpart to index()/forceIndex(): parse the real file set and sum
|
|
12480
|
+
// estimateTokens over the embedding text of every indexable chunk, without
|
|
12481
|
+
// calling the embedding provider or writing to the index. Read-only and
|
|
12482
|
+
// lock-free (mirrors estimateCost). The token sum is the exact value "Tokens
|
|
12483
|
+
// used" climbs to for a force index (cache bypassed); for an incremental it is
|
|
12484
|
+
// an upper bound because cached chunks are counted here but not re-embedded.
|
|
12485
|
+
// Used by index_codebase(dryRun:true) to give a stable, monotonic progress
|
|
12486
|
+
// denominator that matches the live "Tokens used" basis.
|
|
12487
|
+
async dryRunCost() {
|
|
12488
|
+
const { configuredProviderInfo } = await this.ensureInitialized();
|
|
12489
|
+
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
12490
|
+
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
12491
|
+
const { files } = await collectFiles(
|
|
12492
|
+
this.materializedProjectRoot,
|
|
12493
|
+
includePatterns,
|
|
12494
|
+
this.config.exclude,
|
|
12495
|
+
this.config.indexing.maxFileSize,
|
|
12496
|
+
this.getMaterializedKnowledgeBases(),
|
|
12497
|
+
{ maxDepth: this.config.indexing.maxDepth, maxFilesPerDirectory: this.config.indexing.maxFilesPerDirectory }
|
|
12498
|
+
);
|
|
12499
|
+
let filesCount = 0;
|
|
12500
|
+
let chunksCount = 0;
|
|
12501
|
+
let tokensToEmbed = 0;
|
|
12502
|
+
for (const batch of iterateOrderedFileBatches(files, (f) => f.size, this.fileBatchLimits)) {
|
|
12503
|
+
const loadedFiles = await Promise.all(batch.map(async (f) => {
|
|
12504
|
+
try {
|
|
12505
|
+
return {
|
|
12506
|
+
path: this.toStoredFilePath(f.path),
|
|
12507
|
+
content: await import_fs12.promises.readFile(f.path, "utf-8")
|
|
12508
|
+
};
|
|
12509
|
+
} catch {
|
|
12510
|
+
return null;
|
|
12511
|
+
}
|
|
12512
|
+
}));
|
|
12513
|
+
const readable = loadedFiles.filter(
|
|
12514
|
+
(f) => f !== null
|
|
12515
|
+
);
|
|
12516
|
+
filesCount += readable.length;
|
|
12517
|
+
const contentByPath = new Map(readable.map((f) => [f.path, f.content]));
|
|
12518
|
+
const parsedFiles = parseFiles(readable, this.config.indexing.linesPerChunk);
|
|
12519
|
+
for (const parsed of parsedFiles) {
|
|
12520
|
+
let chunksToProcess = parsed.chunks;
|
|
12521
|
+
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
12522
|
+
const content = contentByPath.get(parsed.path);
|
|
12523
|
+
if (content !== void 0) {
|
|
12524
|
+
chunksToProcess = parseFileAsText(parsed.path, content, this.config.indexing.linesPerChunk);
|
|
12525
|
+
}
|
|
12526
|
+
}
|
|
12527
|
+
chunksToProcess = selectIndexableChunks(
|
|
12528
|
+
chunksToProcess,
|
|
12529
|
+
this.config.indexing.maxChunksPerFile,
|
|
12530
|
+
this.config.indexing.semanticOnly
|
|
12531
|
+
);
|
|
12532
|
+
for (const chunk of chunksToProcess) {
|
|
12533
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, maxChunkTokens);
|
|
12534
|
+
chunksCount += 1;
|
|
12535
|
+
for (const text of texts) {
|
|
12536
|
+
tokensToEmbed += estimateTokens(text);
|
|
12537
|
+
}
|
|
12538
|
+
}
|
|
12539
|
+
}
|
|
12540
|
+
}
|
|
12541
|
+
return { filesCount, chunksCount, tokensToEmbed };
|
|
12542
|
+
}
|
|
12456
12543
|
async index(onProgress) {
|
|
12457
12544
|
return this.withIndexMutationLease("index", async (recoveredOwners) => {
|
|
12458
12545
|
return this.indexUnlocked(onProgress, recoveredOwners);
|
|
@@ -15006,6 +15093,9 @@ async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
|
15006
15093
|
if (args.estimateOnly) {
|
|
15007
15094
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
15008
15095
|
}
|
|
15096
|
+
if (args.dryRun) {
|
|
15097
|
+
return { kind: "dryrun", dryrun: await indexer.dryRunCost() };
|
|
15098
|
+
}
|
|
15009
15099
|
const coordinated = runCoordinatedIndex(root, host, args.force ?? false, (progress) => {
|
|
15010
15100
|
if (onProgress) {
|
|
15011
15101
|
void onProgress(formatProgressTitle(progress), {
|
|
@@ -18846,6 +18936,7 @@ async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
|
18846
18936
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
18847
18937
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
18848
18938
|
if (result.kind === "estimate") return { text: formatCostEstimate(result.estimate) };
|
|
18939
|
+
if (result.kind === "dryrun") return { text: formatDryRunEstimate(result.dryrun) };
|
|
18849
18940
|
if (result.kind === "busy") return { text: result.text, isError: true };
|
|
18850
18941
|
if (result.kind === "message") return { text: result.text };
|
|
18851
18942
|
return { text: formatIndexStats(result.stats, args.verbose ?? false) };
|
|
@@ -19710,6 +19801,7 @@ var index_codebase = tool({
|
|
|
19710
19801
|
args: {
|
|
19711
19802
|
force: z3.boolean().optional().default(false).describe("Force reindex even if already indexed"),
|
|
19712
19803
|
estimateOnly: z3.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
19804
|
+
dryRun: z3.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)."),
|
|
19713
19805
|
verbose: z3.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
19714
19806
|
},
|
|
19715
19807
|
async execute(args, context) {
|
|
@@ -20310,6 +20402,7 @@ function assessRoutingIntent(text) {
|
|
|
20310
20402
|
};
|
|
20311
20403
|
}
|
|
20312
20404
|
function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
20405
|
+
const hasSymbolCue = hasIdentifierShape(assessment.text) || containsQuotedIdentifier(assessment.text);
|
|
20313
20406
|
if (assessment.intent === "definition_lookup") {
|
|
20314
20407
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
20315
20408
|
return "For this turn, if you need a symbol definition, check `index_status` first and run `index_codebase` if the index is missing or incompatible. Then use `implementation_lookup` for the definition site. Use `grep` for exhaustive literal matches.";
|
|
@@ -20319,12 +20412,13 @@ function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
|
20319
20412
|
if (assessment.intent !== "local_conceptual" && assessment.intent !== "local_broad_task") {
|
|
20320
20413
|
return null;
|
|
20321
20414
|
}
|
|
20415
|
+
const preEditHint = assessment.intent === "local_broad_task" && hasSymbolCue ? " If a likely target symbol is already known or strongly suspected, consider optional `codebase_edit_context` as a compact pre-edit next step for bounded source plus direct callers and callees." : "";
|
|
20322
20416
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
20323
20417
|
const graphHandoff2 = includeGraphHandoff ? " Use graph tools after semantic discovery identifies relevant symbols." : "";
|
|
20324
|
-
return `For this turn, if local code discovery by behavior is needed, check \`index_status\` first and run \`index_codebase\` if the index is missing or incompatible.${graphHandoff2} Then use \`codebase_context\` as the first local repository lookup. Use \`grep\` for exact identifiers or exhaustive matches
|
|
20418
|
+
return `For this turn, if local code discovery by behavior is needed, check \`index_status\` first and run \`index_codebase\` if the index is missing or incompatible.${graphHandoff2} Then use \`codebase_context\` as the first local repository lookup. Use \`grep\` for exact identifiers or exhaustive matches.${preEditHint}`;
|
|
20325
20419
|
}
|
|
20326
20420
|
const graphHandoff = includeGraphHandoff ? " before graph tools such as `call_graph`, `call_graph_path`, `pr_impact`, or OMO CodeGraph" : "";
|
|
20327
|
-
return `For this turn, prefer \`codebase_context\` for local code discovery, then use \`codebase_peek\` for metadata and \`codebase_search\` when you need implementation content${graphHandoff}. Use \`grep\` for exact identifiers or exhaustive matches
|
|
20421
|
+
return `For this turn, prefer \`codebase_context\` for local code discovery, then use \`codebase_peek\` for metadata and \`codebase_search\` when you need implementation content${graphHandoff}. Use \`grep\` for exact identifiers or exhaustive matches.${preEditHint}`;
|
|
20328
20422
|
}
|
|
20329
20423
|
var RoutingHintController = class {
|
|
20330
20424
|
constructor(getStatus, maxSessions = 200, includeGraphHandoff = false) {
|
|
@@ -20366,7 +20460,7 @@ var RoutingHintController = class {
|
|
|
20366
20460
|
if (!state || !state.pendingHint) {
|
|
20367
20461
|
return;
|
|
20368
20462
|
}
|
|
20369
|
-
if (toolName === "codebase_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
20463
|
+
if (toolName === "codebase_context" || toolName === "codebase_edit_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
20370
20464
|
state.pendingHint = false;
|
|
20371
20465
|
state.updatedAt = Date.now();
|
|
20372
20466
|
this.sessionState.set(sessionID, state);
|