sift-light 1.0.3-4 → 1.0.3-6

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/package.json +9 -6
  3. package/plugins/sift-light/.claude-plugin/plugin.json +1 -1
  4. package/plugins/sift-light/.codex-plugin/plugin.json +1 -1
  5. package/plugins/sift-light/.mcp.json +1 -1
  6. package/plugins/sift-light/concept-worker.mjs +84 -34
  7. package/plugins/sift-light/kimi.plugin.json +2 -2
  8. package/plugins/sift-light/omp-extension.mjs +3096 -2121
  9. package/plugins/sift-light/package.json +1 -1
  10. package/src/analysis-store.ts +23 -2
  11. package/src/analysis-types.ts +3 -0
  12. package/src/byspace-data-source.ts +104 -0
  13. package/src/concept-model.ts +35 -1
  14. package/src/concept-search.ts +116 -227
  15. package/src/concept-worker-client.ts +306 -0
  16. package/src/concept-worker-protocol.ts +86 -0
  17. package/src/concept-worker.mjs +84 -34
  18. package/src/concept-worker.ts +86 -32
  19. package/src/config-reader.ts +11 -2
  20. package/src/data-source-config.ts +98 -0
  21. package/src/data-source-http.ts +120 -0
  22. package/src/data-source-protocol.ts +113 -0
  23. package/src/data-sources.ts +113 -0
  24. package/src/errors.ts +6 -0
  25. package/src/evidence-service.ts +27 -4
  26. package/src/index.ts +1 -0
  27. package/src/language-capabilities.ts +16 -0
  28. package/src/mcp-semantic-judge.ts +8 -1
  29. package/src/mcp-server.mjs +2909 -1932
  30. package/src/mcp-server.ts +10 -5
  31. package/src/mcp.ts +3 -0
  32. package/src/omp-index.ts +1 -0
  33. package/src/package-smoke.mjs +81 -0
  34. package/src/relevance-ranking.ts +184 -0
  35. package/src/request-contract-catalog.ts +14 -1
  36. package/src/request-contract-error.ts +2 -0
  37. package/src/request-contract.ts +134 -9
  38. package/src/rg.ts +30 -7
  39. package/src/ripgrep-diagnostics.ts +21 -3
  40. package/src/scan-revisions.ts +1 -1
  41. package/src/service.ts +41 -3
  42. package/src/tool-schema.ts +19 -1
  43. package/src/types.ts +6 -0
  44. package/src/workspace-files.ts +3 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.3-6 — 2026-10-09
4
+
5
+ - Add bounded, read-only configured data-source adapters with explicit HTTPS/loopback validation, credential references and revision-aware source reads.
6
+ - Improve hybrid relevance ranking with request-scoped BM25 and semantic rank fusion, identifier-declaration candidates and distinct passage handling.
7
+ - Harden MCP/request-contract integration and add a packaged MCP smoke test so the published artifact is exercised through the real stdio transport.
8
+
9
+ ## 1.0.3-5 — 2026-10-07
10
+
11
+ - Update the MCP SDK to 1.31.0 and Transformers.js to 4.3.1 to remove the dependency vulnerabilities reported in [#111](https://github.com/lightsifter/sift-light/issues/111), including the old ONNX proxy/logging dependency chain. Refresh compatible SDK transitive dependencies in the lockfile.
12
+ - Recompute cached text embeddings after the inference runtime upgrade; the pinned offline model and search interfaces remain unchanged.
13
+
3
14
  ## 1.0.3-4 — 2026-10-05
4
15
 
5
16
  - Allow recognized stdin-only filters at any pipeline position, including `cmd | grep pattern | head` and `cmd | grep pattern | wc -l`. Deny file operands, recursive search, file-sourced patterns, input redirection, and unsafe dynamic arguments even when a filter receives piped input ([#109](https://github.com/lightsifter/sift-light/issues/109)).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sift-light",
3
- "version": "1.0.3-4",
3
+ "version": "1.0.3-6",
4
4
  "description": "Context-efficient local search for files, documents, notes and logs across Pi, OMP and MCP clients",
5
5
  "keywords": [
6
6
  "ai-agent",
@@ -38,6 +38,7 @@
38
38
  "src/syntax-worker.mjs",
39
39
  "src/mcp-server.mjs",
40
40
  "src/syntax-worker.toml",
41
+ "src/package-smoke.mjs",
41
42
  "README.md",
42
43
  "README.zh-CN.md",
43
44
  "CONTRIBUTING.md",
@@ -62,8 +63,9 @@
62
63
  "format:check": "oxfmt --check .",
63
64
  "lint": "oxlint --type-aware --deny-warnings --report-unused-disable-directives src scripts",
64
65
  "typecheck": "tsc --noEmit",
65
- "test": "bun test ./doc/testing/test",
66
- "test:node": "bun run doc/testing/scripts/node-smoke.ts",
66
+ "test:repo": "bun test ./doc/testing/test",
67
+ "test": "node src/package-smoke.mjs",
68
+ "test:node:repo": "bun run doc/testing/scripts/node-smoke.ts",
67
69
  "benchmark": "bun run doc/testing/scripts/benchmark.ts",
68
70
  "check": "bun run format:check && bun run lint && bun run typecheck && bun run build",
69
71
  "pack:check": "bun pm pack --dry-run && bun run scripts/check-npm-publish.ts",
@@ -71,6 +73,7 @@
71
73
  "build:concept-worker": "bun run scripts/build-concept-worker.ts",
72
74
  "check:concept-worker": "bun run doc/testing/scripts/check-concept-worker.ts",
73
75
  "test:concept": "bun run doc/testing/scripts/test-concept.ts",
76
+ "evaluate:relevance": "bun run doc/testing/scripts/relevance-eval.ts",
74
77
  "evaluate:investigations": "bun run doc/testing/scripts/investigation-eval.ts",
75
78
  "build:search-plugin": "bun run scripts/build-search-plugin.ts",
76
79
  "check:search-plugin": "bun run doc/testing/scripts/check-search-plugin.ts",
@@ -79,13 +82,13 @@
79
82
  "format:local:check": "bun run doc/testing/scripts/format-local.ts --check",
80
83
  "lint:local": "oxlint --no-ignore --type-aware --tsconfig doc/testing/tsconfig.json --deny-warnings --report-unused-disable-directives src scripts doc/testing/test doc/testing/scripts",
81
84
  "typecheck:local": "tsc --noEmit --project doc/testing/tsconfig.json",
82
- "check:local": "bun run format:check && bun run format:local:check && bun run check:search-plugin && bun run check:concept-worker && bun run check:worker && bun run check:mcp && bun run lint:local && bun run typecheck:local && bun run test && bun run test:node && bun run benchmark"
85
+ "check:local": "bun run format:check && bun run format:local:check && bun run check:search-plugin && bun run check:concept-worker && bun run check:worker && bun run check:mcp && bun run lint:local && bun run typecheck:local && bun run test:repo && bun run test:node:repo && bun run benchmark"
83
86
  },
84
87
  "dependencies": {
85
88
  "@ast-grep/lang-go": "0.0.6",
86
89
  "@ast-grep/napi": "0.45.2",
87
- "@huggingface/transformers": "3.8.1",
88
- "@modelcontextprotocol/sdk": "1.30.0",
90
+ "@huggingface/transformers": "4.3.1",
91
+ "@modelcontextprotocol/sdk": "1.31.0",
89
92
  "@vscode/ripgrep": "1.18.0",
90
93
  "typebox": "1.3.19",
91
94
  "web-tree-sitter": "0.25.10",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sift-light",
3
- "version": "1.0.3-4",
3
+ "version": "1.0.3-6",
4
4
  "description": "Require sift-light for conventional local searches while keeping development tools available.",
5
5
  "author": {
6
6
  "name": "baoer"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sift-light",
3
- "version": "1.0.3-4",
3
+ "version": "1.0.3-6",
4
4
  "description": "Require sift-light for conventional local searches while keeping development tools available.",
5
5
  "author": {
6
6
  "name": "baoer"
@@ -5,7 +5,7 @@
5
5
  "args": [
6
6
  "--yes",
7
7
  "--package",
8
- "sift-light-runtime@npm:sift-light@1.0.3-4",
8
+ "sift-light-runtime@npm:sift-light@1.0.3-6",
9
9
  "sift-light-mcp",
10
10
  "--stdio"
11
11
  ],
@@ -30,7 +30,7 @@ var MAX_CONCEPT_CHARS = 1000;
30
30
  var CONCEPT_MODEL_TOKENS = 256;
31
31
  var CONCEPT_WINDOW_OVERLAP_TOKENS = 64;
32
32
  var CONCEPT_EMBEDDING_DIMENSIONS = 384;
33
- var CONCEPT_CACHE_VERSION = 2;
33
+ var CONCEPT_CACHE_VERSION = 3;
34
34
  var CONCEPT_CACHE_MAX_BYTES = 512 * 1024 * 1024;
35
35
  var CONCEPT_TIMEOUT_MS = 10 * 60000;
36
36
  var MAX_CONCEPT_TIMEOUT_MS = 60 * 60000;
@@ -462,8 +462,12 @@ async function installConceptModel() {
462
462
 
463
463
  // src/concept-worker.ts
464
464
  var CACHE_IO_CONCURRENCY = 64;
465
+ var activeRequestId;
466
+ var extractor;
467
+ var modelVerified = false;
468
+ var modelLoads = 0;
465
469
  function emitProgress(progress) {
466
- process.stdout.write(`${JSON.stringify({ type: "progress", ...progress })}
470
+ process.stdout.write(`${JSON.stringify({ type: "progress", id: activeRequestId, ...progress })}
467
471
  `);
468
472
  }
469
473
  async function readCachedEmbeddings(root, requested, onProgress) {
@@ -475,7 +479,7 @@ async function readCachedEmbeddings(root, requested, onProgress) {
475
479
  }
476
480
  return cached;
477
481
  }
478
- async function requestFromStdin() {
482
+ async function readSingleRequest() {
479
483
  const chunks = [];
480
484
  let bytes = 0;
481
485
  for await (const chunk of process.stdin) {
@@ -485,7 +489,9 @@ async function requestFromStdin() {
485
489
  if (bytes > MAX_CONCEPT_WORKER_INPUT_BYTES)
486
490
  throw new Error("Concept worker input exceeds its 64 MiB source protocol budget");
487
491
  }
488
- const request = JSON.parse(Buffer.concat(chunks).toString("utf8"));
492
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
493
+ }
494
+ function decodeRequest(request) {
489
495
  if (!isRecordValue(request) || typeof request.query !== "string" || request.query.length === 0 || request.query.length > 256 || !request.query.isWellFormed() || /[\r\n\0]/u.test(request.query) || !Array.isArray(request.encodedPassages) || request.encodedPassages.some((item) => typeof item !== "string" || item.length === 0 || item.length % 4 !== 0 || item.length > Math.ceil((MAX_CONCEPT_CHARS + 256) * 4 / 3 * 4) + 4 || !/^[A-Za-z0-9+/]+={0,2}$/u.test(item)))
490
496
  throw new Error("Invalid concept worker input");
491
497
  const encodedPassages = request.encodedPassages.filter((item) => typeof item === "string");
@@ -497,12 +503,16 @@ async function requestFromStdin() {
497
503
  throw new Error("Invalid decoded concept worker passage");
498
504
  return { query: request.query, passages };
499
505
  }
500
- async function search() {
501
- const request = await requestFromStdin();
506
+ async function search(raw) {
507
+ const request = decodeRequest(raw);
502
508
  const directory = conceptModelDirectory();
503
509
  const cacheRoot = conceptCacheDirectory();
504
510
  const stagingRoot = process.env.SIFT_LIGHT_CONCEPT_CACHE_STAGING_DIR ?? cacheRoot;
505
- await verifyConceptModel(directory);
511
+ if (!modelVerified) {
512
+ await verifyConceptModel(directory);
513
+ modelVerified = true;
514
+ }
515
+ const modelReused = extractor !== undefined;
506
516
  const requested = [
507
517
  { key: conceptEmbeddingKey("query", request.query), role: "query", text: request.query },
508
518
  ...request.passages.map((text) => ({
@@ -526,28 +536,27 @@ async function search() {
526
536
  env.useFSCache = false;
527
537
  env.useBrowserCache = false;
528
538
  env.localModelPath = "/";
529
- emitProgress({ phase: "model-loading", ...progressContext });
530
- const extractor = await pipeline("feature-extraction", directory, {
531
- local_files_only: true,
532
- dtype: "q8",
533
- device: "cpu",
534
- session_options: { intraOpNumThreads: 4, interOpNumThreads: 1 }
535
- });
536
- try {
537
- created = await embedConceptInputs(extractor, missing, {
538
- onCompletedEmbedding: async (embedding, completed, total) => {
539
- try {
540
- await writeConceptEmbedding(cacheRoot, embedding, stagingRoot);
541
- } catch {
542
- cacheWriteFailed = true;
543
- }
544
- emitProgress({ phase: "cache-write", completed, total, ...progressContext });
545
- },
546
- onBatch: (completed, total) => emitProgress({ phase: "embedding", completed, total, ...progressContext })
539
+ if (!extractor) {
540
+ emitProgress({ phase: "model-loading", ...progressContext });
541
+ extractor = await pipeline("feature-extraction", directory, {
542
+ local_files_only: true,
543
+ dtype: "q8",
544
+ device: "cpu",
545
+ session_options: { intraOpNumThreads: 4, interOpNumThreads: 1 }
547
546
  });
548
- } finally {
549
- await extractor.dispose();
547
+ modelLoads += 1;
550
548
  }
549
+ created = await embedConceptInputs(extractor, missing, {
550
+ onCompletedEmbedding: async (embedding, completed, total) => {
551
+ try {
552
+ await writeConceptEmbedding(cacheRoot, embedding, stagingRoot);
553
+ } catch {
554
+ cacheWriteFailed = true;
555
+ }
556
+ emitProgress({ phase: "cache-write", completed, total, ...progressContext });
557
+ },
558
+ onBatch: (completed, total) => emitProgress({ phase: "embedding", completed, total, ...progressContext })
559
+ });
551
560
  if (cacheWriteFailed)
552
561
  warnings.push("Concept embedding cache write failed; ranking completed but some work may repeat");
553
562
  }
@@ -575,6 +584,9 @@ async function search() {
575
584
  }
576
585
  process.stdout.write(JSON.stringify({
577
586
  type: "result",
587
+ id: activeRequestId,
588
+ modelLoads,
589
+ modelReused,
578
590
  scores,
579
591
  cacheHits: cached.filter(Boolean).length,
580
592
  cacheMisses: missing.length,
@@ -584,11 +596,49 @@ async function search() {
584
596
  warnings: [...new Set(warnings)],
585
597
  peakRssBytes: process.resourceUsage().maxRSS * 1024,
586
598
  modelBytes: CONCEPT_ASSETS.reduce((sum, asset) => sum + asset.bytes, 0)
587
- }));
599
+ }) + `
600
+ `);
601
+ }
602
+ async function serve() {
603
+ let buffer = Buffer.alloc(0);
604
+ for await (const chunk of process.stdin) {
605
+ buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
606
+ if (buffer.length > MAX_CONCEPT_WORKER_INPUT_BYTES)
607
+ throw new Error("Concept request frame exceeds 64 MiB");
608
+ let newline = buffer.indexOf(10);
609
+ while (newline >= 0) {
610
+ const line = buffer.subarray(0, newline);
611
+ buffer = buffer.subarray(newline + 1);
612
+ const raw = JSON.parse(line.toString("utf8"));
613
+ if (!isRecordValue(raw) || typeof raw.id !== "string" || !/^[a-f0-9-]{36}$/u.test(raw.id))
614
+ throw new Error("Invalid concept request identity");
615
+ activeRequestId = raw.id;
616
+ try {
617
+ await search(raw);
618
+ } catch (error) {
619
+ process.stdout.write(JSON.stringify({
620
+ type: "error",
621
+ id: activeRequestId,
622
+ message: error instanceof Error ? error.message.slice(0, 512) : "Concept inference failed"
623
+ }) + `
624
+ `);
625
+ return;
626
+ }
627
+ newline = buffer.indexOf(10);
628
+ }
629
+ }
630
+ if (buffer.length)
631
+ throw new Error("Incomplete concept request frame");
632
+ }
633
+ try {
634
+ if (process.argv.includes("--install-model"))
635
+ await installConceptModel();
636
+ else if (process.argv.includes("--infer"))
637
+ await search(await readSingleRequest());
638
+ else if (process.argv.includes("--serve"))
639
+ await serve();
640
+ else
641
+ throw new Error("Usage: sift-light-model --install-model");
642
+ } finally {
643
+ await extractor?.dispose();
588
644
  }
589
- if (process.argv.includes("--install-model"))
590
- await installConceptModel();
591
- else if (process.argv.includes("--infer"))
592
- await search();
593
- else
594
- throw new Error("Usage: sift-light-model --install-model");
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sift-light",
3
- "version": "1.0.3-4",
3
+ "version": "1.0.3-6",
4
4
  "description": "Require sift-light for conventional local searches while keeping development tools available.",
5
5
  "author": {
6
6
  "name": "baoer"
@@ -13,7 +13,7 @@
13
13
  "args": [
14
14
  "--yes",
15
15
  "--package",
16
- "sift-light-runtime@npm:sift-light@1.0.3-4",
16
+ "sift-light-runtime@npm:sift-light@1.0.3-6",
17
17
  "sift-light-mcp",
18
18
  "--stdio"
19
19
  ],