@zokizuan/satori-mcp 4.11.13 → 4.11.16
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/README.md +26 -21
- package/dist/cli/args.d.ts +3 -12
- package/dist/cli/args.js +6 -47
- package/dist/cli/index.d.ts +0 -3
- package/dist/cli/index.js +2 -21
- package/dist/config.d.ts +2 -0
- package/dist/config.js +21 -3
- package/dist/core/call-graph.d.ts +2 -0
- package/dist/core/handlers.d.ts +1 -1
- package/dist/core/handlers.js +30 -8
- package/dist/core/indexing-recovery.d.ts +2 -1
- package/dist/core/indexing-recovery.js +6 -2
- package/dist/core/manage-indexing-handlers.d.ts +4 -3
- package/dist/core/manage-indexing-handlers.js +30 -9
- package/dist/core/manage-maintenance-handlers.d.ts +7 -4
- package/dist/core/manage-maintenance-handlers.js +57 -7
- package/dist/core/manage-types.d.ts +6 -1
- package/dist/core/manage-types.js +9 -1
- package/dist/core/navigation-handlers.d.ts +6 -0
- package/dist/core/navigation-handlers.js +79 -12
- package/dist/core/registry-file-outline.d.ts +1 -1
- package/dist/core/registry-file-outline.js +3 -2
- package/dist/core/relationship-backed-call-graph.d.ts +18 -0
- package/dist/core/relationship-backed-call-graph.js +151 -6
- package/dist/core/runtime-owner.d.ts +43 -1
- package/dist/core/runtime-owner.js +128 -3
- package/dist/core/search-exact-fast-path.js +2 -0
- package/dist/core/search-execution.d.ts +10 -0
- package/dist/core/search-execution.js +36 -1
- package/dist/core/search-frontdoor.js +11 -2
- package/dist/core/search-group-ordering.d.ts +3 -0
- package/dist/core/search-group-ordering.js +83 -7
- package/dist/core/search-group-results.js +27 -1
- package/dist/core/search-ranking-policy.js +2 -1
- package/dist/core/search-response-helpers.d.ts +27 -1
- package/dist/core/search-response-helpers.js +116 -11
- package/dist/core/search-result-finalization.js +3 -2
- package/dist/core/search-types.d.ts +17 -0
- package/dist/core/tool-response-builders.d.ts +2 -0
- package/dist/core/tool-response-builders.js +3 -0
- package/dist/core/tracked-root-readiness.js +2 -1
- package/dist/server/provider-runtime.js +1 -0
- package/dist/tools/call_graph.js +19 -7
- package/dist/tools/file_outline.js +18 -6
- package/dist/tools/list_codebases.js +82 -33
- package/dist/tools/manage_index.d.ts +3 -0
- package/dist/tools/manage_index.js +77 -5
- package/dist/tools/read_file.js +151 -35
- package/dist/tools/search_codebase.js +15 -3
- package/dist/tools/types.d.ts +7 -0
- package/dist/tools/types.js +28 -0
- package/dist/utils.d.ts +36 -1
- package/dist/utils.js +83 -7
- package/package.json +3 -3
- package/dist/cli/install.d.ts +0 -46
- package/dist/cli/install.js +0 -928
- package/dist/cli/package-installability.d.ts +0 -14
- package/dist/cli/package-installability.js +0 -124
|
@@ -2,7 +2,7 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as crypto from "node:crypto";
|
|
3
3
|
import { COLLECTION_LIMIT_MESSAGE, deleteCollectionWithVerification, RemoteCollectionDeletePendingError, } from "@zokizuan/satori-core";
|
|
4
4
|
import { classifyVectorBackendError, } from "./backend-diagnostics.js";
|
|
5
|
-
import {
|
|
5
|
+
import { absolutePathOrRaw, requireAbsoluteFilesystemPath, trackCodebasePath } from "../utils.js";
|
|
6
6
|
function isMatchingVerifiedFingerprint(info, runtimeFingerprint) {
|
|
7
7
|
if (info?.fingerprintSource !== "verified") {
|
|
8
8
|
return undefined;
|
|
@@ -144,7 +144,11 @@ export class ManageIndexingHandlers {
|
|
|
144
144
|
const requestedDropCollection = typeof zillizDropCollection === "string" ? zillizDropCollection.trim() : undefined;
|
|
145
145
|
let dropSummaryLine = "";
|
|
146
146
|
try {
|
|
147
|
-
const
|
|
147
|
+
const absolutePathResult = requireAbsoluteFilesystemPath(codebasePath, "path");
|
|
148
|
+
if (!absolutePathResult.ok) {
|
|
149
|
+
return this.host.manageResponse(manageAction, codebasePath, "error", absolutePathResult.message, preflightOptions);
|
|
150
|
+
}
|
|
151
|
+
const absolutePath = absolutePathResult.absolutePath;
|
|
148
152
|
if (!fs.existsSync(absolutePath)) {
|
|
149
153
|
return this.host.manageResponse(manageAction, absolutePath, "error", `Error: Path '${absolutePath}' does not exist. Original input: '${codebasePath}'`, preflightOptions);
|
|
150
154
|
}
|
|
@@ -314,7 +318,7 @@ export class ManageIndexingHandlers {
|
|
|
314
318
|
const ignoreInfo = customIgnorePatterns.length > 0
|
|
315
319
|
? `\nUsing ${customIgnorePatterns.length} custom ignore patterns: ${customIgnorePatterns.join(", ")}`
|
|
316
320
|
: "";
|
|
317
|
-
return this.host.manageResponse(manageAction, absolutePath, "ok", `Started background indexing for codebase '${absolutePath}'.${pathInfo}${dropSummaryLine}${extensionInfo}${ignoreInfo}\n\nIndexing is running in the background.
|
|
321
|
+
return this.host.manageResponse(manageAction, absolutePath, "ok", `Started background indexing for codebase '${absolutePath}'.${pathInfo}${dropSummaryLine}${extensionInfo}${ignoreInfo}\n\nIndexing is running in the background. Search and navigation are blocked until indexing completes. Poll manage_index with {"action":"status","path":"${absolutePath}"} (or wait for completion); do not search for partial results while status is indexing.`, preflightOptions);
|
|
318
322
|
}
|
|
319
323
|
catch (error) {
|
|
320
324
|
console.error("Error in handleIndexCodebase:", error);
|
|
@@ -325,14 +329,18 @@ export class ManageIndexingHandlers {
|
|
|
325
329
|
const humanText = preservesLocalState
|
|
326
330
|
? `${vectorBackendDiagnostic.message} ${errorMessage}`
|
|
327
331
|
: vectorBackendDiagnostic.message;
|
|
328
|
-
return this.host.manageVectorBackendResponse(manageAction,
|
|
332
|
+
return this.host.manageVectorBackendResponse(manageAction, absolutePathOrRaw(codebasePath), vectorBackendDiagnostic, humanText);
|
|
329
333
|
}
|
|
330
|
-
return this.host.manageResponse(manageAction,
|
|
334
|
+
return this.host.manageResponse(manageAction, absolutePathOrRaw(codebasePath), "error", `Error starting indexing: ${formatUnknownError(error)}`, preflightOptions);
|
|
331
335
|
}
|
|
332
336
|
}
|
|
333
337
|
async handleReindexCodebase(args) {
|
|
334
338
|
const { path: codebasePath, customExtensions, ignorePatterns, zillizDropCollection, allowUnnecessaryReindex } = args;
|
|
335
|
-
const
|
|
339
|
+
const absolutePathResult = requireAbsoluteFilesystemPath(codebasePath, "path");
|
|
340
|
+
if (!absolutePathResult.ok) {
|
|
341
|
+
return this.host.manageResponse("reindex", codebasePath, "error", absolutePathResult.message);
|
|
342
|
+
}
|
|
343
|
+
const absolutePath = absolutePathResult.absolutePath;
|
|
336
344
|
const runtimeOwnerConflict = await this.host.buildRuntimeOwnerConflictResponseIfBlocked("reindex", absolutePath);
|
|
337
345
|
if (runtimeOwnerConflict) {
|
|
338
346
|
return runtimeOwnerConflict;
|
|
@@ -374,7 +382,11 @@ export class ManageIndexingHandlers {
|
|
|
374
382
|
}
|
|
375
383
|
let absolutePath = codebasePath;
|
|
376
384
|
try {
|
|
377
|
-
|
|
385
|
+
const absolutePathResult = requireAbsoluteFilesystemPath(codebasePath, "path");
|
|
386
|
+
if (!absolutePathResult.ok) {
|
|
387
|
+
return this.host.manageResponse("repair", codebasePath, "error", absolutePathResult.message);
|
|
388
|
+
}
|
|
389
|
+
absolutePath = absolutePathResult.absolutePath;
|
|
378
390
|
if (!fs.existsSync(absolutePath)) {
|
|
379
391
|
return this.host.manageResponse("repair", absolutePath, "error", `Error: Path '${absolutePath}' does not exist. Original input: '${codebasePath}'`);
|
|
380
392
|
}
|
|
@@ -491,16 +503,25 @@ export class ManageIndexingHandlers {
|
|
|
491
503
|
catch (pruneError) {
|
|
492
504
|
console.warn(`[BACKGROUND-INDEX] Failed to retire superseded generations for '${absolutePath}': ${formatUnknownError(pruneError)}`);
|
|
493
505
|
}
|
|
506
|
+
// indexStatus is carried on stats (completed | limit_reached). limit_reached remains
|
|
507
|
+
// searchable only when core wrote a completion marker for partial vector proof;
|
|
508
|
+
// navigation still fails closed via indexStatus checks (partial_index_navigation_unavailable).
|
|
494
509
|
this.host.snapshotManager.setCodebaseIndexed(absolutePath, stats, this.host.runtimeFingerprint, "verified", targetCollectionName);
|
|
495
510
|
this.host.snapshotManager.setCodebaseIndexManifest(absolutePath, this.host.getContextTrackedRelativePaths(absolutePath));
|
|
496
511
|
this.host.setIndexingStats({ indexedFiles: stats.indexedFiles, totalChunks: stats.totalChunks });
|
|
497
512
|
await this.host.syncManager.recordCurrentIgnoreControlSignature(absolutePath);
|
|
498
513
|
this.host.saveSnapshotIfSupported();
|
|
499
|
-
|
|
514
|
+
// Full navigation rebuild only for completed indexes; partial indexes have no registry seal.
|
|
515
|
+
if (stats.status === "completed") {
|
|
516
|
+
await this.host.rebuildCallGraphForIndex(absolutePath);
|
|
517
|
+
}
|
|
500
518
|
await this.host.touchWatchedCodebase(absolutePath);
|
|
501
519
|
let message = `Background indexing completed for '${absolutePath}'.\nIndexed ${stats.indexedFiles} files, ${stats.totalChunks} chunks.`;
|
|
502
520
|
if (stats.status === "limit_reached") {
|
|
503
|
-
message += "\n⚠️ Warning: Indexing stopped because the chunk limit (450,000) was reached.
|
|
521
|
+
message += "\n⚠️ Warning: Indexing stopped because the chunk limit (450,000) was reached."
|
|
522
|
+
+ " Search may return incomplete results with SEARCH_PARTIAL_INDEX warnings."
|
|
523
|
+
+ " file_outline/call_graph are unavailable until a full reindex completes successfully."
|
|
524
|
+
+ " This is not a fully complete index.";
|
|
504
525
|
}
|
|
505
526
|
console.log(`[BACKGROUND-INDEX] ${message}`);
|
|
506
527
|
}
|
|
@@ -3,6 +3,8 @@ import type { SnapshotCorruptionWarning, SnapshotManager } from "./snapshot.js";
|
|
|
3
3
|
import type { SyncManager } from "./sync.js";
|
|
4
4
|
import type { TrackedRootReadiness } from "./tracked-root-readiness.js";
|
|
5
5
|
import { type VectorBackendDiagnostic } from "./backend-diagnostics.js";
|
|
6
|
+
import type { ManageIndexAction, ManageIndexStatus } from "./manage-types.js";
|
|
7
|
+
import { type RuntimeOwnerMutationAction, type RuntimeOwnersSummary } from "./runtime-owner.js";
|
|
6
8
|
type ToolArgs = Record<string, unknown>;
|
|
7
9
|
type ToolTextResponse = {
|
|
8
10
|
content: Array<{
|
|
@@ -11,7 +13,6 @@ type ToolTextResponse = {
|
|
|
11
13
|
}>;
|
|
12
14
|
isError?: boolean;
|
|
13
15
|
};
|
|
14
|
-
type ManageIndexStatus = "ok" | "error" | "not_ready" | "not_indexed" | "blocked" | "requires_reindex";
|
|
15
16
|
type ManageMaintenanceHandlersHost = {
|
|
16
17
|
context: Pick<Context, "clearIndex">;
|
|
17
18
|
snapshotManager: Pick<SnapshotManager, "removeCodebaseCompletely">;
|
|
@@ -23,11 +24,11 @@ type ManageMaintenanceHandlersHost = {
|
|
|
23
24
|
getSnapshotCodebaseStatus(codebasePath: string): string;
|
|
24
25
|
getSnapshotCodebaseInfo(codebasePath: string): Record<string, unknown> | undefined;
|
|
25
26
|
getSnapshotCorruptionWarning(): SnapshotCorruptionWarning | undefined;
|
|
26
|
-
buildRuntimeOwnerConflictResponseIfBlocked(action: "clear" | "sync"
|
|
27
|
+
buildRuntimeOwnerConflictResponseIfBlocked(action: Extract<RuntimeOwnerMutationAction, "clear" | "sync">, codebasePath: string): Promise<ToolTextResponse | null>;
|
|
27
28
|
recoverStaleIndexingStateIfNeeded(codebasePath: string): Promise<void>;
|
|
28
|
-
manageResponse(action: string, path: string, status: ManageIndexStatus | string, message: string, options?: Record<string, unknown>): ToolTextResponse;
|
|
29
|
+
manageResponse(action: ManageIndexAction | string, path: string, status: ManageIndexStatus | string, message: string, options?: Record<string, unknown>): ToolTextResponse;
|
|
29
30
|
buildCreateHint(codebasePath: string): Record<string, unknown>;
|
|
30
|
-
buildManageActionBlockedMessage(codebasePath: string, action: "clear" | "sync"): string;
|
|
31
|
+
buildManageActionBlockedMessage(codebasePath: string, action: Extract<RuntimeOwnerMutationAction, "clear" | "sync">): string;
|
|
31
32
|
buildStatusHint(codebasePath: string): Record<string, unknown>;
|
|
32
33
|
getManageRetryAfterMs(): number;
|
|
33
34
|
buildIndexingMetadata(codebasePath: string): Record<string, unknown> | undefined;
|
|
@@ -51,6 +52,8 @@ type ManageMaintenanceHandlersHost = {
|
|
|
51
52
|
buildReindexHint(codebasePath: string): Record<string, unknown>;
|
|
52
53
|
touchWatchedCodebase(codebasePath: string): Promise<void>;
|
|
53
54
|
manageVectorBackendResponse(action: string, path: string, diagnostic: VectorBackendDiagnostic, humanText?: string): ToolTextResponse;
|
|
55
|
+
/** Optional live MCP runtime owner summary for status diagnostics. */
|
|
56
|
+
getLiveOwnersSummary?(): Promise<RuntimeOwnersSummary | null> | RuntimeOwnersSummary | null;
|
|
54
57
|
};
|
|
55
58
|
export declare class ManageMaintenanceHandlers {
|
|
56
59
|
private readonly host;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
|
-
import { COLLECTION_LIMIT_MESSAGE, RemoteCollectionDeletePendingError, } from "@zokizuan/satori-core";
|
|
2
|
+
import { COLLECTION_LIMIT_MESSAGE, RemoteCollectionDeletePendingError, formatSymbolQualityMarker, resolveSymbolQualitySummary, } from "@zokizuan/satori-core";
|
|
3
3
|
import { WARNING_CODES } from "./warnings.js";
|
|
4
4
|
import { classifyVectorBackendError, } from "./backend-diagnostics.js";
|
|
5
|
-
import {
|
|
5
|
+
import { requireAbsoluteFilesystemPath } from "../utils.js";
|
|
6
|
+
import { formatRuntimeOwnersStatusLine, } from "./runtime-owner.js";
|
|
6
7
|
function collectErrorFragments(value, output, visited, depth = 0) {
|
|
7
8
|
if (value === null || value === undefined || depth > 4 || output.length >= 8) {
|
|
8
9
|
return;
|
|
@@ -78,7 +79,11 @@ export class ManageMaintenanceHandlers {
|
|
|
78
79
|
}
|
|
79
80
|
async handleClearIndex(args) {
|
|
80
81
|
const codebasePath = typeof args.path === "string" ? args.path : "";
|
|
81
|
-
const
|
|
82
|
+
const absolutePathResult = requireAbsoluteFilesystemPath(codebasePath, "path");
|
|
83
|
+
if (!absolutePathResult.ok) {
|
|
84
|
+
return this.host.manageResponse("clear", codebasePath, "error", absolutePathResult.message);
|
|
85
|
+
}
|
|
86
|
+
const requestedPath = absolutePathResult.absolutePath;
|
|
82
87
|
if (this.host.getSnapshotAllCodebases().length === 0) {
|
|
83
88
|
return this.host.manageResponse("clear", requestedPath, "not_indexed", "No codebases are currently tracked.", { reason: "not_indexed" });
|
|
84
89
|
}
|
|
@@ -167,7 +172,11 @@ export class ManageMaintenanceHandlers {
|
|
|
167
172
|
}
|
|
168
173
|
async handleGetIndexingStatus(args) {
|
|
169
174
|
const codebasePath = typeof args.path === "string" ? args.path : "";
|
|
170
|
-
const
|
|
175
|
+
const absolutePathResult = requireAbsoluteFilesystemPath(codebasePath, "path");
|
|
176
|
+
if (!absolutePathResult.ok) {
|
|
177
|
+
return this.host.manageResponse("status", codebasePath, "error", absolutePathResult.message);
|
|
178
|
+
}
|
|
179
|
+
const requestedPath = absolutePathResult.absolutePath;
|
|
171
180
|
try {
|
|
172
181
|
const absolutePath = requestedPath;
|
|
173
182
|
if (!fs.existsSync(absolutePath)) {
|
|
@@ -281,7 +290,16 @@ export class ManageMaintenanceHandlers {
|
|
|
281
290
|
const info = trackedRootState.root.info || this.host.getSnapshotCodebaseInfo(trackedRootState.root.path);
|
|
282
291
|
switch (status) {
|
|
283
292
|
case "indexed":
|
|
284
|
-
if (info?.status === "indexed") {
|
|
293
|
+
if (info?.status === "indexed" && info.indexStatus === "limit_reached") {
|
|
294
|
+
statusMessage = `⚠️ Codebase '${trackedRootState.root.path}' is partially indexed (limit_reached).`;
|
|
295
|
+
statusMessage += `\n📊 Statistics: ${info.indexedFiles} files, ${info.totalChunks} chunks`;
|
|
296
|
+
statusMessage += `\n📅 Status: ${info.indexStatus}`;
|
|
297
|
+
statusMessage += `\nSearch may return incomplete results; file_outline/call_graph are unavailable until a full reindex completes.`;
|
|
298
|
+
if (typeof info.lastUpdated === "string") {
|
|
299
|
+
statusMessage += `\n🕐 Last updated: ${new Date(info.lastUpdated).toLocaleString()}`;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
else if (info?.status === "indexed") {
|
|
285
303
|
statusMessage = `✅ Codebase '${trackedRootState.root.path}' is fully indexed and ready for search.`;
|
|
286
304
|
statusMessage += `\n📊 Statistics: ${info.indexedFiles} files, ${info.totalChunks} chunks`;
|
|
287
305
|
statusMessage += `\n📅 Status: ${info.indexStatus}`;
|
|
@@ -319,6 +337,17 @@ export class ManageMaintenanceHandlers {
|
|
|
319
337
|
statusMessage += `\n⚠️ Completion proof check is temporarily unavailable (probe_failed); keeping local status.`;
|
|
320
338
|
warnings.push(WARNING_CODES.IGNORE_POLICY_PROBE_FAILED);
|
|
321
339
|
}
|
|
340
|
+
// F9: observed symbol quality from registry (not parser-cause diagnosis).
|
|
341
|
+
let symbolQuality;
|
|
342
|
+
// Attach observed quality for lifecycle statuses that refer to a real root path.
|
|
343
|
+
if (envelopeStatus === "ok" || envelopeStatus === "not_ready" || envelopeStatus === "not_indexed") {
|
|
344
|
+
symbolQuality = await resolveSymbolQualitySummary({
|
|
345
|
+
normalizedRootPath: envelopePath,
|
|
346
|
+
});
|
|
347
|
+
if (envelopeStatus === "ok") {
|
|
348
|
+
statusMessage += `\n🧭 ${formatSymbolQualityMarker(symbolQuality)}: ${symbolQuality.message}`;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
322
351
|
const pathInfo = codebasePath !== envelopePath
|
|
323
352
|
? `\nNote: Input path '${codebasePath}' was resolved to absolute path '${envelopePath}'`
|
|
324
353
|
: "";
|
|
@@ -335,10 +364,27 @@ export class ManageMaintenanceHandlers {
|
|
|
335
364
|
snapshotCorruption: snapshotCorruptionWarning,
|
|
336
365
|
};
|
|
337
366
|
}
|
|
338
|
-
|
|
367
|
+
let runtimeOwnersLine = "";
|
|
368
|
+
if (typeof this.host.getLiveOwnersSummary === "function") {
|
|
369
|
+
try {
|
|
370
|
+
const ownersSummary = await this.host.getLiveOwnersSummary();
|
|
371
|
+
if (ownersSummary) {
|
|
372
|
+
runtimeOwnersLine = `\n👥 ${formatRuntimeOwnersStatusLine(ownersSummary)}`;
|
|
373
|
+
envelopeHints = {
|
|
374
|
+
...(envelopeHints || {}),
|
|
375
|
+
runtimeOwners: ownersSummary,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
// Diagnostic only; never fail status on owner registry issues.
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return this.host.manageResponse("status", envelopePath, envelopeStatus, statusMessage + compatibilityStatus + pathInfo + snapshotWarningText + runtimeOwnersLine, {
|
|
339
384
|
reason: envelopeReason,
|
|
340
385
|
hints: envelopeHints,
|
|
341
386
|
warnings,
|
|
387
|
+
...(symbolQuality ? { symbolQuality } : {}),
|
|
342
388
|
});
|
|
343
389
|
}
|
|
344
390
|
catch (error) {
|
|
@@ -347,7 +393,11 @@ export class ManageMaintenanceHandlers {
|
|
|
347
393
|
}
|
|
348
394
|
async handleSyncCodebase(args) {
|
|
349
395
|
const codebasePath = typeof args.path === "string" ? args.path : "";
|
|
350
|
-
const
|
|
396
|
+
const absolutePathResult = requireAbsoluteFilesystemPath(codebasePath, "path");
|
|
397
|
+
if (!absolutePathResult.ok) {
|
|
398
|
+
return this.host.manageResponse("sync", codebasePath, "error", absolutePathResult.message);
|
|
399
|
+
}
|
|
400
|
+
const requestedPath = absolutePathResult.absolutePath;
|
|
351
401
|
try {
|
|
352
402
|
const absolutePath = requestedPath;
|
|
353
403
|
if (!fs.existsSync(absolutePath)) {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { SymbolQualitySummary } from "@zokizuan/satori-core";
|
|
1
2
|
import { WarningCode } from "./warnings.js";
|
|
2
|
-
|
|
3
|
+
/** Public manage_index action set (SSOT for schema, docs, and contract tests). */
|
|
4
|
+
export declare const MANAGE_INDEX_ACTIONS: readonly ["create", "reindex", "sync", "status", "clear", "repair"];
|
|
5
|
+
export type ManageIndexAction = (typeof MANAGE_INDEX_ACTIONS)[number];
|
|
3
6
|
export type ManageIndexStatus = "ok" | "not_ready" | "not_indexed" | "requires_reindex" | "blocked" | "error";
|
|
4
7
|
export type ManageIndexReason = "indexing" | "not_indexed" | "requires_reindex" | "unnecessary_reindex_ignore_only" | "preflight_unknown" | "backend_timeout" | "remote_delete_pending" | "missing_provider_config" | "vector_backend_unavailable" | "runtime_owner_conflict" | "needs_create";
|
|
5
8
|
export type VectorBackendResponseCode = "ZILLIZ_CLUSTER_STOPPED" | "VECTOR_BACKEND_AUTH_FAILED" | "VECTOR_BACKEND_UNREACHABLE" | "VECTOR_BACKEND_TIMEOUT" | "VECTOR_BACKEND_CONNECTION_CLOSED";
|
|
@@ -25,5 +28,7 @@ export interface ManageIndexResponseEnvelope {
|
|
|
25
28
|
confidence: "high" | "low";
|
|
26
29
|
probeFailed?: boolean;
|
|
27
30
|
};
|
|
31
|
+
/** Observed symbol quality from registry (F9); not parser-cause diagnosis. */
|
|
32
|
+
symbolQuality?: SymbolQualitySummary;
|
|
28
33
|
}
|
|
29
34
|
//# sourceMappingURL=manage-types.d.ts.map
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { type NavigationStore, type SymbolRecord } from "@zokizuan/satori-core";
|
|
2
|
+
/**
|
|
3
|
+
* Non-blocking outline warning: count + optional sample keys + agent action.
|
|
4
|
+
* Does not dump every registry diagnostic string into the outline payload.
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatOutlineSymbolRegistryWarnings(registryWarnings: readonly string[]): string | undefined;
|
|
2
7
|
import { type PythonSourceBackedSpanRepair } from "./python-call-fallback.js";
|
|
3
8
|
import type { CompletionProbeDebugHint, TrackedRootReadiness } from "./tracked-root-readiness.js";
|
|
4
9
|
import type { CallGraphDirection, CallGraphEdge, CallGraphNode, CallGraphNote, CallGraphSymbolRef, CallGraphTestReference } from "./call-graph.js";
|
|
@@ -126,6 +131,7 @@ type NavigationHandlersHost = {
|
|
|
126
131
|
nodeCount: number;
|
|
127
132
|
edgeCount: number;
|
|
128
133
|
};
|
|
134
|
+
hints?: Record<string, unknown>;
|
|
129
135
|
} | null>;
|
|
130
136
|
};
|
|
131
137
|
export declare class NavigationHandlers {
|
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import { getSupportedExtensionsForCapability, } from "@zokizuan/satori-core";
|
|
3
|
+
import { compareContractStrings, getSupportedExtensionsForCapability, } from "@zokizuan/satori-core";
|
|
4
|
+
const OUTLINE_DUPLICATE_SYMBOL_KEY_RE = /^Duplicate symbolKey '([^']+)' has \d+ candidates$/;
|
|
5
|
+
/**
|
|
6
|
+
* Non-blocking outline warning: count + optional sample keys + agent action.
|
|
7
|
+
* Does not dump every registry diagnostic string into the outline payload.
|
|
8
|
+
*/
|
|
9
|
+
export function formatOutlineSymbolRegistryWarnings(registryWarnings) {
|
|
10
|
+
if (registryWarnings.length === 0) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const samples = [];
|
|
14
|
+
for (const warning of registryWarnings) {
|
|
15
|
+
const match = OUTLINE_DUPLICATE_SYMBOL_KEY_RE.exec(warning);
|
|
16
|
+
if (match) {
|
|
17
|
+
samples.push(match[1]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
samples.sort(compareContractStrings);
|
|
21
|
+
const sample = samples.slice(0, 3).join(",");
|
|
22
|
+
return `OUTLINE_SYMBOL_REGISTRY_WARNINGS:${registryWarnings.length} action=treat_outline_as_degraded_identity${sample ? ` sample=${sample}` : ""}`;
|
|
23
|
+
}
|
|
4
24
|
import { repairSourceBackedPythonSpan, } from "./python-call-fallback.js";
|
|
5
25
|
import { buildRegistryFileOutlinePayload, findExactRegistrySymbols, } from "./registry-file-outline.js";
|
|
6
|
-
import {
|
|
26
|
+
import { requireAbsoluteFilesystemPath, requireRepoRelativeFilePath, trackCodebasePath } from "../utils.js";
|
|
7
27
|
const OUTLINE_SUPPORTED_EXTENSIONS = getSupportedExtensionsForCapability("fileOutline");
|
|
8
28
|
const PARTIAL_INDEX_NAVIGATION_UNAVAILABLE_DETAIL = "Partial index/search data may exist, but navigation sidecars were not published because indexing stopped before completion.";
|
|
9
29
|
function collectErrorFragments(value, output, visited, depth = 0) {
|
|
@@ -81,8 +101,24 @@ export class NavigationHandlers {
|
|
|
81
101
|
const symbolIdExact = typeof args?.symbolIdExact === "string" ? args.symbolIdExact.trim() : undefined;
|
|
82
102
|
const symbolLabelExact = typeof args?.symbolLabelExact === "string" ? args.symbolLabelExact.trim() : undefined;
|
|
83
103
|
try {
|
|
84
|
-
const
|
|
85
|
-
|
|
104
|
+
const absoluteRootResult = requireAbsoluteFilesystemPath(args.path, "path");
|
|
105
|
+
if (!absoluteRootResult.ok) {
|
|
106
|
+
const payload = this.host.buildInvalidFileOutlineRequestPayload(absoluteRootResult.path, typeof args.file === "string" ? args.file : "", absoluteRootResult.message, "not_indexed", "not_indexed");
|
|
107
|
+
return {
|
|
108
|
+
content: [{ type: "text", text: this.host.stringifyToolJson(payload) }],
|
|
109
|
+
isError: true,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const absoluteRoot = absoluteRootResult.absolutePath;
|
|
113
|
+
const relativeFileResult = requireRepoRelativeFilePath(typeof args.file === "string" ? args.file : "", "file");
|
|
114
|
+
if (!relativeFileResult.ok) {
|
|
115
|
+
const payload = this.host.buildInvalidFileOutlineRequestPayload(absoluteRoot, relativeFileResult.path, relativeFileResult.message, "not_found");
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: "text", text: this.host.stringifyToolJson(payload) }],
|
|
118
|
+
isError: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const normalizedFile = this.host.normalizeRelativeFilePath(relativeFileResult.relativePath);
|
|
86
122
|
if (!fs.existsSync(absoluteRoot)) {
|
|
87
123
|
const payload = this.host.buildInvalidFileOutlineRequestPayload(absoluteRoot, normalizedFile, `Path '${absoluteRoot}' does not exist. file_outline requires an indexed codebase directory root.`, "not_indexed", "not_indexed");
|
|
88
124
|
return {
|
|
@@ -227,9 +263,11 @@ export class NavigationHandlers {
|
|
|
227
263
|
codebaseRoot: effectiveRoot,
|
|
228
264
|
registryManifestHash: registryState.manifestHash,
|
|
229
265
|
});
|
|
230
|
-
const outlineWarnings =
|
|
231
|
-
|
|
232
|
-
|
|
266
|
+
const outlineWarnings = [];
|
|
267
|
+
const registryWarning = formatOutlineSymbolRegistryWarnings(registryState.warnings);
|
|
268
|
+
if (registryWarning) {
|
|
269
|
+
outlineWarnings.push(registryWarning);
|
|
270
|
+
}
|
|
233
271
|
if (relationshipGraph.warning) {
|
|
234
272
|
outlineWarnings.push(`OUTLINE_${relationshipGraph.warning}`);
|
|
235
273
|
}
|
|
@@ -307,7 +345,11 @@ export class NavigationHandlers {
|
|
|
307
345
|
};
|
|
308
346
|
}
|
|
309
347
|
catch (error) {
|
|
310
|
-
const
|
|
348
|
+
const pathResult = typeof args?.path === "string"
|
|
349
|
+
? requireAbsoluteFilesystemPath(args.path)
|
|
350
|
+
: null;
|
|
351
|
+
const pathForError = pathResult?.ok ? pathResult.absolutePath : (typeof args?.path === "string" ? args.path : "");
|
|
352
|
+
const payload = this.host.buildInvalidFileOutlineRequestPayload(pathForError, typeof args?.file === "string" ? this.host.normalizeRelativeFilePath(args.file) : "", `Unexpected file_outline failure: ${formatUnknownError(error)}`, "not_ready");
|
|
311
353
|
return {
|
|
312
354
|
content: [{ type: "text", text: this.host.stringifyToolJson(payload) }],
|
|
313
355
|
isError: true,
|
|
@@ -322,19 +364,41 @@ export class NavigationHandlers {
|
|
|
322
364
|
const depth = Number.isFinite(args?.depth) ? Math.max(1, Math.min(3, Number(args.depth))) : 1;
|
|
323
365
|
const limit = Number.isFinite(args?.limit) ? Math.max(1, Number(args.limit)) : 20;
|
|
324
366
|
const symbolRef = args?.symbolRef;
|
|
367
|
+
const symbolFileResult = typeof symbolRef?.file === "string"
|
|
368
|
+
? requireRepoRelativeFilePath(symbolRef.file, "symbolRef.file")
|
|
369
|
+
: { ok: false, path: "", message: "symbolRef.file is required." };
|
|
325
370
|
const normalizedSymbolRef = {
|
|
326
|
-
file:
|
|
371
|
+
file: symbolFileResult.ok
|
|
372
|
+
? this.host.normalizeRelativeFilePath(symbolFileResult.relativePath)
|
|
373
|
+
: (typeof symbolRef?.file === "string" ? this.host.normalizeRelativeFilePath(symbolRef.file) : ""),
|
|
327
374
|
symbolId: typeof symbolRef?.symbolId === "string" ? symbolRef.symbolId : "",
|
|
328
375
|
...(typeof symbolRef?.symbolLabel === "string" ? { symbolLabel: symbolRef.symbolLabel } : {}),
|
|
329
376
|
...(symbolRef?.span ? { span: symbolRef.span } : {}),
|
|
330
377
|
};
|
|
378
|
+
const absolutePathResult = typeof args?.path === "string"
|
|
379
|
+
? requireAbsoluteFilesystemPath(args.path, "path")
|
|
380
|
+
: { ok: false, path: "", message: "path is required." };
|
|
331
381
|
const invalidSymbolRefContext = {
|
|
332
|
-
path: typeof args?.path === "string" ?
|
|
382
|
+
path: absolutePathResult.ok ? absolutePathResult.absolutePath : (typeof args?.path === "string" ? args.path : ""),
|
|
333
383
|
symbolRef: normalizedSymbolRef,
|
|
334
384
|
direction,
|
|
335
385
|
depth,
|
|
336
386
|
limit,
|
|
337
387
|
};
|
|
388
|
+
if (!absolutePathResult.ok) {
|
|
389
|
+
const payload = this.host.buildInvalidCallGraphRequestPayload(invalidSymbolRefContext, absolutePathResult.message, "not_indexed", "not_indexed");
|
|
390
|
+
return {
|
|
391
|
+
content: [{ type: "text", text: this.host.stringifyToolJson(payload) }],
|
|
392
|
+
isError: true,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
if (!symbolFileResult.ok) {
|
|
396
|
+
const payload = this.host.buildInvalidCallGraphRequestPayload(invalidSymbolRefContext, symbolFileResult.message, "not_found", "invalid_symbol_ref");
|
|
397
|
+
return {
|
|
398
|
+
content: [{ type: "text", text: this.host.stringifyToolJson(payload) }],
|
|
399
|
+
isError: true,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
338
402
|
if (!symbolRef || typeof symbolRef.file !== "string" || typeof symbolRef.symbolId !== "string") {
|
|
339
403
|
const payload = this.host.buildInvalidCallGraphRequestPayload(invalidSymbolRefContext, "symbolRef with { file, symbolId } is required.", "not_found", "invalid_symbol_ref");
|
|
340
404
|
return {
|
|
@@ -343,7 +407,7 @@ export class NavigationHandlers {
|
|
|
343
407
|
};
|
|
344
408
|
}
|
|
345
409
|
try {
|
|
346
|
-
const absolutePath =
|
|
410
|
+
const absolutePath = absolutePathResult.absolutePath;
|
|
347
411
|
if (!fs.existsSync(absolutePath)) {
|
|
348
412
|
const payload = this.host.buildInvalidCallGraphRequestPayload({
|
|
349
413
|
path: absolutePath,
|
|
@@ -658,8 +722,11 @@ export class NavigationHandlers {
|
|
|
658
722
|
};
|
|
659
723
|
}
|
|
660
724
|
catch (error) {
|
|
725
|
+
const pathResult = typeof args?.path === "string"
|
|
726
|
+
? requireAbsoluteFilesystemPath(args.path)
|
|
727
|
+
: null;
|
|
661
728
|
const payload = this.host.buildInvalidCallGraphRequestPayload({
|
|
662
|
-
path: typeof args?.path === "string" ?
|
|
729
|
+
path: pathResult?.ok ? pathResult.absolutePath : (typeof args?.path === "string" ? args.path : ""),
|
|
663
730
|
symbolRef: normalizedSymbolRef,
|
|
664
731
|
direction,
|
|
665
732
|
depth,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type SymbolRecord } from "@zokizuan/satori-core";
|
|
2
2
|
import type { CallGraphHint } from "./search-types.js";
|
|
3
3
|
import type { FileOutlineResponseEnvelope } from "./search-types.js";
|
|
4
4
|
import { type PythonSourceBackedSpanRepair } from "./python-call-fallback.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { compareContractStrings } from "@zokizuan/satori-core";
|
|
1
2
|
import { repairSourceBackedPythonSpans, } from "./python-call-fallback.js";
|
|
2
3
|
function compareNullableNumbersAsc(a, b) {
|
|
3
4
|
const left = a ?? Number.POSITIVE_INFINITY;
|
|
@@ -7,7 +8,7 @@ function compareNullableNumbersAsc(a, b) {
|
|
|
7
8
|
function compareNullableStringsAsc(a, b) {
|
|
8
9
|
const left = a ?? "\uffff";
|
|
9
10
|
const right = b ?? "\uffff";
|
|
10
|
-
return left
|
|
11
|
+
return compareContractStrings(left, right);
|
|
11
12
|
}
|
|
12
13
|
function sortFileOutlineSymbols(symbols) {
|
|
13
14
|
return [...symbols].sort((a, b) => {
|
|
@@ -106,7 +107,7 @@ export function buildRegistryFileOutlinePayload(input) {
|
|
|
106
107
|
if (!visibleState.hasExtractedSymbols && symbols.length > 0) {
|
|
107
108
|
warningSet.add("OUTLINE_SYNTHESIZED_FILE_SYMBOL");
|
|
108
109
|
}
|
|
109
|
-
return [...warningSet].sort(
|
|
110
|
+
return [...warningSet].sort(compareContractStrings);
|
|
110
111
|
};
|
|
111
112
|
if (input.resolveMode === "exact") {
|
|
112
113
|
const exactMatchIds = new Set(findExactRegistrySymbols({
|
|
@@ -2,6 +2,11 @@ import { type NavigationStore, type SymbolRecord, type SymbolRegistry } from "@z
|
|
|
2
2
|
import type { SnapshotManager } from "./snapshot.js";
|
|
3
3
|
import type { CallGraphDirection, CallGraphEdge, CallGraphNode, CallGraphNote, CallGraphSidecarManager, CallGraphTestReference } from "./call-graph.js";
|
|
4
4
|
import { type PythonSourceBackedSpanRepair } from "./python-call-fallback.js";
|
|
5
|
+
/**
|
|
6
|
+
* Collapse per-key registry duplicate warnings into one count + sample line.
|
|
7
|
+
* Presentation-only: registry build still retains full diagnostics.
|
|
8
|
+
*/
|
|
9
|
+
export declare function collapseRegistryDuplicateKeyWarnings(warnings: readonly string[]): string[];
|
|
5
10
|
type RelationshipBackedCallGraphHost = {
|
|
6
11
|
navigationStore: NavigationStore;
|
|
7
12
|
callGraphManager: CallGraphSidecarManager;
|
|
@@ -37,7 +42,20 @@ type RelationshipBackedCallGraphResult = {
|
|
|
37
42
|
nodeCount: number;
|
|
38
43
|
edgeCount: number;
|
|
39
44
|
};
|
|
45
|
+
hints?: Record<string, unknown>;
|
|
40
46
|
};
|
|
47
|
+
/** True when a repo-relative path looks like a test/fixture site (not production call graph signal). */
|
|
48
|
+
export declare function isTestOrFixtureCallerFile(file: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Prefer a single unique suppressed inbound caller *site* file for recovery search.
|
|
51
|
+
* Prefer production files when both production and test sites exist.
|
|
52
|
+
* Never use the callee defining file when sites disagree or are multi-file.
|
|
53
|
+
*/
|
|
54
|
+
export declare function uniqueInboundCallerSiteFile(notes: readonly CallGraphNote[]): string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Production suppressed callers first; collapse excess test/fixture caller notes into one summary.
|
|
57
|
+
*/
|
|
58
|
+
export declare function prioritizeInboundSuppressedNotes(notes: readonly CallGraphNote[]): CallGraphNote[];
|
|
41
59
|
export declare class RelationshipBackedCallGraph {
|
|
42
60
|
private readonly host;
|
|
43
61
|
constructor(host: RelationshipBackedCallGraphHost);
|