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.js
CHANGED
|
@@ -6576,6 +6576,26 @@ function formatCostEstimate(estimate) {
|
|
|
6576
6576
|
\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
|
|
6577
6577
|
`;
|
|
6578
6578
|
}
|
|
6579
|
+
function formatDryRunEstimate(estimate) {
|
|
6580
|
+
return `Dry run: parsed the file set to measure the embedding workload. No embedding requests were made and the index was not changed.
|
|
6581
|
+
|
|
6582
|
+
Files to embed: ${estimate.filesCount.toLocaleString()}
|
|
6583
|
+
Chunks to embed: ${estimate.chunksCount.toLocaleString()}
|
|
6584
|
+
Tokens to embed: ${estimate.tokensToEmbed.toLocaleString()}
|
|
6585
|
+
|
|
6586
|
+
The "Tokens to embed" value uses the local estimateTokens(text) = ceil(len/4). It
|
|
6587
|
+
matches the live "Tokens used" counter only for providers that report usage on the
|
|
6588
|
+
same basis (ollama); for providers that report a server tokenizer count (OpenAI,
|
|
6589
|
+
Gemini, custom) it is only an estimate.
|
|
6590
|
+
|
|
6591
|
+
For a matching provider and a project-scoped force index, the force pass clears its
|
|
6592
|
+
own cached embeddings, so the live counter climbs to this number. A force index on a
|
|
6593
|
+
shared global index can reuse cached embeddings from other projects, and an
|
|
6594
|
+
incremental index counts cached chunks that are not re-embedded; in both cases this
|
|
6595
|
+
number is an upper bound on the live counter, so a progress percent against this
|
|
6596
|
+
total tops out below 100%.
|
|
6597
|
+
`;
|
|
6598
|
+
}
|
|
6579
6599
|
function formatBytes(bytes) {
|
|
6580
6600
|
if (bytes === 0) return "0 B";
|
|
6581
6601
|
const k = 1024;
|
|
@@ -8850,6 +8870,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
8850
8870
|
"enum_declaration",
|
|
8851
8871
|
"function_definition",
|
|
8852
8872
|
"class_definition",
|
|
8873
|
+
// Ruby module/class symbols that are declaration-bearing and navigable.
|
|
8874
|
+
"class",
|
|
8875
|
+
"module",
|
|
8853
8876
|
"class_specifier",
|
|
8854
8877
|
"struct_specifier",
|
|
8855
8878
|
"namespace_definition",
|
|
@@ -12450,6 +12473,70 @@ var Indexer = class _Indexer {
|
|
|
12450
12473
|
);
|
|
12451
12474
|
return createCostEstimate(files, configuredProviderInfo);
|
|
12452
12475
|
}
|
|
12476
|
+
// Dry-run counterpart to index()/forceIndex(): parse the real file set and sum
|
|
12477
|
+
// estimateTokens over the embedding text of every indexable chunk, without
|
|
12478
|
+
// calling the embedding provider or writing to the index. Read-only and
|
|
12479
|
+
// lock-free (mirrors estimateCost). The token sum is the exact value "Tokens
|
|
12480
|
+
// used" climbs to for a force index (cache bypassed); for an incremental it is
|
|
12481
|
+
// an upper bound because cached chunks are counted here but not re-embedded.
|
|
12482
|
+
// Used by index_codebase(dryRun:true) to give a stable, monotonic progress
|
|
12483
|
+
// denominator that matches the live "Tokens used" basis.
|
|
12484
|
+
async dryRunCost() {
|
|
12485
|
+
const { configuredProviderInfo } = await this.ensureInitialized();
|
|
12486
|
+
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
12487
|
+
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
12488
|
+
const { files } = await collectFiles(
|
|
12489
|
+
this.materializedProjectRoot,
|
|
12490
|
+
includePatterns,
|
|
12491
|
+
this.config.exclude,
|
|
12492
|
+
this.config.indexing.maxFileSize,
|
|
12493
|
+
this.getMaterializedKnowledgeBases(),
|
|
12494
|
+
{ maxDepth: this.config.indexing.maxDepth, maxFilesPerDirectory: this.config.indexing.maxFilesPerDirectory }
|
|
12495
|
+
);
|
|
12496
|
+
let filesCount = 0;
|
|
12497
|
+
let chunksCount = 0;
|
|
12498
|
+
let tokensToEmbed = 0;
|
|
12499
|
+
for (const batch of iterateOrderedFileBatches(files, (f) => f.size, this.fileBatchLimits)) {
|
|
12500
|
+
const loadedFiles = await Promise.all(batch.map(async (f) => {
|
|
12501
|
+
try {
|
|
12502
|
+
return {
|
|
12503
|
+
path: this.toStoredFilePath(f.path),
|
|
12504
|
+
content: await fsPromises3.readFile(f.path, "utf-8")
|
|
12505
|
+
};
|
|
12506
|
+
} catch {
|
|
12507
|
+
return null;
|
|
12508
|
+
}
|
|
12509
|
+
}));
|
|
12510
|
+
const readable = loadedFiles.filter(
|
|
12511
|
+
(f) => f !== null
|
|
12512
|
+
);
|
|
12513
|
+
filesCount += readable.length;
|
|
12514
|
+
const contentByPath = new Map(readable.map((f) => [f.path, f.content]));
|
|
12515
|
+
const parsedFiles = parseFiles(readable, this.config.indexing.linesPerChunk);
|
|
12516
|
+
for (const parsed of parsedFiles) {
|
|
12517
|
+
let chunksToProcess = parsed.chunks;
|
|
12518
|
+
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
12519
|
+
const content = contentByPath.get(parsed.path);
|
|
12520
|
+
if (content !== void 0) {
|
|
12521
|
+
chunksToProcess = parseFileAsText(parsed.path, content, this.config.indexing.linesPerChunk);
|
|
12522
|
+
}
|
|
12523
|
+
}
|
|
12524
|
+
chunksToProcess = selectIndexableChunks(
|
|
12525
|
+
chunksToProcess,
|
|
12526
|
+
this.config.indexing.maxChunksPerFile,
|
|
12527
|
+
this.config.indexing.semanticOnly
|
|
12528
|
+
);
|
|
12529
|
+
for (const chunk of chunksToProcess) {
|
|
12530
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, maxChunkTokens);
|
|
12531
|
+
chunksCount += 1;
|
|
12532
|
+
for (const text of texts) {
|
|
12533
|
+
tokensToEmbed += estimateTokens(text);
|
|
12534
|
+
}
|
|
12535
|
+
}
|
|
12536
|
+
}
|
|
12537
|
+
}
|
|
12538
|
+
return { filesCount, chunksCount, tokensToEmbed };
|
|
12539
|
+
}
|
|
12453
12540
|
async index(onProgress) {
|
|
12454
12541
|
return this.withIndexMutationLease("index", async (recoveredOwners) => {
|
|
12455
12542
|
return this.indexUnlocked(onProgress, recoveredOwners);
|
|
@@ -15003,6 +15090,9 @@ async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
|
15003
15090
|
if (args.estimateOnly) {
|
|
15004
15091
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
15005
15092
|
}
|
|
15093
|
+
if (args.dryRun) {
|
|
15094
|
+
return { kind: "dryrun", dryrun: await indexer.dryRunCost() };
|
|
15095
|
+
}
|
|
15006
15096
|
const coordinated = runCoordinatedIndex(root, host, args.force ?? false, (progress) => {
|
|
15007
15097
|
if (onProgress) {
|
|
15008
15098
|
void onProgress(formatProgressTitle(progress), {
|
|
@@ -18843,6 +18933,7 @@ async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
|
18843
18933
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
18844
18934
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
18845
18935
|
if (result.kind === "estimate") return { text: formatCostEstimate(result.estimate) };
|
|
18936
|
+
if (result.kind === "dryrun") return { text: formatDryRunEstimate(result.dryrun) };
|
|
18846
18937
|
if (result.kind === "busy") return { text: result.text, isError: true };
|
|
18847
18938
|
if (result.kind === "message") return { text: result.text };
|
|
18848
18939
|
return { text: formatIndexStats(result.stats, args.verbose ?? false) };
|
|
@@ -19707,6 +19798,7 @@ var index_codebase = tool({
|
|
|
19707
19798
|
args: {
|
|
19708
19799
|
force: z3.boolean().optional().default(false).describe("Force reindex even if already indexed"),
|
|
19709
19800
|
estimateOnly: z3.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
19801
|
+
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)."),
|
|
19710
19802
|
verbose: z3.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
19711
19803
|
},
|
|
19712
19804
|
async execute(args, context) {
|
|
@@ -20307,6 +20399,7 @@ function assessRoutingIntent(text) {
|
|
|
20307
20399
|
};
|
|
20308
20400
|
}
|
|
20309
20401
|
function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
20402
|
+
const hasSymbolCue = hasIdentifierShape(assessment.text) || containsQuotedIdentifier(assessment.text);
|
|
20310
20403
|
if (assessment.intent === "definition_lookup") {
|
|
20311
20404
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
20312
20405
|
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.";
|
|
@@ -20316,12 +20409,13 @@ function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
|
20316
20409
|
if (assessment.intent !== "local_conceptual" && assessment.intent !== "local_broad_task") {
|
|
20317
20410
|
return null;
|
|
20318
20411
|
}
|
|
20412
|
+
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." : "";
|
|
20319
20413
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
20320
20414
|
const graphHandoff2 = includeGraphHandoff ? " Use graph tools after semantic discovery identifies relevant symbols." : "";
|
|
20321
|
-
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
|
|
20415
|
+
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}`;
|
|
20322
20416
|
}
|
|
20323
20417
|
const graphHandoff = includeGraphHandoff ? " before graph tools such as `call_graph`, `call_graph_path`, `pr_impact`, or OMO CodeGraph" : "";
|
|
20324
|
-
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
|
|
20418
|
+
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}`;
|
|
20325
20419
|
}
|
|
20326
20420
|
var RoutingHintController = class {
|
|
20327
20421
|
constructor(getStatus, maxSessions = 200, includeGraphHandoff = false) {
|
|
@@ -20363,7 +20457,7 @@ var RoutingHintController = class {
|
|
|
20363
20457
|
if (!state || !state.pendingHint) {
|
|
20364
20458
|
return;
|
|
20365
20459
|
}
|
|
20366
|
-
if (toolName === "codebase_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
20460
|
+
if (toolName === "codebase_context" || toolName === "codebase_edit_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
20367
20461
|
state.pendingHint = false;
|
|
20368
20462
|
state.updatedAt = Date.now();
|
|
20369
20463
|
this.sessionState.set(sessionID, state);
|