sift-light 1.0.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/CHANGELOG.md +0 -0
- package/CONTRIBUTING.md +19 -0
- package/LICENSE +661 -0
- package/README.md +177 -0
- package/README.zh-CN.md +177 -0
- package/SECURITY.md +25 -0
- package/package.json +142 -0
- package/plugins/sift-light/.claude-plugin/plugin.json +10 -0
- package/plugins/sift-light/.codex-plugin/plugin.json +20 -0
- package/plugins/sift-light/.mcp.json +24 -0
- package/plugins/sift-light/LICENSE +661 -0
- package/plugins/sift-light/concept-worker.mjs +567 -0
- package/plugins/sift-light/hooks/THIRD_PARTY_NOTICES.txt +70 -0
- package/plugins/sift-light/hooks/hooks.json +16 -0
- package/plugins/sift-light/hooks/search-policy.mjs +4113 -0
- package/plugins/sift-light/hooks/tree-sitter-bash.wasm +0 -0
- package/plugins/sift-light/hooks/tree-sitter-powershell.wasm +0 -0
- package/plugins/sift-light/hooks/tree-sitter.wasm +0 -0
- package/plugins/sift-light/kimi.plugin.json +36 -0
- package/plugins/sift-light/mcp-server.mjs +1 -0
- package/plugins/sift-light/omp-extension.mjs +20914 -0
- package/plugins/sift-light/package.json +11 -0
- package/plugins/sift-light/syntax-worker.mjs +280 -0
- package/plugins/sift-light/syntax-worker.toml +2 -0
- package/src/analysis-evidence.ts +43 -0
- package/src/analysis-limits.ts +27 -0
- package/src/analysis-store.ts +559 -0
- package/src/analysis-term-pages.ts +73 -0
- package/src/analysis-types.ts +162 -0
- package/src/audit-search.ts +391 -0
- package/src/capped-lines.ts +112 -0
- package/src/concept-embedding-cache.ts +186 -0
- package/src/concept-inference.ts +218 -0
- package/src/concept-model.ts +96 -0
- package/src/concept-search.ts +577 -0
- package/src/concept-setup.ts +75 -0
- package/src/concept-source-generation.ts +268 -0
- package/src/concept-worker.mjs +567 -0
- package/src/concept-worker.ts +210 -0
- package/src/config-reader.ts +283 -0
- package/src/config.ts +37 -0
- package/src/context-budget.ts +26 -0
- package/src/discovery-errors.ts +2 -0
- package/src/errors.ts +95 -0
- package/src/evidence-candidates.ts +344 -0
- package/src/evidence-ranking.ts +48 -0
- package/src/evidence-service.ts +1047 -0
- package/src/evidence-validation.ts +466 -0
- package/src/evidence-validity.ts +33 -0
- package/src/excerpt.ts +53 -0
- package/src/file-discovery.ts +150 -0
- package/src/file-metadata-filter.ts +46 -0
- package/src/format.ts +407 -0
- package/src/git-diff.ts +195 -0
- package/src/git-process.ts +189 -0
- package/src/git-repository.ts +367 -0
- package/src/git-source.ts +385 -0
- package/src/historical-paths.ts +205 -0
- package/src/hybrid-search.ts +340 -0
- package/src/import-model.ts +611 -0
- package/src/import-navigation.ts +100 -0
- package/src/import-resolution.ts +240 -0
- package/src/index.ts +97 -0
- package/src/inspect-batch.ts +265 -0
- package/src/inspect.ts +271 -0
- package/src/language-capabilities.ts +157 -0
- package/src/language-capability-definitions.ts +204 -0
- package/src/literal-search.ts +25 -0
- package/src/mcp-cli.ts +21 -0
- package/src/mcp-model-output.ts +120 -0
- package/src/mcp-output.ts +9 -0
- package/src/mcp-semantic-judge.ts +39 -0
- package/src/mcp-server.mjs +14064 -0
- package/src/mcp-server.ts +157 -0
- package/src/mcp-stdio.ts +114 -0
- package/src/mcp.ts +631 -0
- package/src/model-error.ts +120 -0
- package/src/multi-term-search.ts +122 -0
- package/src/omp-index.ts +277 -0
- package/src/omp-marketplace-entry.ts +7 -0
- package/src/operation-lifecycle.ts +413 -0
- package/src/operation-output.ts +100 -0
- package/src/owned-parallel.ts +22 -0
- package/src/owned-process.ts +102 -0
- package/src/owned-task-queue.ts +38 -0
- package/src/package-version.ts +3 -0
- package/src/path-policy.ts +203 -0
- package/src/pi-search-policy.ts +33 -0
- package/src/prompt-guidelines.ts +54 -0
- package/src/python-outline.ts +231 -0
- package/src/record-value.ts +3 -0
- package/src/redaction.ts +95 -0
- package/src/request-contract-catalog.ts +215 -0
- package/src/request-contract-error.ts +96 -0
- package/src/request-contract.ts +481 -0
- package/src/request.ts +132 -0
- package/src/result-statistics.ts +178 -0
- package/src/rg.ts +574 -0
- package/src/ripgrep-diagnostics.ts +122 -0
- package/src/ripgrep-executable.ts +43 -0
- package/src/runtime.ts +53 -0
- package/src/scan-revisions.ts +148 -0
- package/src/script-runtime.ts +11 -0
- package/src/search-policy-commands.ts +170 -0
- package/src/search-policy-hook.ts +61 -0
- package/src/search-policy-recovery.ts +388 -0
- package/src/search-policy-shell.ts +280 -0
- package/src/search-policy.ts +102 -0
- package/src/search-retention.ts +77 -0
- package/src/semantic-judge-batches.ts +135 -0
- package/src/semantic-judge.ts +519 -0
- package/src/service.ts +945 -0
- package/src/session-summary.ts +100 -0
- package/src/snapshot-store.ts +203 -0
- package/src/source-access.ts +288 -0
- package/src/source-continuations.ts +168 -0
- package/src/source-document.ts +277 -0
- package/src/source-inspection.ts +731 -0
- package/src/source-pages.ts +112 -0
- package/src/source.ts +286 -0
- package/src/structural-search.ts +125 -0
- package/src/structure.ts +259 -0
- package/src/summary-previews.ts +96 -0
- package/src/summary.ts +79 -0
- package/src/syntax-facts.ts +464 -0
- package/src/syntax-fields.ts +161 -0
- package/src/syntax-search.ts +361 -0
- package/src/syntax-tree.ts +30 -0
- package/src/syntax-types.ts +72 -0
- package/src/syntax-worker.mjs +280 -0
- package/src/syntax-worker.toml +2 -0
- package/src/syntax-worker.ts +143 -0
- package/src/syntax.ts +259 -0
- package/src/test-navigation-facts.ts +261 -0
- package/src/test-navigation.ts +543 -0
- package/src/tool-schema.ts +321 -0
- package/src/tui/dashboard.ts +107 -0
- package/src/tui/layout.ts +291 -0
- package/src/tui/palette.ts +73 -0
- package/src/tui/presentation.ts +240 -0
- package/src/tui/renderers.ts +106 -0
- package/src/types.ts +368 -0
- package/src/validation-output.ts +148 -0
- package/src/validation-types.ts +48 -0
- package/src/workspace-files.ts +142 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_MCP_HOST,
|
|
4
|
+
DEFAULT_MCP_MAX_SESSIONS,
|
|
5
|
+
DEFAULT_MCP_PORT,
|
|
6
|
+
DEFAULT_MCP_SESSION_IDLE_TIMEOUT_MS,
|
|
7
|
+
SIFT_LIGHT_MCP_PATH,
|
|
8
|
+
createDefaultSiftLightMcpService,
|
|
9
|
+
startSiftLightMcpServer,
|
|
10
|
+
} from "./mcp.js";
|
|
11
|
+
import {
|
|
12
|
+
createMcpSemanticJudgeIntegration,
|
|
13
|
+
mcpSemanticJudgeConfigSource,
|
|
14
|
+
} from "./mcp-semantic-judge.js";
|
|
15
|
+
import type { SemanticJudgeIntegration } from "./semantic-judge.js";
|
|
16
|
+
import { parseSiftLightMcpTransport, SIFT_LIGHT_MCP_USAGE } from "./mcp-cli.js";
|
|
17
|
+
import { parseSiftLightMcpOutputMode, type SiftLightMcpOutputMode } from "./mcp-output.js";
|
|
18
|
+
import { startSiftLightMcpStdioServer } from "./mcp-stdio.js";
|
|
19
|
+
|
|
20
|
+
function environmentInteger(
|
|
21
|
+
name: string,
|
|
22
|
+
fallback: number,
|
|
23
|
+
minimum: number,
|
|
24
|
+
maximum: number,
|
|
25
|
+
): number {
|
|
26
|
+
const value = process.env[name];
|
|
27
|
+
if (value === undefined) return fallback;
|
|
28
|
+
const port = Number(value);
|
|
29
|
+
if (!Number.isSafeInteger(port) || port < minimum || port > maximum) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`${name} must be an integer from ${String(minimum)} through ${String(maximum)}`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return port;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function allowedOrigins(): string[] {
|
|
38
|
+
return (process.env.SIFT_LIGHT_MCP_ALLOWED_ORIGINS ?? "")
|
|
39
|
+
.split(",")
|
|
40
|
+
.map((origin) => origin.trim())
|
|
41
|
+
.filter((origin) => origin.length > 0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function configuredSemanticJudge(): Promise<SemanticJudgeIntegration> {
|
|
45
|
+
return createMcpSemanticJudgeIntegration();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function logSemanticJudgeStatus(integration: SemanticJudgeIntegration): void {
|
|
49
|
+
const status = integration.config.enabled ? "enabled" : "disabled";
|
|
50
|
+
process.stderr.write(
|
|
51
|
+
`sift-light MCP semantic judge: ${status}; source=${mcpSemanticJudgeConfigSource()}\n`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function runHttpServer(
|
|
56
|
+
outputMode: SiftLightMcpOutputMode,
|
|
57
|
+
semanticJudge: SemanticJudgeIntegration | undefined,
|
|
58
|
+
): Promise<void> {
|
|
59
|
+
const running = await startSiftLightMcpServer({
|
|
60
|
+
cwd: process.env.SIFT_LIGHT_MCP_CWD ?? process.cwd(),
|
|
61
|
+
host: process.env.SIFT_LIGHT_MCP_HOST ?? DEFAULT_MCP_HOST,
|
|
62
|
+
port: environmentInteger("SIFT_LIGHT_MCP_PORT", DEFAULT_MCP_PORT, 0, 65_535),
|
|
63
|
+
createService: () => createDefaultSiftLightMcpService(semanticJudge),
|
|
64
|
+
maxSessions: environmentInteger(
|
|
65
|
+
"SIFT_LIGHT_MCP_MAX_SESSIONS",
|
|
66
|
+
DEFAULT_MCP_MAX_SESSIONS,
|
|
67
|
+
1,
|
|
68
|
+
Number.MAX_SAFE_INTEGER,
|
|
69
|
+
),
|
|
70
|
+
sessionIdleTimeoutMs: environmentInteger(
|
|
71
|
+
"SIFT_LIGHT_MCP_SESSION_IDLE_MS",
|
|
72
|
+
DEFAULT_MCP_SESSION_IDLE_TIMEOUT_MS,
|
|
73
|
+
1,
|
|
74
|
+
Number.MAX_SAFE_INTEGER,
|
|
75
|
+
),
|
|
76
|
+
allowedOrigins: allowedOrigins(),
|
|
77
|
+
outputMode,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const address = running.httpServer.address();
|
|
81
|
+
if (!address || !(address instanceof Object)) {
|
|
82
|
+
throw new Error("MCP TCP listener is unavailable");
|
|
83
|
+
}
|
|
84
|
+
const displayHost = address.family === "IPv6" ? `[${address.address}]` : address.address;
|
|
85
|
+
process.stderr.write(
|
|
86
|
+
`sift-light MCP listening on http://${displayHost}:${String(address.port)}${SIFT_LIGHT_MCP_PATH}\n`,
|
|
87
|
+
);
|
|
88
|
+
process.stderr.write(`sift-light MCP working directory: ${running.cwd}\n`);
|
|
89
|
+
|
|
90
|
+
let shuttingDown = false;
|
|
91
|
+
const closeAfterSignal = async (): Promise<void> => {
|
|
92
|
+
try {
|
|
93
|
+
await running.close();
|
|
94
|
+
} catch (error) {
|
|
95
|
+
process.stderr.write(`sift-light MCP shutdown failed: ${String(error)}\n`);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const shutdown = (): void => {
|
|
100
|
+
if (shuttingDown) return;
|
|
101
|
+
shuttingDown = true;
|
|
102
|
+
void closeAfterSignal();
|
|
103
|
+
};
|
|
104
|
+
process.once("SIGINT", shutdown);
|
|
105
|
+
process.once("SIGTERM", shutdown);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function runStdioServer(
|
|
109
|
+
outputMode: SiftLightMcpOutputMode,
|
|
110
|
+
semanticJudge: SemanticJudgeIntegration | undefined,
|
|
111
|
+
): Promise<void> {
|
|
112
|
+
const running = await startSiftLightMcpStdioServer({
|
|
113
|
+
cwd: process.env.SIFT_LIGHT_MCP_CWD ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd(),
|
|
114
|
+
outputMode,
|
|
115
|
+
createService: () => createDefaultSiftLightMcpService(semanticJudge),
|
|
116
|
+
});
|
|
117
|
+
process.stderr.write("sift-light MCP serving one local client over stdio\n");
|
|
118
|
+
process.stderr.write(`sift-light MCP working directory: ${running.cwd}\n`);
|
|
119
|
+
|
|
120
|
+
let shuttingDown = false;
|
|
121
|
+
const shutdown = (): void => {
|
|
122
|
+
if (shuttingDown) return;
|
|
123
|
+
shuttingDown = true;
|
|
124
|
+
void running.close();
|
|
125
|
+
};
|
|
126
|
+
process.once("SIGINT", shutdown);
|
|
127
|
+
process.once("SIGTERM", shutdown);
|
|
128
|
+
try {
|
|
129
|
+
await running.closed;
|
|
130
|
+
} finally {
|
|
131
|
+
process.off("SIGINT", shutdown);
|
|
132
|
+
process.off("SIGTERM", shutdown);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function main(): Promise<void> {
|
|
137
|
+
const transport = parseSiftLightMcpTransport(process.argv.slice(2));
|
|
138
|
+
if (transport === "help") {
|
|
139
|
+
process.stdout.write(SIFT_LIGHT_MCP_USAGE);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const outputMode = parseSiftLightMcpOutputMode(process.env.SIFT_LIGHT_MCP_OUTPUT_MODE);
|
|
143
|
+
const semanticJudge = await configuredSemanticJudge();
|
|
144
|
+
logSemanticJudgeStatus(semanticJudge);
|
|
145
|
+
if (transport === "stdio") {
|
|
146
|
+
await runStdioServer(outputMode, semanticJudge);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
await runHttpServer(outputMode, semanticJudge);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
await main();
|
|
154
|
+
} catch (error) {
|
|
155
|
+
process.stderr.write(`sift-light MCP failed: ${String(error)}\n`);
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
}
|
package/src/mcp-stdio.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { Readable, Writable } from "node:stream";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import {
|
|
4
|
+
createDefaultSiftLightMcpService,
|
|
5
|
+
createSiftLightMcpServer,
|
|
6
|
+
type SiftLightMcpService,
|
|
7
|
+
} from "./mcp.js";
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_MCP_OUTPUT_MODE,
|
|
10
|
+
parseSiftLightMcpOutputMode,
|
|
11
|
+
type SiftLightMcpOutputMode,
|
|
12
|
+
} from "./mcp-output.js";
|
|
13
|
+
|
|
14
|
+
export interface SiftLightMcpStdioOptions {
|
|
15
|
+
cwd?: string;
|
|
16
|
+
input?: Readable;
|
|
17
|
+
output?: Writable;
|
|
18
|
+
outputMode?: SiftLightMcpOutputMode;
|
|
19
|
+
createService?: () => SiftLightMcpService;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RunningSiftLightMcpStdioServer {
|
|
23
|
+
readonly cwd: string;
|
|
24
|
+
readonly closed: Promise<void>;
|
|
25
|
+
close(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function rejectedReasons(results: readonly PromiseSettledResult<unknown>[]): unknown[] {
|
|
29
|
+
return results.flatMap((result) => (result.status === "rejected" ? [result.reason] : []));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function startSiftLightMcpStdioServer(
|
|
33
|
+
options: SiftLightMcpStdioOptions = {},
|
|
34
|
+
): Promise<RunningSiftLightMcpStdioServer> {
|
|
35
|
+
const cwd = options.cwd ?? process.cwd();
|
|
36
|
+
const input = options.input ?? process.stdin;
|
|
37
|
+
const output = options.output ?? process.stdout;
|
|
38
|
+
const outputMode = parseSiftLightMcpOutputMode(options.outputMode ?? DEFAULT_MCP_OUTPUT_MODE);
|
|
39
|
+
const service = (options.createService ?? createDefaultSiftLightMcpService)();
|
|
40
|
+
const protocol = createSiftLightMcpServer(service, cwd, outputMode);
|
|
41
|
+
|
|
42
|
+
const lifecycle = Promise.withResolvers<void>();
|
|
43
|
+
let closePromise: Promise<void> | undefined;
|
|
44
|
+
let transportFailure: Error | undefined;
|
|
45
|
+
const requestClose = (): void => {
|
|
46
|
+
void close();
|
|
47
|
+
};
|
|
48
|
+
const requestFailure = (error: Error): void => {
|
|
49
|
+
transportFailure ??= error;
|
|
50
|
+
void close();
|
|
51
|
+
};
|
|
52
|
+
const removeLifecycleListeners = (): void => {
|
|
53
|
+
input.off("end", requestClose);
|
|
54
|
+
input.off("close", requestClose);
|
|
55
|
+
input.off("error", requestFailure);
|
|
56
|
+
output.off("error", requestFailure);
|
|
57
|
+
};
|
|
58
|
+
const close = (): Promise<void> => {
|
|
59
|
+
if (closePromise) return closePromise;
|
|
60
|
+
input.off("end", requestClose);
|
|
61
|
+
input.off("close", requestClose);
|
|
62
|
+
closePromise = lifecycle.promise;
|
|
63
|
+
const performClose = async (): Promise<void> => {
|
|
64
|
+
const cleanupErrors = rejectedReasons(
|
|
65
|
+
await Promise.allSettled([protocol.close(), service.shutdown()]),
|
|
66
|
+
);
|
|
67
|
+
removeLifecycleListeners();
|
|
68
|
+
const errors = transportFailure ? [transportFailure, ...cleanupErrors] : cleanupErrors;
|
|
69
|
+
if (errors.length > 0) {
|
|
70
|
+
lifecycle.reject(
|
|
71
|
+
new AggregateError(
|
|
72
|
+
errors,
|
|
73
|
+
transportFailure ? "MCP stdio transport failed" : "MCP stdio shutdown failed",
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
lifecycle.resolve();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
void performClose();
|
|
81
|
+
return closePromise;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const transport = new StdioServerTransport(input, output);
|
|
85
|
+
try {
|
|
86
|
+
// The upstream transport exposes a callback property rather than an EventTarget API.
|
|
87
|
+
if (!Reflect.set(transport, "onclose", requestClose)) {
|
|
88
|
+
throw new Error("Unable to attach the MCP stdio close handler");
|
|
89
|
+
}
|
|
90
|
+
input.once("end", requestClose);
|
|
91
|
+
input.once("close", requestClose);
|
|
92
|
+
input.once("error", requestFailure);
|
|
93
|
+
output.once("error", requestFailure);
|
|
94
|
+
await protocol.connect(transport);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
let cleanupFailure: Error | undefined;
|
|
97
|
+
try {
|
|
98
|
+
await close();
|
|
99
|
+
} catch (closeError) {
|
|
100
|
+
cleanupFailure =
|
|
101
|
+
closeError instanceof Error
|
|
102
|
+
? closeError
|
|
103
|
+
: new Error("MCP stdio startup cleanup failed", { cause: closeError });
|
|
104
|
+
}
|
|
105
|
+
if (cleanupFailure) {
|
|
106
|
+
throw new AggregateError([error, cleanupFailure], "MCP stdio startup failed", {
|
|
107
|
+
cause: error,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { cwd, closed: lifecycle.promise, close };
|
|
114
|
+
}
|