@treeseed/sdk 0.1.2 → 0.3.1

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 (237) hide show
  1. package/README.md +97 -506
  2. package/dist/{src/cli-tools.d.ts → cli-tools.d.ts} +1 -1
  3. package/dist/cli-tools.js +5 -3
  4. package/dist/{src/content-store.d.ts → content-store.d.ts} +3 -2
  5. package/dist/content-store.js +52 -20
  6. package/dist/{src/d1-store.d.ts → d1-store.d.ts} +62 -1
  7. package/dist/d1-store.js +625 -65
  8. package/dist/field-aliases.d.ts +11 -0
  9. package/dist/field-aliases.js +41 -0
  10. package/dist/graph/build.d.ts +19 -0
  11. package/dist/graph/build.js +949 -0
  12. package/dist/graph/dsl.d.ts +2 -0
  13. package/dist/graph/dsl.js +243 -0
  14. package/dist/graph/query.d.ts +47 -0
  15. package/dist/graph/query.js +447 -0
  16. package/dist/graph/ranking.d.ts +3 -0
  17. package/dist/graph/ranking.js +483 -0
  18. package/dist/graph/schema.d.ts +142 -0
  19. package/dist/graph/schema.js +133 -0
  20. package/dist/graph.d.ts +52 -0
  21. package/dist/graph.js +133 -0
  22. package/dist/index.d.ts +28 -0
  23. package/dist/index.js +91 -2
  24. package/dist/model-registry.d.ts +8 -0
  25. package/dist/model-registry.js +351 -25
  26. package/dist/operations/providers/default.d.ts +10 -0
  27. package/dist/operations/providers/default.js +514 -0
  28. package/dist/operations/runtime.d.ts +7 -0
  29. package/dist/operations/runtime.js +60 -0
  30. package/dist/operations/services/config-runtime.d.ts +269 -0
  31. package/dist/operations/services/config-runtime.js +1397 -0
  32. package/dist/operations/services/d1-migration.d.ts +6 -0
  33. package/dist/operations/services/d1-migration.js +89 -0
  34. package/dist/operations/services/deploy.d.ts +371 -0
  35. package/dist/operations/services/deploy.js +981 -0
  36. package/dist/operations/services/git-workflow.d.ts +49 -0
  37. package/dist/operations/services/git-workflow.js +218 -0
  38. package/dist/operations/services/github-automation.d.ts +156 -0
  39. package/dist/operations/services/github-automation.js +256 -0
  40. package/dist/operations/services/local-dev.d.ts +9 -0
  41. package/dist/operations/services/local-dev.js +106 -0
  42. package/dist/operations/services/mailpit-runtime.d.ts +4 -0
  43. package/dist/operations/services/mailpit-runtime.js +59 -0
  44. package/dist/operations/services/railway-deploy.d.ts +53 -0
  45. package/dist/operations/services/railway-deploy.js +123 -0
  46. package/dist/operations/services/runtime-paths.d.ts +19 -0
  47. package/dist/operations/services/runtime-paths.js +54 -0
  48. package/dist/operations/services/runtime-tools.d.ts +117 -0
  49. package/dist/operations/services/runtime-tools.js +358 -0
  50. package/dist/operations/services/save-deploy-preflight.d.ts +34 -0
  51. package/dist/operations/services/save-deploy-preflight.js +76 -0
  52. package/dist/operations/services/template-registry.d.ts +88 -0
  53. package/dist/operations/services/template-registry.js +407 -0
  54. package/dist/operations/services/watch-dev.d.ts +21 -0
  55. package/dist/operations/services/watch-dev.js +284 -0
  56. package/dist/operations/services/workspace-preflight.d.ts +40 -0
  57. package/dist/operations/services/workspace-preflight.js +165 -0
  58. package/dist/operations/services/workspace-save.d.ts +42 -0
  59. package/dist/operations/services/workspace-save.js +235 -0
  60. package/dist/operations/services/workspace-tools.d.ts +16 -0
  61. package/dist/operations/services/workspace-tools.js +270 -0
  62. package/dist/operations-registry.d.ts +5 -0
  63. package/dist/operations-registry.js +68 -0
  64. package/dist/operations-types.d.ts +71 -0
  65. package/dist/operations-types.js +17 -0
  66. package/dist/operations.d.ts +6 -0
  67. package/dist/operations.js +16 -0
  68. package/dist/platform/books-data.d.ts +1 -0
  69. package/dist/platform/books-data.js +1 -0
  70. package/dist/platform/contracts.d.ts +158 -0
  71. package/dist/platform/contracts.js +0 -0
  72. package/dist/platform/deploy/config.d.ts +4 -0
  73. package/dist/platform/deploy/config.js +222 -0
  74. package/dist/platform/deploy-config.d.ts +1 -0
  75. package/dist/platform/deploy-config.js +1 -0
  76. package/dist/platform/deploy-runtime.d.ts +18 -0
  77. package/dist/platform/deploy-runtime.js +78 -0
  78. package/dist/platform/env.yaml +394 -0
  79. package/dist/platform/environment.d.ts +130 -0
  80. package/dist/platform/environment.js +331 -0
  81. package/dist/platform/plugin.d.ts +2 -0
  82. package/dist/platform/plugin.js +4 -0
  83. package/dist/platform/plugins/constants.d.ts +22 -0
  84. package/dist/platform/plugins/constants.js +29 -0
  85. package/dist/platform/plugins/plugin.d.ts +51 -0
  86. package/dist/platform/plugins/plugin.js +6 -0
  87. package/dist/platform/plugins/runtime.d.ts +35 -0
  88. package/dist/platform/plugins/runtime.js +161 -0
  89. package/dist/platform/plugins.d.ts +6 -0
  90. package/dist/platform/plugins.js +38 -0
  91. package/dist/platform/site-config-schema.js +1 -0
  92. package/dist/platform/tenant/config.d.ts +9 -0
  93. package/dist/platform/tenant/config.js +154 -0
  94. package/dist/platform/tenant/runtime-config.d.ts +4 -0
  95. package/dist/platform/tenant/runtime-config.js +20 -0
  96. package/dist/platform/tenant-config.d.ts +1 -0
  97. package/dist/platform/tenant-config.js +1 -0
  98. package/dist/platform/utils/books-data.d.ts +29 -0
  99. package/dist/platform/utils/books-data.js +82 -0
  100. package/dist/platform/utils/site-config-schema.js +321 -0
  101. package/dist/remote.d.ts +175 -0
  102. package/dist/remote.js +202 -0
  103. package/dist/runtime.js +35 -22
  104. package/dist/scripts/aggregate-book.js +121 -0
  105. package/dist/scripts/build-dist.js +54 -13
  106. package/dist/scripts/build-tenant-worker.js +36 -0
  107. package/dist/scripts/cleanup-markdown.js +373 -0
  108. package/dist/scripts/cli-test-fixtures.js +48 -0
  109. package/dist/scripts/config-treeseed.js +95 -0
  110. package/dist/scripts/ensure-mailpit.js +29 -0
  111. package/dist/scripts/local-dev.js +129 -0
  112. package/dist/scripts/logs-mailpit.js +2 -0
  113. package/dist/scripts/patch-starlight-content-path.js +172 -0
  114. package/dist/scripts/release-verify.js +34 -6
  115. package/dist/scripts/run-fixture-astro-command.js +18 -0
  116. package/dist/scripts/scaffold-site.js +65 -0
  117. package/dist/scripts/stop-mailpit.js +5 -0
  118. package/dist/scripts/sync-dev-vars.js +6 -0
  119. package/dist/scripts/sync-template.js +20 -0
  120. package/dist/scripts/template-catalog.test.js +100 -0
  121. package/dist/scripts/template-command.js +31 -0
  122. package/dist/scripts/tenant-astro-command.js +3 -0
  123. package/dist/scripts/tenant-build.js +16 -0
  124. package/dist/scripts/tenant-check.js +7 -0
  125. package/dist/scripts/tenant-d1-migrate-local.js +11 -0
  126. package/dist/scripts/tenant-deploy.js +180 -0
  127. package/dist/scripts/tenant-destroy.js +104 -0
  128. package/dist/scripts/tenant-dev.js +171 -0
  129. package/dist/scripts/tenant-lint.js +4 -0
  130. package/dist/scripts/tenant-test.js +4 -0
  131. package/dist/scripts/test-cloudflare-local.js +212 -0
  132. package/dist/scripts/test-scaffold.js +314 -0
  133. package/dist/scripts/test-smoke.js +71 -13
  134. package/dist/scripts/treeseed-assert-release-tag-version.js +21 -0
  135. package/dist/scripts/treeseed-build-dist.js +134 -0
  136. package/dist/scripts/treeseed-publish-package.js +19 -0
  137. package/dist/scripts/treeseed-release-verify.js +131 -0
  138. package/dist/scripts/treeseed-run-ts.js +45 -0
  139. package/dist/scripts/validate-templates.js +6 -0
  140. package/dist/scripts/verify-driver.js +29 -0
  141. package/dist/scripts/workflow-commands.test.js +39 -0
  142. package/dist/scripts/workspace-close.js +24 -0
  143. package/dist/scripts/workspace-command-e2e.js +718 -0
  144. package/dist/scripts/workspace-lint.js +9 -0
  145. package/dist/scripts/workspace-preflight.js +22 -0
  146. package/dist/scripts/workspace-publish-changed-packages.js +16 -0
  147. package/dist/scripts/workspace-release-verify.js +81 -0
  148. package/dist/scripts/workspace-release.js +42 -0
  149. package/dist/scripts/workspace-save.js +124 -0
  150. package/dist/scripts/workspace-start-warning.js +3 -0
  151. package/dist/scripts/workspace-start.js +71 -0
  152. package/dist/scripts/workspace-test-unit.js +4 -0
  153. package/dist/scripts/workspace-test.js +11 -0
  154. package/dist/sdk-fields.d.ts +11 -0
  155. package/dist/sdk-fields.js +169 -0
  156. package/dist/sdk-filters.d.ts +4 -0
  157. package/dist/sdk-filters.js +12 -15
  158. package/dist/sdk-types.d.ts +796 -0
  159. package/dist/sdk-types.js +7 -1
  160. package/dist/sdk-version.d.ts +2 -0
  161. package/dist/sdk-version.js +42 -0
  162. package/dist/sdk.d.ts +215 -0
  163. package/dist/sdk.js +235 -11
  164. package/dist/stores/cursor-store.js +9 -3
  165. package/dist/stores/lease-store.js +8 -2
  166. package/dist/{src/stores → stores}/message-store.d.ts +1 -1
  167. package/dist/stores/message-store.js +27 -3
  168. package/dist/stores/operational-store.d.ts +24 -0
  169. package/dist/stores/operational-store.js +279 -0
  170. package/dist/stores/run-store.js +8 -1
  171. package/dist/stores/subscription-store.js +7 -5
  172. package/dist/template-catalog.d.ts +13 -0
  173. package/dist/template-catalog.js +141 -0
  174. package/dist/treeseed/services/compose.yml +7 -0
  175. package/dist/treeseed/template-catalog/catalog.fixture.json +55 -0
  176. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +2 -0
  177. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +3 -0
  178. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +32 -0
  179. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +40 -0
  180. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +1 -0
  181. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +11 -0
  182. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +11 -0
  183. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +1 -0
  184. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +3 -0
  185. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +1 -0
  186. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +19 -0
  187. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +26 -0
  188. package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +9 -0
  189. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +90 -0
  190. package/dist/utils/agents/contracts/messages.d.ts +88 -0
  191. package/dist/utils/agents/contracts/messages.js +138 -0
  192. package/dist/utils/agents/contracts/run.d.ts +20 -0
  193. package/dist/utils/agents/contracts/run.js +0 -0
  194. package/dist/utils/agents/runtime-types.d.ts +117 -0
  195. package/dist/utils/agents/runtime-types.js +4 -0
  196. package/dist/verification.d.ts +20 -0
  197. package/dist/verification.js +98 -0
  198. package/dist/workflow/operations.d.ts +396 -0
  199. package/dist/workflow/operations.js +841 -0
  200. package/dist/workflow-state.d.ts +56 -0
  201. package/dist/workflow-state.js +195 -0
  202. package/dist/workflow-support.d.ts +9 -0
  203. package/dist/workflow-support.js +176 -0
  204. package/dist/workflow.d.ts +111 -0
  205. package/dist/workflow.js +97 -0
  206. package/package.json +111 -5
  207. package/scripts/verify-driver.mjs +29 -0
  208. package/dist/scripts/.ts-run-1775630384291-crtqr3izsa.js +0 -22
  209. package/dist/scripts/.ts-run-1775630388025-vnjle0z75a.js +0 -129
  210. package/dist/scripts/assert-release-tag-version.d.ts +0 -1
  211. package/dist/scripts/build-dist.d.ts +0 -1
  212. package/dist/scripts/fixture-tools.d.ts +0 -5
  213. package/dist/scripts/package-tools.d.ts +0 -15
  214. package/dist/scripts/publish-package.d.ts +0 -1
  215. package/dist/scripts/release-verify.d.ts +0 -1
  216. package/dist/scripts/test-smoke.d.ts +0 -1
  217. package/dist/src/index.d.ts +0 -6
  218. package/dist/src/model-registry.d.ts +0 -4
  219. package/dist/src/sdk-filters.d.ts +0 -4
  220. package/dist/src/sdk-types.d.ts +0 -285
  221. package/dist/src/sdk.d.ts +0 -109
  222. package/dist/test/test-fixture.d.ts +0 -1
  223. package/dist/test/utils/envelopes.test.d.ts +0 -1
  224. package/dist/test/utils/sdk.test.d.ts +0 -1
  225. package/dist/vitest.config.d.ts +0 -2
  226. /package/dist/{src/frontmatter.d.ts → frontmatter.d.ts} +0 -0
  227. /package/dist/{src/git-runtime.d.ts → git-runtime.d.ts} +0 -0
  228. /package/dist/{src/runtime.d.ts → runtime.d.ts} +0 -0
  229. /package/dist/{src/stores → stores}/cursor-store.d.ts +0 -0
  230. /package/dist/{src/stores → stores}/envelopes.d.ts +0 -0
  231. /package/dist/{src/stores → stores}/helpers.d.ts +0 -0
  232. /package/dist/{src/stores → stores}/lease-store.d.ts +0 -0
  233. /package/dist/{src/stores → stores}/run-store.d.ts +0 -0
  234. /package/dist/{src/stores → stores}/subscription-store.d.ts +0 -0
  235. /package/dist/{src/types → types}/agents.d.ts +0 -0
  236. /package/dist/{src/types → types}/cloudflare.d.ts +0 -0
  237. /package/dist/{src/wrangler-d1.d.ts → wrangler-d1.d.ts} +0 -0
@@ -0,0 +1,447 @@
1
+ import path from "node:path";
2
+ import { parseGraphDsl } from "./dsl.js";
3
+ import { DEFAULT_GRAPH_RANKING_PROVIDER } from "./ranking.js";
4
+ import { normalizeText } from "./schema.js";
5
+ const RELATION_TO_EDGE_TYPE = {
6
+ related: "RELATES_TO",
7
+ depends_on: "DEPENDS_ON",
8
+ implements: "IMPLEMENTS",
9
+ references: "REFERENCES",
10
+ parent: "PARENT_SECTION",
11
+ child: "CHILD_SECTION",
12
+ supersedes: "SUPERSEDES"
13
+ };
14
+ function matchesNodeOptions(node, options) {
15
+ if (!node) {
16
+ return false;
17
+ }
18
+ if (options?.models?.length && (!node.sourceModel || !options.models.includes(node.sourceModel))) {
19
+ return false;
20
+ }
21
+ if (options?.nodeTypes?.length && !options.nodeTypes.includes(node.nodeType)) {
22
+ return false;
23
+ }
24
+ return true;
25
+ }
26
+ function dedupeResults(results) {
27
+ return [...new Map(results.map((result) => [result.node.id, result])).values()];
28
+ }
29
+ function tokenEstimate(text) {
30
+ return Math.max(1, Math.ceil(text.trim().length / 4));
31
+ }
32
+ function normalizeScopePath(value) {
33
+ return value.replace(/\\/gu, "/").replace(/\/+/gu, "/").replace(/\/$/u, "") || "/";
34
+ }
35
+ function stripExt(value) {
36
+ return value.replace(/\.(md|mdx)$/iu, "");
37
+ }
38
+ function nodeContentPath(node) {
39
+ const relativePath = typeof node.data?.relativePath === "string" ? node.data.relativePath.replace(/\.(md|mdx)$/iu, "") : typeof node.slug === "string" ? node.slug.replace(/#.*$/u, "") : "";
40
+ const modelPrefix = node.sourceModel ? `/${node.sourceModel}` : "";
41
+ if (!relativePath && modelPrefix) {
42
+ return modelPrefix;
43
+ }
44
+ return normalizeScopePath(`${modelPrefix}/${relativePath}`);
45
+ }
46
+ function nodeMatchesScope(node, scopePaths) {
47
+ if (!scopePaths?.length) {
48
+ return true;
49
+ }
50
+ const contentPath = nodeContentPath(node);
51
+ return scopePaths.some((scopePath) => contentPath === normalizeScopePath(scopePath) || contentPath.startsWith(`${normalizeScopePath(scopePath)}/`));
52
+ }
53
+ function nodeMetadataType(node) {
54
+ const frontmatter = node.data?.frontmatter;
55
+ const frontmatterType = typeof frontmatter?.type === "string" ? frontmatter.type : null;
56
+ return normalizeText(frontmatterType ?? node.entityType ?? node.sourceModel ?? node.nodeType);
57
+ }
58
+ function nodeMatchesWhere(node, filters) {
59
+ if (!filters?.length) {
60
+ return true;
61
+ }
62
+ return filters.every((filter) => {
63
+ const values = filter.field === "type" ? [nodeMetadataType(node)] : filter.field === "status" ? [normalizeText(node.status ?? "")] : filter.field === "audience" ? (node.audience ?? []).map(normalizeText) : filter.field === "tag" ? (node.tags ?? []).map(normalizeText) : filter.field === "domain" ? [normalizeText(node.domain ?? "")] : [];
64
+ const expected = Array.isArray(filter.value) ? filter.value.map(normalizeText) : [normalizeText(filter.value)];
65
+ return filter.op === "eq" ? expected.some((entry) => values.includes(entry)) : expected.every((entry) => values.includes(entry));
66
+ });
67
+ }
68
+ function excerptForView(node, view) {
69
+ const text = node.text ?? "";
70
+ switch (view) {
71
+ case "list":
72
+ return "";
73
+ case "map":
74
+ return `${node.title ?? node.id}`;
75
+ case "brief":
76
+ return text.slice(0, 480).trim();
77
+ case "full":
78
+ default:
79
+ return text;
80
+ }
81
+ }
82
+ class GraphQueryEngine {
83
+ constructor(state, onQuery, rankingProvider = DEFAULT_GRAPH_RANKING_PROVIDER) {
84
+ this.state = state;
85
+ this.onQuery = onQuery;
86
+ this.rankingProvider = rankingProvider;
87
+ for (const node of state.nodes) {
88
+ this.nodesById.set(node.id, node);
89
+ if (node.nodeType === "Section" && node.fileId) {
90
+ const current = this.fileSections.get(node.fileId) ?? [];
91
+ current.push(node);
92
+ this.fileSections.set(node.fileId, current);
93
+ }
94
+ }
95
+ for (const edge of state.edges) {
96
+ this.edgesById.set(edge.id, edge);
97
+ const outgoing = this.outgoing.get(edge.sourceId) ?? [];
98
+ outgoing.push(edge);
99
+ this.outgoing.set(edge.sourceId, outgoing);
100
+ const incoming = this.incoming.get(edge.targetId) ?? [];
101
+ incoming.push(edge);
102
+ this.incoming.set(edge.targetId, incoming);
103
+ }
104
+ for (const sections of this.fileSections.values()) {
105
+ sections.sort((left, right) => Number(left.data?.startOffset ?? 0) - Number(right.data?.startOffset ?? 0));
106
+ }
107
+ this.rankingIndex = this.rankingProvider.buildIndex({
108
+ nodes: state.nodes,
109
+ edges: state.edges
110
+ });
111
+ }
112
+ state;
113
+ onQuery;
114
+ nodesById = /* @__PURE__ */ new Map();
115
+ edgesById = /* @__PURE__ */ new Map();
116
+ outgoing = /* @__PURE__ */ new Map();
117
+ incoming = /* @__PURE__ */ new Map();
118
+ fileSections = /* @__PURE__ */ new Map();
119
+ rankingProvider;
120
+ rankingIndex;
121
+ filterSearchResults(results, options) {
122
+ return dedupeResults(
123
+ results.filter((result) => matchesNodeOptions(result.node, options)).slice(0, options?.limit ?? 20)
124
+ );
125
+ }
126
+ eligibleNodeIds(request) {
127
+ return statefulIds(
128
+ this.nodesById.values(),
129
+ (node) => matchesNodeOptions(node, request.options) && nodeMatchesScope(node, request.scopePaths) && nodeMatchesWhere(node, request.where)
130
+ );
131
+ }
132
+ searchFiles(query, options) {
133
+ this.onQuery?.("searchFiles", query);
134
+ return this.filterSearchResults(this.rankingIndex.search({ query, scope: "files", options }), options);
135
+ }
136
+ searchSections(query, options) {
137
+ this.onQuery?.("searchSections", query);
138
+ return this.filterSearchResults(this.rankingIndex.search({ query, scope: "sections", options }), options);
139
+ }
140
+ searchEntities(query, options) {
141
+ this.onQuery?.("searchEntities", query);
142
+ return this.filterSearchResults(this.rankingIndex.search({ query, scope: "entities", options }), options);
143
+ }
144
+ getNode(id) {
145
+ this.onQuery?.("getNode", id);
146
+ return this.nodesById.get(id) ?? null;
147
+ }
148
+ getNeighbors(id, options) {
149
+ this.onQuery?.("getNeighbors", id);
150
+ const edges = [
151
+ ...options?.direction !== "incoming" ? this.outgoing.get(id) ?? [] : [],
152
+ ...options?.direction !== "outgoing" ? this.incoming.get(id) ?? [] : []
153
+ ].filter((edge) => !options?.edgeTypes?.length || options.edgeTypes.includes(edge.type));
154
+ const nodes = dedupeResults(
155
+ edges.map((edge) => this.nodesById.get(edge.sourceId === id ? edge.targetId : edge.sourceId)).filter((node) => matchesNodeOptions(node, options)).map((node) => ({ node, score: 1, reason: "neighbor" }))
156
+ ).map((result) => result.node);
157
+ return {
158
+ node: this.nodesById.get(id) ?? null,
159
+ nodes: nodes.slice(0, options?.limit ?? nodes.length),
160
+ edges: edges.slice(0, options?.limit ?? edges.length)
161
+ };
162
+ }
163
+ followReferences(seedId, options) {
164
+ this.onQuery?.("followReferences", seedId);
165
+ const maxDepth = options?.depth ?? 2;
166
+ const visited = /* @__PURE__ */ new Set([seedId]);
167
+ const queue = [{ id: seedId, depth: 0 }];
168
+ const nodes = [];
169
+ const edges = [];
170
+ while (queue.length > 0) {
171
+ const current = queue.shift();
172
+ const node = this.nodesById.get(current.id);
173
+ if (node && matchesNodeOptions(node, options)) {
174
+ nodes.push(node);
175
+ }
176
+ if (current.depth >= maxDepth) {
177
+ continue;
178
+ }
179
+ for (const edge of this.outgoing.get(current.id) ?? []) {
180
+ if (options?.edgeTypes?.length && !options.edgeTypes.includes(edge.type)) {
181
+ continue;
182
+ }
183
+ edges.push(edge);
184
+ const target = edge.targetId;
185
+ if (!visited.has(target) && matchesNodeOptions(this.nodesById.get(target), options)) {
186
+ visited.add(target);
187
+ queue.push({ id: target, depth: current.depth + 1 });
188
+ }
189
+ }
190
+ }
191
+ return {
192
+ seedId,
193
+ nodes: dedupeResults(nodes.map((node) => ({ node, score: 1, reason: "traversal" }))).map((result) => result.node).slice(0, options?.limit ?? nodes.length),
194
+ edges: [...new Map(edges.map((edge) => [edge.id, edge])).values()].slice(0, options?.limit ?? edges.length)
195
+ };
196
+ }
197
+ getBacklinks(id, options) {
198
+ this.onQuery?.("getBacklinks", id);
199
+ const edges = (this.incoming.get(id) ?? []).filter((edge) => !options?.edgeTypes?.length || options.edgeTypes.includes(edge.type));
200
+ const nodes = edges.map((edge) => this.nodesById.get(edge.sourceId)).filter((node) => matchesNodeOptions(node, options));
201
+ return {
202
+ node: this.nodesById.get(id) ?? null,
203
+ nodes: nodes.slice(0, options?.limit ?? nodes.length),
204
+ edges: edges.slice(0, options?.limit ?? edges.length)
205
+ };
206
+ }
207
+ getRelated(id, options) {
208
+ this.onQuery?.("getRelated", id);
209
+ const result = this.queryGraph({
210
+ seedIds: [id],
211
+ options: {
212
+ ...options,
213
+ depth: options?.depth ?? 1,
214
+ limit: options?.limit ?? 20,
215
+ maxNodes: options?.maxNodes ?? options?.limit ?? 20
216
+ },
217
+ relations: ["related", "references", "depends_on"]
218
+ });
219
+ return result.nodes.filter((entry) => entry.node.id !== id);
220
+ }
221
+ getSubgraph(seedIds, options) {
222
+ this.onQuery?.("getSubgraph", seedIds.join(","));
223
+ const aggregatedNodes = /* @__PURE__ */ new Map();
224
+ const aggregatedEdges = /* @__PURE__ */ new Map();
225
+ for (const seedId of seedIds) {
226
+ const traversal = this.followReferences(seedId, options);
227
+ for (const node of traversal.nodes) aggregatedNodes.set(node.id, node);
228
+ for (const edge of traversal.edges) aggregatedEdges.set(edge.id, edge);
229
+ }
230
+ return {
231
+ seedId: seedIds.join(","),
232
+ nodes: [...aggregatedNodes.values()],
233
+ edges: [...aggregatedEdges.values()]
234
+ };
235
+ }
236
+ resolveSeeds(request) {
237
+ this.onQuery?.("resolveSeeds", request.query ?? request.seedIds?.join(",") ?? "");
238
+ const explicitSeeds = request.seeds ?? [];
239
+ const idSeeds = (request.seedIds ?? []).map((id, index) => ({ id: `seed-id:${index}`, kind: "id", value: id }));
240
+ const querySeeds = request.query ? [{ id: "seed-query:0", kind: "query", value: request.query, scope: request.scope }] : [];
241
+ const seeds = [...explicitSeeds, ...idSeeds, ...querySeeds];
242
+ const matches = [];
243
+ const resolvedNodeIds = /* @__PURE__ */ new Set();
244
+ for (const seed of seeds) {
245
+ if (seed.kind === "id") {
246
+ const node = this.getNode(seed.value);
247
+ if (node && nodeMatchesScope(node, request.scopePaths) && nodeMatchesWhere(node, request.where)) {
248
+ matches.push({ node, score: 100, reason: "seed-id" });
249
+ resolvedNodeIds.add(node.id);
250
+ }
251
+ continue;
252
+ }
253
+ if (seed.kind === "path") {
254
+ const node = this.resolveReference(seed.value) ?? [...this.nodesById.values()].find((entry) => nodeContentPath(entry) === normalizeScopePath(seed.value)) ?? null;
255
+ if (node && nodeMatchesScope(node, request.scopePaths) && nodeMatchesWhere(node, request.where)) {
256
+ matches.push({ node, score: 90, reason: "seed-path" });
257
+ resolvedNodeIds.add(node.id);
258
+ }
259
+ continue;
260
+ }
261
+ if (seed.kind === "tag") {
262
+ for (const node of this.nodesById.values()) {
263
+ if ((node.tags ?? []).map(normalizeText).includes(normalizeText(seed.value)) && nodeMatchesScope(node, request.scopePaths) && nodeMatchesWhere(node, request.where)) {
264
+ matches.push({ node, score: 85, reason: "seed-tag" });
265
+ resolvedNodeIds.add(node.id);
266
+ }
267
+ }
268
+ continue;
269
+ }
270
+ if (seed.kind === "type") {
271
+ for (const node of this.nodesById.values()) {
272
+ if (nodeMetadataType(node) === normalizeText(seed.value) && nodeMatchesScope(node, request.scopePaths) && nodeMatchesWhere(node, request.where)) {
273
+ matches.push({ node, score: 85, reason: "seed-type" });
274
+ resolvedNodeIds.add(node.id);
275
+ }
276
+ }
277
+ continue;
278
+ }
279
+ const scoped = seed.scope === "files" ? this.searchFiles(seed.value, request.options) : seed.scope === "entities" ? this.searchEntities(seed.value, request.options) : seed.scope === "sections" ? this.searchSections(seed.value, request.options) : this.filterSearchResults(this.rankingIndex.search({ query: seed.value, scope: "all", options: request.options, request }), request.options);
280
+ for (const match of scoped.filter((entry) => nodeMatchesScope(entry.node, request.scopePaths) && nodeMatchesWhere(entry.node, request.where)).slice(0, request.options?.limit ?? 10)) {
281
+ matches.push({ ...match, reason: `${match.reason}:seed-query` });
282
+ resolvedNodeIds.add(match.node.id);
283
+ }
284
+ }
285
+ return { seeds, matches: dedupeResults(matches), resolvedNodeIds: [...resolvedNodeIds] };
286
+ }
287
+ queryGraph(request) {
288
+ this.onQuery?.("queryGraph", request.query ?? request.seedIds?.join(",") ?? "");
289
+ const resolved = this.resolveSeeds(request);
290
+ const allowedEdgeTypes = request.relations?.length ? request.relations.map((relation) => RELATION_TO_EDGE_TYPE[relation]) : request.options?.edgeTypes;
291
+ const eligibleNodeIds = this.eligibleNodeIds(request);
292
+ for (const seedId of resolved.resolvedNodeIds) {
293
+ eligibleNodeIds.add(seedId);
294
+ }
295
+ const ranked = this.rankingIndex.rankQuery({
296
+ request,
297
+ seedIds: resolved.resolvedNodeIds.filter((id) => eligibleNodeIds.has(id)),
298
+ seedMatches: resolved.matches.filter((match) => eligibleNodeIds.has(match.node.id)),
299
+ allowedNodeIds: [...eligibleNodeIds],
300
+ allowedEdgeTypes
301
+ });
302
+ const nodes = ranked.nodes.map((entry) => ({
303
+ node: this.nodesById.get(entry.nodeId),
304
+ score: entry.score,
305
+ depth: entry.depth,
306
+ reasons: entry.reasons,
307
+ diagnostics: entry.diagnostics
308
+ })).filter((entry) => Boolean(entry.node) && nodeMatchesScope(entry.node, request.scopePaths) && nodeMatchesWhere(entry.node, request.where));
309
+ const includedNodeIds = new Set(nodes.map((entry) => entry.node.id));
310
+ const edges = ranked.edgeIds.map((id) => this.edgesById.get(id)).filter((edge) => Boolean(edge)).filter((edge) => includedNodeIds.has(edge.sourceId) || includedNodeIds.has(edge.targetId));
311
+ return {
312
+ seedIds: resolved.resolvedNodeIds,
313
+ nodes,
314
+ edges,
315
+ providerId: ranked.providerId,
316
+ diagnostics: ranked.diagnostics
317
+ };
318
+ }
319
+ buildContextPack(request) {
320
+ this.onQuery?.("buildContextPack", request.query ?? request.seedIds?.join(",") ?? "");
321
+ const graphResult = this.queryGraph(request);
322
+ const maxTokens = request.budget?.maxTokens ?? 1800;
323
+ const includeMode = request.budget?.includeMode ?? (request.view === "list" || request.view === "map" ? "mixed" : request.view === "full" ? "mixed" : "mixed");
324
+ const view = request.view ?? "brief";
325
+ const includedNodeIds = /* @__PURE__ */ new Set();
326
+ const nodes = [];
327
+ let totalTokenEstimate = 0;
328
+ for (const entry of graphResult.nodes) {
329
+ if (includeMode === "files" && entry.node.nodeType !== "File") continue;
330
+ if (includeMode === "sections" && entry.node.nodeType !== "Section") continue;
331
+ if (includeMode === "mixed" && !["File", "Section"].includes(entry.node.nodeType)) continue;
332
+ if (includeMode === "mixed" && entry.node.nodeType === "File" && entry.node.fileId && includedNodeIds.has(entry.node.fileId)) continue;
333
+ const text = excerptForView(entry.node, view);
334
+ if (!text.trim() && !["list", "map"].includes(view)) continue;
335
+ const estimate = tokenEstimate(text);
336
+ if (totalTokenEstimate + estimate > maxTokens && nodes.length > 0) continue;
337
+ totalTokenEstimate += estimate;
338
+ includedNodeIds.add(entry.node.id);
339
+ nodes.push({
340
+ node: entry.node,
341
+ score: entry.score,
342
+ depth: entry.depth,
343
+ text,
344
+ tokenEstimate: estimate,
345
+ reasons: entry.reasons,
346
+ provenance: {
347
+ seedIds: graphResult.seedIds,
348
+ viaEdgeTypes: graphResult.edges.filter((edge) => edge.sourceId === entry.node.id || edge.targetId === entry.node.id).map((edge) => edge.type)
349
+ }
350
+ });
351
+ }
352
+ return {
353
+ seedIds: graphResult.seedIds,
354
+ totalTokenEstimate,
355
+ includedNodeIds: [...includedNodeIds],
356
+ nodes,
357
+ edges: graphResult.edges
358
+ };
359
+ }
360
+ parseDsl(source) {
361
+ return parseGraphDsl(source);
362
+ }
363
+ explainReferenceChain(fromId, toId) {
364
+ this.onQuery?.("explainReferenceChain", `${fromId}:${toId}`);
365
+ const queue = [{ id: fromId, path: [fromId], edges: [] }];
366
+ const visited = /* @__PURE__ */ new Set([fromId]);
367
+ while (queue.length > 0) {
368
+ const current = queue.shift();
369
+ if (current.id === toId) {
370
+ return {
371
+ fromId,
372
+ toId,
373
+ nodes: current.path.map((id) => this.nodesById.get(id)).filter((node) => Boolean(node)),
374
+ edges: current.edges.map((id) => this.edgesById.get(id)).filter((edge) => Boolean(edge))
375
+ };
376
+ }
377
+ for (const edge of this.outgoing.get(current.id) ?? []) {
378
+ if (visited.has(edge.targetId)) continue;
379
+ visited.add(edge.targetId);
380
+ queue.push({
381
+ id: edge.targetId,
382
+ path: [...current.path, edge.targetId],
383
+ edges: [...current.edges, edge.id]
384
+ });
385
+ }
386
+ }
387
+ return null;
388
+ }
389
+ resolveReference(reference, options) {
390
+ this.onQuery?.("resolveReference", reference);
391
+ const trimmed = reference.trim();
392
+ const [pathPart, hashPart = ""] = trimmed.split("#");
393
+ const directNode = this.nodesById.get(trimmed);
394
+ if (directNode && matchesNodeOptions(directNode, { models: options?.models })) {
395
+ return directNode;
396
+ }
397
+ for (const node of this.nodesById.values()) {
398
+ if (options?.models?.length && (!node.sourceModel || !options.models.includes(node.sourceModel))) continue;
399
+ if (node.nodeType !== "File" && node.nodeType !== "Section" && node.nodeType !== "Entity" && !node.entityType) continue;
400
+ if (node.id === `entity:${pathPart}` || node.slug === pathPart || `${node.sourceModel}/${node.slug}` === pathPart) {
401
+ return node;
402
+ }
403
+ if (node.path && (stripExt(node.path) === stripExt(pathPart) || stripExt(path.relative(process.cwd(), node.path)) === stripExt(pathPart))) {
404
+ if (hashPart) {
405
+ const section = (this.fileSections.get(node.id) ?? []).find((entry) => entry.headingPath === hashPart || entry.slug?.endsWith(`#${hashPart}`));
406
+ if (section) return section;
407
+ }
408
+ return node;
409
+ }
410
+ }
411
+ if (options?.fromNodeId) {
412
+ const source = this.nodesById.get(options.fromNodeId);
413
+ if (source?.path) {
414
+ const absolute = path.resolve(path.dirname(source.path), pathPart);
415
+ for (const node of this.nodesById.values()) {
416
+ if (node.nodeType !== "File" || !node.path) continue;
417
+ if (stripExt(node.path) === stripExt(absolute)) {
418
+ if (hashPart) {
419
+ const section = (this.fileSections.get(node.id) ?? []).find((entry) => entry.headingPath === hashPart || entry.heading === hashPart);
420
+ if (section) return section;
421
+ }
422
+ return node;
423
+ }
424
+ }
425
+ }
426
+ }
427
+ return null;
428
+ }
429
+ serializeIndexes() {
430
+ return {
431
+ providerId: this.rankingProvider.id,
432
+ ranking: this.rankingIndex.serialize?.() ?? null
433
+ };
434
+ }
435
+ }
436
+ function statefulIds(nodes, predicate) {
437
+ const ids = /* @__PURE__ */ new Set();
438
+ for (const node of nodes) {
439
+ if (predicate(node)) {
440
+ ids.add(node.id);
441
+ }
442
+ }
443
+ return ids;
444
+ }
445
+ export {
446
+ GraphQueryEngine
447
+ };
@@ -0,0 +1,3 @@
1
+ import type { SdkGraphRankingProvider } from '../sdk-types.ts';
2
+ export declare function createDefaultGraphRankingProvider(): SdkGraphRankingProvider;
3
+ export declare const DEFAULT_GRAPH_RANKING_PROVIDER: SdkGraphRankingProvider;