@folterung/project-memory 0.1.19 → 0.1.21

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 (98) hide show
  1. package/README.md +13 -8
  2. package/package.json +4 -2
  3. package/packages/cli/coverage/lcov-report/chunking/chunker.ts.html +81 -81
  4. package/packages/cli/coverage/lcov-report/chunking/hash.ts.html +12 -12
  5. package/packages/cli/coverage/lcov-report/chunking/index.html +1 -1
  6. package/packages/cli/coverage/lcov-report/chunking/types.ts.html +23 -23
  7. package/packages/cli/coverage/lcov-report/config/index.html +1 -1
  8. package/packages/cli/coverage/lcov-report/config/load.ts.html +1 -1
  9. package/packages/cli/coverage/lcov-report/config/types.ts.html +1 -1
  10. package/packages/cli/coverage/lcov-report/embedding/index.html +1 -1
  11. package/packages/cli/coverage/lcov-report/embedding/stub.ts.html +1 -1
  12. package/packages/cli/coverage/lcov-report/index.html +18 -18
  13. package/packages/cli/coverage/lcov-report/qdrant/index.html +1 -1
  14. package/packages/cli/coverage/lcov-report/qdrant/upsert.ts.html +1 -1
  15. package/packages/cli/coverage/lcov-report/scope/allowlist.ts.html +51 -51
  16. package/packages/cli/coverage/lcov-report/scope/ignore.ts.html +1 -1
  17. package/packages/cli/coverage/lcov-report/scope/index.html +19 -19
  18. package/packages/cli/coverage/lcov.info +221 -213
  19. package/packages/cli/coverage/tmp/{coverage-7460-1770137208481-0.json → coverage-24604-1770174821315-0.json} +1 -1
  20. package/packages/cli/coverage/tmp/coverage-24605-1770174821362-0.json +1 -0
  21. package/packages/cli/coverage/tmp/{coverage-7462-1770137208524-0.json → coverage-24606-1770174821361-0.json} +1 -1
  22. package/packages/cli/coverage/tmp/{coverage-7463-1770137208524-0.json → coverage-24607-1770174821359-0.json} +1 -1
  23. package/packages/cli/coverage/tmp/{coverage-7464-1770137208531-0.json → coverage-24608-1770174821367-0.json} +1 -1
  24. package/packages/cli/coverage/tmp/{coverage-7465-1770137208526-0.json → coverage-24609-1770174821359-0.json} +1 -1
  25. package/packages/cli/coverage/tmp/{coverage-7466-1770137208528-0.json → coverage-24610-1770174821360-0.json} +1 -1
  26. package/packages/cli/coverage/tmp/{coverage-7467-1770137208579-0.json → coverage-24611-1770174821416-0.json} +1 -1
  27. package/packages/cli/coverage/tmp/coverage-24612-1770174821392-0.json +1 -0
  28. package/packages/cli/coverage/tmp/{coverage-7469-1770137208543-0.json → coverage-24613-1770174821380-0.json} +1 -1
  29. package/packages/cli/dist/chunking/chunker.test.js +19 -0
  30. package/packages/cli/dist/chunking/chunker.test.js.map +1 -1
  31. package/packages/cli/dist/cli/index.js +1 -1
  32. package/packages/cli/dist/cli/index.js.map +1 -1
  33. package/packages/cli/dist/phase1/pipeline.js +17 -7
  34. package/packages/cli/dist/phase1/pipeline.js.map +1 -1
  35. package/packages/cli/dist/phase2/deep-index.js +18 -6
  36. package/packages/cli/dist/phase2/deep-index.js.map +1 -1
  37. package/packages/cli/dist/scope/allowlist.test.js +14 -1
  38. package/packages/cli/dist/scope/allowlist.test.js.map +1 -1
  39. package/packages/cli/src/chunking/chunker.test.ts +21 -0
  40. package/packages/cli/src/cli/index.ts +1 -1
  41. package/packages/cli/src/phase1/pipeline.ts +15 -8
  42. package/packages/cli/src/phase2/deep-index.ts +15 -6
  43. package/packages/cli/src/scope/allowlist.test.ts +16 -1
  44. package/packages/mcp-server/dist/index.js +174 -16
  45. package/packages/mcp-server/dist/index.js.map +1 -1
  46. package/packages/mcp-server/dist/system-instructions.md +2 -0
  47. package/packages/mcp-server/src/index.ts +204 -16
  48. package/packages/mcp-server/system-instructions.md +2 -0
  49. package/packages/server/coverage/lcov-report/api/index.html +146 -0
  50. package/packages/server/coverage/lcov-report/api/points.ts.html +361 -0
  51. package/packages/server/coverage/lcov-report/api/search.ts.html +436 -0
  52. package/packages/server/coverage/lcov-report/api/store.ts.html +487 -0
  53. package/packages/server/coverage/lcov-report/embedding/index.html +116 -0
  54. package/packages/server/coverage/lcov-report/embedding/stub.ts.html +184 -0
  55. package/packages/server/coverage/lcov-report/index.html +40 -10
  56. package/packages/server/coverage/lcov-report/qdrant/client.ts.html +517 -0
  57. package/packages/server/coverage/lcov-report/qdrant/index.html +116 -0
  58. package/packages/server/coverage/lcov-report/stub.ts.html +1 -1
  59. package/packages/server/coverage/lcov.info +674 -27
  60. package/packages/server/coverage/tmp/{coverage-7549-1770137209315-0.json → coverage-24692-1770174822211-0.json} +1 -1
  61. package/packages/server/coverage/tmp/coverage-24693-1770174822463-0.json +1 -0
  62. package/packages/server/coverage/tmp/coverage-24694-1770174822454-0.json +1 -0
  63. package/packages/server/coverage/tmp/coverage-24695-1770174822463-0.json +1 -0
  64. package/packages/server/coverage/tmp/{coverage-7550-1770137209349-0.json → coverage-24696-1770174822253-0.json} +1 -1
  65. package/packages/server/dist/api/points.d.ts +24 -0
  66. package/packages/server/dist/api/points.js +60 -0
  67. package/packages/server/dist/api/points.js.map +1 -0
  68. package/packages/server/dist/api/points.test.d.ts +1 -0
  69. package/packages/server/dist/api/points.test.js +105 -0
  70. package/packages/server/dist/api/points.test.js.map +1 -0
  71. package/packages/server/dist/api/search.d.ts +16 -0
  72. package/packages/server/dist/api/search.js +26 -8
  73. package/packages/server/dist/api/search.js.map +1 -1
  74. package/packages/server/dist/api/search.test.d.ts +1 -0
  75. package/packages/server/dist/api/search.test.js +102 -0
  76. package/packages/server/dist/api/search.test.js.map +1 -0
  77. package/packages/server/dist/api/store.d.ts +7 -0
  78. package/packages/server/dist/api/store.js +50 -7
  79. package/packages/server/dist/api/store.js.map +1 -1
  80. package/packages/server/dist/api/store.test.d.ts +1 -0
  81. package/packages/server/dist/api/store.test.js +85 -0
  82. package/packages/server/dist/api/store.test.js.map +1 -0
  83. package/packages/server/dist/index.js +2 -0
  84. package/packages/server/dist/index.js.map +1 -1
  85. package/packages/server/dist/qdrant/client.d.ts +4 -0
  86. package/packages/server/dist/qdrant/client.js +12 -0
  87. package/packages/server/dist/qdrant/client.js.map +1 -1
  88. package/packages/server/package.json +1 -1
  89. package/packages/server/src/api/points.test.ts +113 -0
  90. package/packages/server/src/api/points.ts +92 -0
  91. package/packages/server/src/api/search.test.ts +110 -0
  92. package/packages/server/src/api/search.ts +59 -13
  93. package/packages/server/src/api/store.test.ts +91 -0
  94. package/packages/server/src/api/store.ts +60 -12
  95. package/packages/server/src/index.ts +2 -0
  96. package/packages/server/src/qdrant/client.ts +15 -0
  97. package/packages/cli/coverage/tmp/coverage-7461-1770137208528-0.json +0 -1
  98. package/packages/cli/coverage/tmp/coverage-7468-1770137208547-0.json +0 -1
@@ -0,0 +1,24 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ import type { QdrantClient } from "@qdrant/js-client-rest";
3
+ export interface PointsBatchBody {
4
+ ids: string[];
5
+ }
6
+ export interface PointItem {
7
+ id: string;
8
+ text: string;
9
+ path?: string;
10
+ startLine?: number;
11
+ endLine?: number;
12
+ symbol?: string;
13
+ kind?: string;
14
+ indexedAt?: string;
15
+ storedAt?: string;
16
+ source?: string;
17
+ supersededById?: string;
18
+ }
19
+ export declare function registerPointsRoutes(app: FastifyInstance, options: {
20
+ qdrantHost?: string;
21
+ qdrantPort?: number;
22
+ collection?: string;
23
+ qdrantClient?: QdrantClient;
24
+ }): void;
@@ -0,0 +1,60 @@
1
+ import { createQdrantClient } from "../qdrant/client.js";
2
+ import { retrievePointsById } from "../qdrant/client.js";
3
+ const BATCH_MAX_IDS = 20;
4
+ function payloadToItem(id, payload) {
5
+ return {
6
+ id,
7
+ text: payload.text ?? "",
8
+ path: payload.path,
9
+ startLine: payload.startLine,
10
+ endLine: payload.endLine,
11
+ symbol: payload.symbol,
12
+ kind: payload.kind,
13
+ indexedAt: payload.indexedAt,
14
+ storedAt: payload.storedAt,
15
+ source: payload.source,
16
+ supersededById: payload.supersededById,
17
+ };
18
+ }
19
+ export function registerPointsRoutes(app, options) {
20
+ const client = options.qdrantClient ??
21
+ createQdrantClient(options.qdrantHost ?? "127.0.0.1", options.qdrantPort ?? 6333);
22
+ const collection = options.collection ?? "project_memory";
23
+ app.post("/points/batch", {
24
+ schema: {
25
+ body: {
26
+ type: "object",
27
+ required: ["ids"],
28
+ properties: {
29
+ ids: {
30
+ type: "array",
31
+ items: { type: "string" },
32
+ },
33
+ },
34
+ },
35
+ },
36
+ }, async (request, reply) => {
37
+ const { ids } = request.body ?? {};
38
+ if (!Array.isArray(ids) || ids.length === 0) {
39
+ await reply.status(400).send({
40
+ statusCode: 400,
41
+ error: "Bad Request",
42
+ message: "ids must be a non-empty array (max " + BATCH_MAX_IDS + " items)",
43
+ });
44
+ return;
45
+ }
46
+ if (ids.length > BATCH_MAX_IDS) {
47
+ await reply.status(400).send({
48
+ statusCode: 400,
49
+ error: "Bad Request",
50
+ message: "ids must contain at most " + BATCH_MAX_IDS + " items",
51
+ });
52
+ return;
53
+ }
54
+ const uniqueIds = [...new Set(ids)];
55
+ const points = await retrievePointsById(client, collection, uniqueIds);
56
+ const items = points.map((p) => payloadToItem(p.id, p.payload));
57
+ await reply.send({ items });
58
+ });
59
+ }
60
+ //# sourceMappingURL=points.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"points.js","sourceRoot":"","sources":["../../src/api/points.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,MAAM,aAAa,GAAG,EAAE,CAAC;AAoBzB,SAAS,aAAa,CAAC,EAAU,EAAE,OAAqB;IACtD,OAAO;QACL,EAAE;QACF,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;QACxB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,SAAS,EAAE,OAAO,CAAC,SAA+B;QAClD,OAAO,EAAE,OAAO,CAAC,OAA6B;QAC9C,MAAM,EAAE,OAAO,CAAC,MAA4B;QAC5C,IAAI,EAAE,OAAO,CAAC,IAA0B;QACxC,SAAS,EAAE,OAAO,CAAC,SAA+B;QAClD,QAAQ,EAAE,OAAO,CAAC,QAA8B;QAChD,MAAM,EAAE,OAAO,CAAC,MAA4B;QAC5C,cAAc,EAAE,OAAO,CAAC,cAAoC;KAC7D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,GAAoB,EACpB,OAAuG;IAEvG,MAAM,MAAM,GACV,OAAO,CAAC,YAAY;QACpB,kBAAkB,CAAC,OAAO,CAAC,UAAU,IAAI,WAAW,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;IACpF,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,gBAAgB,CAAC;IAE1D,GAAG,CAAC,IAAI,CACN,eAAe,EACf;QACE,MAAM,EAAE;YACN,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,KAAK,CAAC;gBACjB,UAAU,EAAE;oBACV,GAAG,EAAE;wBACH,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC1B;iBACF;aACF;SACF;KACF,EACD,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC3B,UAAU,EAAE,GAAG;gBACf,KAAK,EAAE,aAAa;gBACpB,OAAO,EAAE,qCAAqC,GAAG,aAAa,GAAG,SAAS;aAC3E,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;YAC/B,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC3B,UAAU,EAAE,GAAG;gBACf,KAAK,EAAE,aAAa;gBACpB,OAAO,EAAE,2BAA2B,GAAG,aAAa,GAAG,QAAQ;aAChE,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAa,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QACvE,MAAM,KAAK,GAAgB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7E,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9B,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,105 @@
1
+ import { strict as assert } from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import Fastify from "fastify";
4
+ import { registerPointsRoutes } from "./points.js";
5
+ function createMockPointsClient() {
6
+ return {
7
+ retrieve: async (_collection, opts) => opts.ids.map((id) => ({
8
+ id,
9
+ payload: {
10
+ kind: "chunk",
11
+ text: `Full text for ${id}`,
12
+ path: "src/example.ts",
13
+ startLine: 1,
14
+ endLine: 10,
15
+ symbol: "example",
16
+ indexedAt: "2026-02-03T12:00:00.000Z",
17
+ source: "chunk",
18
+ },
19
+ })),
20
+ };
21
+ }
22
+ describe("points batch API", () => {
23
+ it("returns 400 when ids is empty", async () => {
24
+ const app = Fastify();
25
+ registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
26
+ const res = await app.inject({
27
+ method: "POST",
28
+ url: "/points/batch",
29
+ payload: { ids: [] },
30
+ });
31
+ assert.strictEqual(res.statusCode, 400);
32
+ assert.match(JSON.parse(res.body).message, /non-empty/);
33
+ });
34
+ it("returns 400 when ids is not an array", async () => {
35
+ const app = Fastify();
36
+ registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
37
+ const res = await app.inject({
38
+ method: "POST",
39
+ url: "/points/batch",
40
+ payload: {},
41
+ });
42
+ assert.strictEqual(res.statusCode, 400);
43
+ });
44
+ it("returns 400 when ids exceeds max", async () => {
45
+ const app = Fastify();
46
+ registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
47
+ const ids = Array.from({ length: 25 }, (_, i) => `id-${i}`);
48
+ const res = await app.inject({
49
+ method: "POST",
50
+ url: "/points/batch",
51
+ payload: { ids },
52
+ });
53
+ assert.strictEqual(res.statusCode, 400);
54
+ assert.match(JSON.parse(res.body).message, /at most 20/);
55
+ });
56
+ it("returns 200 with items array and full metadata", async () => {
57
+ const app = Fastify();
58
+ registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
59
+ const res = await app.inject({
60
+ method: "POST",
61
+ url: "/points/batch",
62
+ payload: { ids: ["point-1", "point-2"] },
63
+ });
64
+ assert.strictEqual(res.statusCode, 200);
65
+ const body = JSON.parse(res.body);
66
+ assert.ok(Array.isArray(body.items));
67
+ assert.strictEqual(body.items.length, 2);
68
+ const item = body.items[0];
69
+ assert.strictEqual(item.id, "point-1");
70
+ assert.strictEqual(item.text, "Full text for point-1");
71
+ assert.strictEqual(item.path, "src/example.ts");
72
+ assert.strictEqual(item.startLine, 1);
73
+ assert.strictEqual(item.endLine, 10);
74
+ assert.strictEqual(item.symbol, "example");
75
+ assert.strictEqual(item.kind, "chunk");
76
+ assert.strictEqual(item.indexedAt, "2026-02-03T12:00:00.000Z");
77
+ assert.strictEqual(item.source, "chunk");
78
+ });
79
+ it("deduplicates ids", async () => {
80
+ const app = Fastify();
81
+ registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
82
+ const res = await app.inject({
83
+ method: "POST",
84
+ url: "/points/batch",
85
+ payload: { ids: ["a", "a", "b"] },
86
+ });
87
+ assert.strictEqual(res.statusCode, 200);
88
+ const body = JSON.parse(res.body);
89
+ assert.strictEqual(body.items.length, 2);
90
+ });
91
+ it("returns empty items when client returns no points", async () => {
92
+ const emptyMock = { retrieve: async () => [] };
93
+ const app = Fastify();
94
+ registerPointsRoutes(app, { qdrantClient: emptyMock });
95
+ const res = await app.inject({
96
+ method: "POST",
97
+ url: "/points/batch",
98
+ payload: { ids: ["missing-id"] },
99
+ });
100
+ assert.strictEqual(res.statusCode, 200);
101
+ const body = JSON.parse(res.body);
102
+ assert.strictEqual(body.items.length, 0);
103
+ });
104
+ });
105
+ //# sourceMappingURL=points.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"points.test.js","sourceRoot":"","sources":["../../src/api/points.test.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,14 @@
1
1
  import type { FastifyInstance } from "fastify";
2
+ import type { QdrantClient } from "@qdrant/js-client-rest";
2
3
  export interface SearchBody {
3
4
  query: string;
4
5
  limit?: number;
6
+ refsOnly?: boolean;
7
+ intent?: "factual" | "planning" | "navigation";
8
+ kinds?: string[];
9
+ limitSystemMap?: number;
10
+ limitModuleSummary?: number;
11
+ limitChunks?: number;
5
12
  }
6
13
  export interface SearchResponse {
7
14
  systemMaps: Array<{
@@ -19,10 +26,19 @@ export interface SearchResponse {
19
26
  text: string;
20
27
  path?: string;
21
28
  score?: number;
29
+ startLine?: number;
30
+ endLine?: number;
31
+ symbol?: string;
32
+ kind?: string;
33
+ indexedAt?: string;
34
+ storedAt?: string;
35
+ source?: string;
36
+ supersededById?: string;
22
37
  }>;
23
38
  }
24
39
  export declare function registerSearchRoutes(app: FastifyInstance, options: {
25
40
  qdrantHost?: string;
26
41
  qdrantPort?: number;
27
42
  collection?: string;
43
+ qdrantClient?: QdrantClient;
28
44
  }): void;
@@ -2,7 +2,8 @@ import { createQdrantClient } from "../qdrant/client.js";
2
2
  import { embedText } from "../embedding/stub.js";
3
3
  import { searchPoints, searchPointsKinds } from "../qdrant/client.js";
4
4
  export function registerSearchRoutes(app, options) {
5
- const client = createQdrantClient(options.qdrantHost ?? "127.0.0.1", options.qdrantPort ?? 6333);
5
+ const client = options.qdrantClient ??
6
+ createQdrantClient(options.qdrantHost ?? "127.0.0.1", options.qdrantPort ?? 6333);
6
7
  const collection = options.collection ?? "project_memory";
7
8
  app.post("/search", {
8
9
  schema: {
@@ -12,33 +13,50 @@ export function registerSearchRoutes(app, options) {
12
13
  properties: {
13
14
  query: { type: "string" },
14
15
  limit: { type: "number" },
16
+ refsOnly: { type: "boolean" },
17
+ intent: { type: "string", enum: ["factual", "planning", "navigation"] },
18
+ kinds: { type: "array", items: { type: "string" } },
19
+ limitSystemMap: { type: "number" },
20
+ limitModuleSummary: { type: "number" },
21
+ limitChunks: { type: "number" },
15
22
  },
16
23
  },
17
24
  },
18
25
  }, async (request, reply) => {
19
- const { query, limit = 20 } = request.body;
26
+ const { query, limit = 20, refsOnly = false, kinds, limitSystemMap = 5, limitModuleSummary = 10, limitChunks, } = request.body;
20
27
  const vector = embedText(query ?? "");
28
+ const chunkKinds = kinds && kinds.length > 0 ? kinds : ["chunk", "entrypoint", "agent_note"];
29
+ const chunkLimit = limitChunks ?? limit;
21
30
  const [systemMaps, moduleSummaries, chunks] = await Promise.all([
22
- searchPoints(client, collection, vector, 5, "system_map"),
23
- searchPoints(client, collection, vector, 10, "module_summary"),
24
- searchPointsKinds(client, collection, vector, limit, ["chunk", "entrypoint", "agent_note"]),
31
+ searchPoints(client, collection, vector, limitSystemMap, "system_map"),
32
+ searchPoints(client, collection, vector, limitModuleSummary, "module_summary"),
33
+ searchPointsKinds(client, collection, vector, chunkLimit, chunkKinds),
25
34
  ]);
35
+ const textForChunk = (raw, refsOnlyMode) => refsOnlyMode && raw.length > 80 ? raw.slice(0, 80) + "…" : raw;
26
36
  const response = {
27
37
  systemMaps: systemMaps.map((r) => ({
28
38
  id: r.id,
29
- text: r.payload.text ?? "",
39
+ text: textForChunk(r.payload.text ?? "", refsOnly),
30
40
  path: r.payload.path,
31
41
  })),
32
42
  moduleSummaries: moduleSummaries.map((r) => ({
33
43
  id: r.id,
34
- text: r.payload.text ?? "",
44
+ text: textForChunk(r.payload.text ?? "", refsOnly),
35
45
  path: r.payload.path,
36
46
  })),
37
47
  chunks: chunks.map((r) => ({
38
48
  id: r.id,
39
- text: r.payload.text ?? "",
49
+ text: textForChunk(r.payload.text ?? "", refsOnly),
40
50
  path: r.payload.path,
41
51
  score: r.score,
52
+ startLine: r.payload.startLine,
53
+ endLine: r.payload.endLine,
54
+ symbol: r.payload.symbol,
55
+ kind: r.payload.kind,
56
+ indexedAt: r.payload.indexedAt,
57
+ storedAt: r.payload.storedAt,
58
+ source: r.payload.source,
59
+ supersededById: r.payload.supersededById,
42
60
  })),
43
61
  };
44
62
  await reply.send(response);
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/api/search.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAatE,MAAM,UAAU,oBAAoB,CAClC,GAAoB,EACpB,OAA0E;IAE1E,MAAM,MAAM,GAAG,kBAAkB,CAC/B,OAAO,CAAC,UAAU,IAAI,WAAW,EACjC,OAAO,CAAC,UAAU,IAAI,IAAI,CAC3B,CAAC;IACF,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,gBAAgB,CAAC;IAE1D,GAAG,CAAC,IAAI,CACN,SAAS,EACT;QACE,MAAM,EAAE;YACN,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,OAAO,CAAC;gBACnB,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACzB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iBAC1B;aACF;SACF;KACF,EACD,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;QAC3C,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAExC,MAAM,CAAC,UAAU,EAAE,eAAe,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC9D,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,CAAC;YACzD,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,gBAAgB,CAAC;YAC9D,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;SAC5F,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAmB;YAC/B,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACjC,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE;gBAC1B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI;aACrB,CAAC,CAAC;YACH,eAAe,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC3C,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE;gBAC1B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI;aACrB,CAAC,CAAC;YACH,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACzB,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE;gBAC1B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI;gBACpB,KAAK,EAAE,CAAC,CAAC,KAAK;aACf,CAAC,CAAC;SACJ,CAAC;QACF,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/api/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,102 @@
1
+ import { strict as assert } from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import Fastify from "fastify";
4
+ import { registerSearchRoutes } from "./search.js";
5
+ function createMockSearchClient() {
6
+ const chunkPayload = {
7
+ kind: "chunk",
8
+ text: "some code content here that could be long",
9
+ path: "src/foo.ts",
10
+ startLine: 42,
11
+ endLine: 80,
12
+ symbol: "handleSubmit",
13
+ indexedAt: "2026-02-03T12:00:00.000Z",
14
+ source: "chunk",
15
+ };
16
+ const searchResult = [
17
+ {
18
+ id: "chunk-id-1",
19
+ score: 0.9,
20
+ payload: chunkPayload,
21
+ },
22
+ ];
23
+ return {
24
+ getCollection: async () => ({ config: { params: { vectors: { default: {} } } } }),
25
+ search: async () => searchResult,
26
+ };
27
+ }
28
+ describe("search API", () => {
29
+ it("returns 200 with systemMaps, moduleSummaries, chunks", async () => {
30
+ const app = Fastify();
31
+ registerSearchRoutes(app, { qdrantClient: createMockSearchClient() });
32
+ const res = await app.inject({
33
+ method: "POST",
34
+ url: "/search",
35
+ payload: { query: "auth flow", limit: 20 },
36
+ });
37
+ assert.strictEqual(res.statusCode, 200);
38
+ const body = JSON.parse(res.body);
39
+ assert.ok(Array.isArray(body.systemMaps));
40
+ assert.ok(Array.isArray(body.moduleSummaries));
41
+ assert.ok(Array.isArray(body.chunks));
42
+ });
43
+ it("returns chunks with anchor and freshness fields when present in payload", async () => {
44
+ const app = Fastify();
45
+ registerSearchRoutes(app, { qdrantClient: createMockSearchClient() });
46
+ const res = await app.inject({
47
+ method: "POST",
48
+ url: "/search",
49
+ payload: { query: "test" },
50
+ });
51
+ assert.strictEqual(res.statusCode, 200);
52
+ const body = JSON.parse(res.body);
53
+ assert.ok(body.chunks.length >= 1);
54
+ const c = body.chunks[0];
55
+ assert.strictEqual(c.path, "src/foo.ts");
56
+ assert.strictEqual(c.startLine, 42);
57
+ assert.strictEqual(c.endLine, 80);
58
+ assert.strictEqual(c.symbol, "handleSubmit");
59
+ assert.strictEqual(c.kind, "chunk");
60
+ assert.strictEqual(c.indexedAt, "2026-02-03T12:00:00.000Z");
61
+ assert.strictEqual(c.source, "chunk");
62
+ });
63
+ it("refsOnly truncates chunk text to 80 chars", async () => {
64
+ const longText = "x".repeat(100);
65
+ const app = Fastify();
66
+ const mockClient = {
67
+ getCollection: async () => ({ config: { params: { vectors: { default: {} } } } }),
68
+ search: async () => [
69
+ {
70
+ id: "id1",
71
+ score: 0.9,
72
+ payload: { kind: "chunk", text: longText },
73
+ },
74
+ ],
75
+ };
76
+ registerSearchRoutes(app, { qdrantClient: mockClient });
77
+ const res = await app.inject({
78
+ method: "POST",
79
+ url: "/search",
80
+ payload: { query: "test", refsOnly: true },
81
+ });
82
+ assert.strictEqual(res.statusCode, 200);
83
+ const body = JSON.parse(res.body);
84
+ assert.ok(body.chunks[0].text.length <= 81);
85
+ assert.match(body.chunks[0].text, /…$/);
86
+ });
87
+ it("accepts optional kinds and intent", async () => {
88
+ const app = Fastify();
89
+ registerSearchRoutes(app, { qdrantClient: createMockSearchClient() });
90
+ const res = await app.inject({
91
+ method: "POST",
92
+ url: "/search",
93
+ payload: {
94
+ query: "session summary",
95
+ kinds: ["agent_note"],
96
+ intent: "planning",
97
+ },
98
+ });
99
+ assert.strictEqual(res.statusCode, 200);
100
+ });
101
+ });
102
+ //# sourceMappingURL=search.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.test.js","sourceRoot":"","sources":["../../src/api/search.test.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,18 @@
1
1
  import type { FastifyInstance } from "fastify";
2
+ import type { QdrantClient } from "@qdrant/js-client-rest";
2
3
  export interface StoreBody {
3
4
  content: string;
4
5
  title?: string;
5
6
  path?: string;
7
+ startLine?: number;
8
+ endLine?: number;
9
+ symbol?: string;
10
+ scope?: string;
11
+ supersedesId?: string;
6
12
  }
7
13
  export declare function registerStoreRoutes(app: FastifyInstance, options: {
8
14
  qdrantHost?: string;
9
15
  qdrantPort?: number;
10
16
  collection?: string;
17
+ qdrantClient?: QdrantClient;
11
18
  }): void;
@@ -9,11 +9,14 @@ function buildTextToEmbed(body) {
9
9
  parts.push(`File: ${body.path}`);
10
10
  if (body.title)
11
11
  parts.push(`Title: ${body.title}`);
12
+ if (body.symbol)
13
+ parts.push(`Symbol: ${body.symbol}`);
12
14
  parts.push(body.content);
13
15
  return parts.join("\n\n");
14
16
  }
15
17
  export function registerStoreRoutes(app, options) {
16
- const client = createQdrantClient(options.qdrantHost ?? "127.0.0.1", options.qdrantPort ?? 6333);
18
+ const client = options.qdrantClient ??
19
+ createQdrantClient(options.qdrantHost ?? "127.0.0.1", options.qdrantPort ?? 6333);
17
20
  const collection = options.collection ?? "project_memory";
18
21
  app.post("/store", {
19
22
  schema: {
@@ -24,15 +27,43 @@ export function registerStoreRoutes(app, options) {
24
27
  content: { type: "string" },
25
28
  title: { type: ["string", "null"] },
26
29
  path: { type: ["string", "null"] },
30
+ startLine: { type: ["number", "null"] },
31
+ endLine: { type: ["number", "null"] },
32
+ symbol: { type: ["string", "null"] },
33
+ scope: { type: ["string", "null"] },
34
+ supersedesId: { type: ["string", "null"] },
27
35
  },
28
36
  },
29
37
  },
30
38
  }, async (request, reply) => {
31
39
  const raw = request.body;
40
+ const startLine = raw.startLine != null ? Number(raw.startLine) : undefined;
41
+ const endLine = raw.endLine != null ? Number(raw.endLine) : undefined;
42
+ if (startLine != null && (!Number.isInteger(startLine) || startLine < 1)) {
43
+ await reply.status(400).send({
44
+ statusCode: 400,
45
+ error: "Bad Request",
46
+ message: "startLine must be a positive integer when provided",
47
+ });
48
+ return;
49
+ }
50
+ if (endLine != null && (!Number.isInteger(endLine) || endLine < 1)) {
51
+ await reply.status(400).send({
52
+ statusCode: 400,
53
+ error: "Bad Request",
54
+ message: "endLine must be a positive integer when provided",
55
+ });
56
+ return;
57
+ }
32
58
  const body = {
33
59
  content: raw.content ?? "",
34
60
  title: raw.title ?? undefined,
35
61
  path: raw.path ?? undefined,
62
+ startLine,
63
+ endLine,
64
+ symbol: raw.symbol ?? undefined,
65
+ scope: raw.scope ?? undefined,
66
+ supersedesId: raw.supersedesId ?? undefined,
36
67
  };
37
68
  const content = body.content.trim();
38
69
  if (!content) {
@@ -46,17 +77,29 @@ export function registerStoreRoutes(app, options) {
46
77
  const textToEmbed = buildTextToEmbed({ ...body, content });
47
78
  const vector = embedText(textToEmbed);
48
79
  const id = randomUUID();
80
+ const storedAt = new Date().toISOString();
81
+ const source = body.title?.trim().toLowerCase().startsWith("session summary")
82
+ ? "session-summary"
83
+ : "store";
84
+ const payload = {
85
+ kind: KIND_AGENT_NOTE,
86
+ path: body.path,
87
+ title: body.title,
88
+ text: content,
89
+ storedAt,
90
+ source,
91
+ ...(body.startLine != null && { startLine: body.startLine }),
92
+ ...(body.endLine != null && { endLine: body.endLine }),
93
+ ...(body.symbol != null && { symbol: body.symbol }),
94
+ ...(body.scope != null && { scope: body.scope }),
95
+ ...(body.supersedesId != null && { supersedesId: body.supersedesId }),
96
+ };
49
97
  await ensureCollection(client, collection);
50
98
  await upsertPoints(client, collection, [
51
99
  {
52
100
  id,
53
101
  vector,
54
- payload: {
55
- kind: KIND_AGENT_NOTE,
56
- path: body.path,
57
- title: body.title,
58
- text: content,
59
- },
102
+ payload,
60
103
  },
61
104
  ]);
62
105
  await reply.send({ id: `${KIND_AGENT_NOTE}:${id}`, message: "Stored." });
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/api/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAQjD,MAAM,eAAe,GAAG,YAAY,CAAC;AAErC,SAAS,gBAAgB,CAAC,IAAe;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,IAAI,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,IAAI,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACnD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,GAAoB,EACpB,OAA0E;IAE1E,MAAM,MAAM,GAAG,kBAAkB,CAC/B,OAAO,CAAC,UAAU,IAAI,WAAW,EACjC,OAAO,CAAC,UAAU,IAAI,IAAI,CAC3B,CAAC;IACF,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,gBAAgB,CAAC;IAE1D,GAAG,CAAC,IAAI,CACN,QAAQ,EACR;QACE,MAAM,EAAE;YACN,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,SAAS,CAAC;gBACrB,UAAU,EAAE;oBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;oBACnC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;iBACnC;aACF;SACF;KACF,EACD,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG;YACX,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE;YAC1B,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;YAC7B,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;SAC5B,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC3B,UAAU,EAAE,GAAG;gBACf,KAAK,EAAE,aAAa;gBACpB,OAAO,EAAE,2CAA2C;aACrD,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;QAExB,MAAM,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC3C,MAAM,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE;YACrC;gBACE,EAAE;gBACF,MAAM;gBACN,OAAO,EAAE;oBACP,IAAI,EAAE,eAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,IAAI,EAAE,OAAO;iBACd;aACF;SACF,CAAC,CAAC;QAEH,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,eAAe,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3E,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/api/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};