@work-graph/cli 0.2.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.
Files changed (194) hide show
  1. package/README.md +31 -0
  2. package/bin/work-graph.mjs +238 -0
  3. package/package.json +38 -0
  4. package/vendor/packages/design-tokens/generated/gripe-dark-default.css +67 -0
  5. package/vendor/packages/design-tokens/generated/marketplace-default.css +67 -0
  6. package/vendor/packages/design-tokens/generated/workgraph-dark.css +67 -0
  7. package/vendor/packages/workgraph-mcp/README.md +28 -0
  8. package/vendor/packages/workgraph-mcp/bin/workgraph-mcp.mjs +21 -0
  9. package/vendor/packages/workgraph-mcp/package.json +37 -0
  10. package/vendor/packages/workgraph-mcp/src/handlers.mjs +761 -0
  11. package/vendor/packages/workgraph-mcp/src/index.mjs +638 -0
  12. package/vendor/packages/workgraph-mcp/src/prompts.mjs +162 -0
  13. package/vendor/public/assets/workgraph-logo.svg +11 -0
  14. package/vendor/public/fonts/GraphikLCG/GraphikLCG-Medium.woff2 +0 -0
  15. package/vendor/public/fonts/GraphikLCG/GraphikLCG-Regular.woff2 +0 -0
  16. package/vendor/public/fonts/GraphikLCG/GraphikLCG-Semibold.woff2 +0 -0
  17. package/vendor/public/fonts/GraphikLCG/stylesheet.css +25 -0
  18. package/vendor/public/graph-canvas-lit-flow.css +154 -0
  19. package/vendor/public/graph-canvas-lit-flow.css.map +7 -0
  20. package/vendor/public/graph-canvas-lit-flow.js +8530 -0
  21. package/vendor/public/graph-canvas-lit-flow.js.map +7 -0
  22. package/vendor/src/agentBehaviorRulesAudit.mjs +168 -0
  23. package/vendor/src/agentBehaviorRulesBundle.mjs +144 -0
  24. package/vendor/src/agentRunApi.mjs +136 -0
  25. package/vendor/src/agentToolLoopGuard.mjs +88 -0
  26. package/vendor/src/agentWorkerClaudeProvider.mjs +288 -0
  27. package/vendor/src/agentWorkerCursorSdkProvider.mjs +156 -0
  28. package/vendor/src/agentWorkerLiveLoop.mjs +455 -0
  29. package/vendor/src/agentWorkerLocalCliProvider.mjs +217 -0
  30. package/vendor/src/agentWorkerLocalRunner.mjs +246 -0
  31. package/vendor/src/agentWorkerOpenAiProvider.mjs +459 -0
  32. package/vendor/src/analyticsPanelProjection.mjs +212 -0
  33. package/vendor/src/analyticsRecordStore.mjs +165 -0
  34. package/vendor/src/analyticsRecordWorkItems.mjs +104 -0
  35. package/vendor/src/architectureL1Canon.mjs +419 -0
  36. package/vendor/src/architectureLayout.mjs +229 -0
  37. package/vendor/src/architectureSnapshot.mjs +490 -0
  38. package/vendor/src/architectureViewsProjection.mjs +116 -0
  39. package/vendor/src/atomInspector.mjs +253 -0
  40. package/vendor/src/atomInspectorApi.mjs +130 -0
  41. package/vendor/src/auditGapMatrixRefresh.mjs +121 -0
  42. package/vendor/src/backlogSchemaLint.mjs +176 -0
  43. package/vendor/src/blockedOnebaseGoPreflightEval.mjs +100 -0
  44. package/vendor/src/bracketIrTraceSignal.mjs +93 -0
  45. package/vendor/src/bvcAtomParser.mjs +210 -0
  46. package/vendor/src/bvcDialectRegistry.mjs +86 -0
  47. package/vendor/src/bvcFileFormat.mjs +218 -0
  48. package/vendor/src/bvcFormatCli.mjs +55 -0
  49. package/vendor/src/bvcLintCli.mjs +48 -0
  50. package/vendor/src/bvcNewWritePolicy.mjs +70 -0
  51. package/vendor/src/charterPreflightPromoteGate.mjs +194 -0
  52. package/vendor/src/claimNoEligibleEval.mjs +205 -0
  53. package/vendor/src/closingAnalysisSuggest.mjs +59 -0
  54. package/vendor/src/codeGapAnalyzer.mjs +308 -0
  55. package/vendor/src/codeGapBacklogFeeder.mjs +82 -0
  56. package/vendor/src/codeGapDraftIntakeApi.mjs +307 -0
  57. package/vendor/src/codeGapOperatorProjection.mjs +60 -0
  58. package/vendor/src/codeSyntaxHighlight.mjs +123 -0
  59. package/vendor/src/codegenEvidence.mjs +187 -0
  60. package/vendor/src/compilerRoundTripCli.mjs +164 -0
  61. package/vendor/src/dagreGraphLayout.mjs +78 -0
  62. package/vendor/src/draftIntakePromotionRules.mjs +205 -0
  63. package/vendor/src/epicWorkScope.mjs +85 -0
  64. package/vendor/src/evalLiveLlmEnv.mjs +63 -0
  65. package/vendor/src/evidenceReadModel.mjs +167 -0
  66. package/vendor/src/gfsOverlayProjectPassport.mjs +235 -0
  67. package/vendor/src/globalStepPathToBvcReferences.mjs +196 -0
  68. package/vendor/src/goldenPath.mjs +69 -0
  69. package/vendor/src/graphCanvasLayout.mjs +464 -0
  70. package/vendor/src/graphCanvasLitFlow/client/graphCanvasMinimap.ts +261 -0
  71. package/vendor/src/graphCanvasLitFlow/client/graphCanvasSvgEdges.ts +259 -0
  72. package/vendor/src/graphCanvasLitFlow/client/graphCanvasTheme.css +152 -0
  73. package/vendor/src/graphCanvasLitFlow/client/graphCardNode.ts +328 -0
  74. package/vendor/src/graphCanvasLitFlow/client/mountGraphCanvasLitFlow.ts +322 -0
  75. package/vendor/src/graphCanvasLitFlow/graphCanvasEdgeLabels.mjs +58 -0
  76. package/vendor/src/graphCanvasLitFlow/graphCanvasEdgeRouter.mjs +142 -0
  77. package/vendor/src/graphCanvasLitFlow/graphCanvasLayoutProfile.mjs +32 -0
  78. package/vendor/src/graphCanvasLitFlow/graphCanvasNodeMetrics.mjs +45 -0
  79. package/vendor/src/graphCanvasLitFlow/graphCanvasProjection.mjs +115 -0
  80. package/vendor/src/graphCanvasLitFlow/graphCanvasProjectionToFlow.mjs +133 -0
  81. package/vendor/src/graphCanvasLitFlow/graphCanvasTraversal.mjs +77 -0
  82. package/vendor/src/graphCanvasLitFlow/layoutIntentRoadmapWorkStack.mjs +73 -0
  83. package/vendor/src/graphCanvasLitFlow/resolveGraphCanvasOverlaps.mjs +77 -0
  84. package/vendor/src/graphRagContextSlice.mjs +461 -0
  85. package/vendor/src/gvmVerifyWorkerGate.mjs +95 -0
  86. package/vendor/src/homeSnapshotApi.mjs +131 -0
  87. package/vendor/src/homeSnapshotProjection.mjs +275 -0
  88. package/vendor/src/inboxEventStream.mjs +140 -0
  89. package/vendor/src/intentComposerApi.mjs +245 -0
  90. package/vendor/src/intentGraphGbcSliceBoundary.mjs +258 -0
  91. package/vendor/src/intentGraphProjection.mjs +208 -0
  92. package/vendor/src/intentHierarchy.mjs +241 -0
  93. package/vendor/src/intentNodeLint.mjs +107 -0
  94. package/vendor/src/intentNodeRuntime.mjs +185 -0
  95. package/vendor/src/intentRoadmapCanvas.mjs +393 -0
  96. package/vendor/src/intentRoadmapEpicProjection.mjs +122 -0
  97. package/vendor/src/intentRoadmapMermaid.mjs +165 -0
  98. package/vendor/src/intentRoadmapProjection.mjs +85 -0
  99. package/vendor/src/intentTreeLint.mjs +114 -0
  100. package/vendor/src/intentTreeMigration.mjs +150 -0
  101. package/vendor/src/intentTreeWorkItems.mjs +227 -0
  102. package/vendor/src/kanbanBoardProjection.mjs +58 -0
  103. package/vendor/src/languageAdapterRegistry.mjs +180 -0
  104. package/vendor/src/languageAdapters/goAdapter.mjs +62 -0
  105. package/vendor/src/languageAdapters/jsTsAdapter.mjs +60 -0
  106. package/vendor/src/languageAdapters/jsonYamlAdapter.mjs +103 -0
  107. package/vendor/src/languageAdapters/onebaseOsAdapter.mjs +55 -0
  108. package/vendor/src/languageAdapters/plaintextAdapter.mjs +36 -0
  109. package/vendor/src/languageAdapters/shared.mjs +68 -0
  110. package/vendor/src/languageAdapters/stepAdapter.mjs +81 -0
  111. package/vendor/src/lintPlanWorkAlignment.mjs +136 -0
  112. package/vendor/src/loopHintRepeatToolEval.mjs +153 -0
  113. package/vendor/src/lowcodeScaffoldCli.mjs +386 -0
  114. package/vendor/src/markdownDocumentRender.mjs +208 -0
  115. package/vendor/src/memoryPanelProjection.mjs +116 -0
  116. package/vendor/src/memoryRecordWriter.mjs +243 -0
  117. package/vendor/src/memoryWorkerSlice.mjs +238 -0
  118. package/vendor/src/migrateStepToBvc.mjs +133 -0
  119. package/vendor/src/missionControlServerHandlers.mjs +195 -0
  120. package/vendor/src/missionControlUiClient.mjs +278 -0
  121. package/vendor/src/onebaseCliCapabilityProbe.mjs +107 -0
  122. package/vendor/src/onebaseCliRunner.mjs +145 -0
  123. package/vendor/src/onebaseGrossProfitStaticVerify.mjs +98 -0
  124. package/vendor/src/onebaseParityEvidenceSync.mjs +88 -0
  125. package/vendor/src/onebasePvrgGraphNodes.mjs +257 -0
  126. package/vendor/src/onebaseRestEvidenceAdapter.mjs +216 -0
  127. package/vendor/src/onebaseVectorDslCodegenReadiness.mjs +137 -0
  128. package/vendor/src/onebaseWorkItemTemplate.mjs +154 -0
  129. package/vendor/src/onebaseWorkerTools.mjs +586 -0
  130. package/vendor/src/operatorShellProjection.mjs +102 -0
  131. package/vendor/src/pipelineProseRender.mjs +180 -0
  132. package/vendor/src/pipelineStageLint.mjs +118 -0
  133. package/vendor/src/promptRulesEditorApi.mjs +174 -0
  134. package/vendor/src/promptRulesProjection.mjs +134 -0
  135. package/vendor/src/pvrg/bladeAdapter.mjs +40 -0
  136. package/vendor/src/pvrgTaskScope.mjs +152 -0
  137. package/vendor/src/releaseGateMatrix.mjs +188 -0
  138. package/vendor/src/schematicView.mjs +305 -0
  139. package/vendor/src/seedAnalyticsRecord.mjs +217 -0
  140. package/vendor/src/semanticSearchBm25.mjs +103 -0
  141. package/vendor/src/semanticSearchExcerpts.mjs +68 -0
  142. package/vendor/src/semanticSearchTfidfVector.mjs +86 -0
  143. package/vendor/src/semanticSearchWorkflow.mjs +366 -0
  144. package/vendor/src/stepAtomFormatter.mjs +413 -0
  145. package/vendor/src/stepGraphSlice.mjs +318 -0
  146. package/vendor/src/ui/atoms/badge.mjs +40 -0
  147. package/vendor/src/ui/atoms/badgeClient.mjs +32 -0
  148. package/vendor/src/ui/atoms/button.mjs +114 -0
  149. package/vendor/src/ui/atoms/buttonClient.mjs +49 -0
  150. package/vendor/src/ui/atoms/icon.mjs +23 -0
  151. package/vendor/src/ui/atoms/input.mjs +38 -0
  152. package/vendor/src/ui/atoms/modal.mjs +44 -0
  153. package/vendor/src/ui/atoms/select.mjs +98 -0
  154. package/vendor/src/ui/backlogShellButtons.mjs +238 -0
  155. package/vendor/src/ui/htmlEscape.mjs +11 -0
  156. package/vendor/src/ui/molecules/rating.mjs +48 -0
  157. package/vendor/src/ui/molecules/tabs.mjs +70 -0
  158. package/vendor/src/ui/organisms/modal.mjs +1 -0
  159. package/vendor/src/ui/pages/uiKitPage.mjs +147 -0
  160. package/vendor/src/ui/workItemStatusTone.mjs +36 -0
  161. package/vendor/src/unifiedLinkageProjection.mjs +264 -0
  162. package/vendor/src/verificationLoop.mjs +206 -0
  163. package/vendor/src/workGraphBacklogPersist.mjs +234 -0
  164. package/vendor/src/workGraphBacklogUiServer.mjs +9192 -0
  165. package/vendor/src/workGraphBoundedTargetFileRead.mjs +178 -0
  166. package/vendor/src/workGraphCycleSlice.mjs +184 -0
  167. package/vendor/src/workGraphDaemonTick.mjs +307 -0
  168. package/vendor/src/workGraphDaemonWatch.mjs +157 -0
  169. package/vendor/src/workGraphEngineRoot.mjs +136 -0
  170. package/vendor/src/workGraphInstallLayout.mjs +65 -0
  171. package/vendor/src/workGraphLlmUsefulnessEval.mjs +611 -0
  172. package/vendor/src/workGraphPhasePromoteReadyQueue.mjs +159 -0
  173. package/vendor/src/workGraphProjectHost.mjs +149 -0
  174. package/vendor/src/workGraphProjectInit.mjs +392 -0
  175. package/vendor/src/workGraphPromoteReadyApi.mjs +115 -0
  176. package/vendor/src/workGraphRecoveryPolicy.mjs +124 -0
  177. package/vendor/src/workGraphRunnerQueueProjection.mjs +187 -0
  178. package/vendor/src/workGraphRuntime.mjs +1008 -0
  179. package/vendor/src/workGraphToolSurfaceAudit.mjs +372 -0
  180. package/vendor/src/workGraphToolTransportRuntime.mjs +195 -0
  181. package/vendor/src/workGraphWorkerProvider.mjs +600 -0
  182. package/vendor/src/workItemBvcQuality.mjs +262 -0
  183. package/vendor/src/workItemCreateAnalysis.mjs +157 -0
  184. package/vendor/src/workItemDecisionPipeline.mjs +278 -0
  185. package/vendor/src/workItemEpicCascade.mjs +176 -0
  186. package/vendor/src/workItemExecutionGate.mjs +78 -0
  187. package/vendor/src/workItemHierarchy.mjs +226 -0
  188. package/vendor/src/workItemProseLint.mjs +133 -0
  189. package/vendor/src/workItemTextRusify.mjs +794 -0
  190. package/vendor/src/workItemTraceEnvelope.mjs +158 -0
  191. package/vendor/src/workItemUiReferences.mjs +272 -0
  192. package/vendor/src/workflowEpicGrouping.mjs +67 -0
  193. package/vendor/src/workflowTreeProjection.mjs +53 -0
  194. package/vendor/src/workspaceRegistry.mjs +150 -0
@@ -0,0 +1,366 @@
1
+ import { classifyWorkItemBlock } from './architectureSnapshot.mjs';
2
+ import {
3
+ buildBm25Index,
4
+ scoreBm25,
5
+ tokenizeForBm25,
6
+ } from './semanticSearchBm25.mjs';
7
+ import { enrichSemanticDocumentsWithExcerpts } from './semanticSearchExcerpts.mjs';
8
+ import { buildTfidfIndex, scoreTfidfCosine } from './semanticSearchTfidfVector.mjs';
9
+
10
+ export const SEMANTIC_SEARCH_RESULT_SCHEMA = 'semantic-search.result.v1';
11
+ export const SEMANTIC_SEARCH_MODE_LEXICAL_V1 = 'lexical-v1';
12
+ export const SEMANTIC_SEARCH_MODE_HYBRID_V1 = 'hybrid-lexical-bm25-v1';
13
+ export const SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1 = 'hybrid-lexical-bm25-tfidf-v1';
14
+
15
+ const DEFAULT_LIMIT = 12;
16
+ const DEFAULT_MAX_CHARS = 4000;
17
+
18
+ const compareText = (left, right) => String(left).localeCompare(String(right), 'en', { sensitivity: 'variant' });
19
+
20
+ function tokenizeQuery(query) {
21
+ return String(query ?? '')
22
+ .toLowerCase()
23
+ .split(/[^a-z0-9\u0400-\u04ff]+/u)
24
+ .map((token) => token.trim())
25
+ .filter((token) => token.length >= 2);
26
+ }
27
+
28
+ function fieldText(item, field) {
29
+ if (field === 'targetFiles') {
30
+ return (item.targetFiles ?? []).join(' ');
31
+ }
32
+
33
+ return String(item[field] ?? '');
34
+ }
35
+
36
+ function scoreDocument(tokens, parts) {
37
+ if (tokens.length === 0) {
38
+ return 0;
39
+ }
40
+
41
+ let score = 0;
42
+ for (const part of parts) {
43
+ const haystack = String(part.text ?? '').toLowerCase();
44
+ const weight = Number(part.weight ?? 1);
45
+ for (const token of tokens) {
46
+ if (haystack.includes(token)) {
47
+ score += weight;
48
+ }
49
+ }
50
+ }
51
+
52
+ return score;
53
+ }
54
+
55
+ function buildWorkItemDocument(item) {
56
+ const architectureBlockId = classifyWorkItemBlock(item);
57
+ const traceRefs = [`work:${item.id}`];
58
+
59
+ return {
60
+ id: `work:${item.id}`,
61
+ kind: 'work_item',
62
+ label: item.title || item.id,
63
+ summary: String(item.goal || item.vector || item.nextAction || item.title || item.id).trim(),
64
+ workId: item.id,
65
+ filePath: null,
66
+ architectureBlockId,
67
+ traceRefs,
68
+ parts: [
69
+ { text: item.id, weight: 4 },
70
+ { text: item.title, weight: 3 },
71
+ { text: item.basis, weight: 2 },
72
+ { text: item.vector, weight: 2 },
73
+ { text: item.goal, weight: 2 },
74
+ { text: (item.targetFiles ?? []).join(' '), weight: 2 },
75
+ { text: item.nextAction, weight: 1 },
76
+ { text: item.ownerRole, weight: 1 },
77
+ { text: item.department, weight: 1 },
78
+ ],
79
+ };
80
+ }
81
+
82
+ function buildFileArtifactDocuments(item) {
83
+ return (item.targetFiles ?? []).map((filePath) => ({
84
+ id: `file:${filePath}`,
85
+ kind: 'file_artifact',
86
+ label: filePath,
87
+ summary: `Файл из задачи ${item.id}`,
88
+ workId: item.id,
89
+ filePath,
90
+ architectureBlockId: classifyWorkItemBlock(item),
91
+ traceRefs: [`file:${filePath}`, `work:${item.id}`],
92
+ parts: [
93
+ { text: filePath, weight: 4 },
94
+ { text: item.id, weight: 2 },
95
+ { text: item.title, weight: 2 },
96
+ ],
97
+ }));
98
+ }
99
+
100
+ export function buildSemanticSearchDocuments(items, options = {}) {
101
+ if (!Array.isArray(items)) {
102
+ throw new TypeError('items must be an array');
103
+ }
104
+
105
+ const includeFileArtifacts = options.includeFileArtifacts !== false;
106
+ const documents = [];
107
+
108
+ for (const item of items) {
109
+ documents.push(buildWorkItemDocument(item));
110
+ if (includeFileArtifacts) {
111
+ documents.push(...buildFileArtifactDocuments(item));
112
+ }
113
+ }
114
+
115
+ return documents.sort((left, right) => compareText(left.id, right.id));
116
+ }
117
+
118
+ export function searchSemanticWorkflow(query, items, options = {}) {
119
+ const mode = options.mode ?? SEMANTIC_SEARCH_MODE_LEXICAL_V1;
120
+ if (mode === SEMANTIC_SEARCH_MODE_HYBRID_V1 || mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1) {
121
+ throw new TypeError('hybrid mode requires searchSemanticWorkflowAsync');
122
+ }
123
+
124
+ return searchSemanticWorkflowLexical(query, items, options);
125
+ }
126
+
127
+ export function searchSemanticWorkflowLexical(query, items, options = {}) {
128
+ const tokens = tokenizeQuery(query);
129
+ const limit = Number.isInteger(options.limit) && options.limit > 0
130
+ ? options.limit
131
+ : DEFAULT_LIMIT;
132
+ const maxChars = Number.isInteger(options.maxChars) && options.maxChars > 0
133
+ ? options.maxChars
134
+ : DEFAULT_MAX_CHARS;
135
+
136
+ if (tokens.length === 0) {
137
+ return {
138
+ schema: SEMANTIC_SEARCH_RESULT_SCHEMA,
139
+ query: String(query ?? '').trim(),
140
+ mode: SEMANTIC_SEARCH_MODE_LEXICAL_V1,
141
+ truncated: false,
142
+ hitCount: 0,
143
+ summaryChars: 0,
144
+ hits: [],
145
+ reviewRequired: false,
146
+ };
147
+ }
148
+
149
+ const documents = options.documents ?? buildSemanticSearchDocuments(items, options);
150
+ const scored = documents
151
+ .map((document) => ({
152
+ ...document,
153
+ score: scoreDocument(tokens, document.parts),
154
+ }))
155
+ .filter((entry) => entry.score > 0)
156
+ .sort((left, right) => {
157
+ const byScore = right.score - left.score;
158
+ if (byScore !== 0) {
159
+ return byScore;
160
+ }
161
+
162
+ return compareText(left.id, right.id);
163
+ });
164
+
165
+ const hits = [];
166
+ let summaryChars = 0;
167
+ let truncated = false;
168
+
169
+ for (const entry of scored) {
170
+ if (hits.length >= limit) {
171
+ truncated = true;
172
+ break;
173
+ }
174
+
175
+ const nextSummaryChars = summaryChars + entry.summary.length;
176
+ if (nextSummaryChars > maxChars && hits.length > 0) {
177
+ truncated = true;
178
+ continue;
179
+ }
180
+
181
+ hits.push({
182
+ id: entry.id,
183
+ score: entry.score,
184
+ kind: entry.kind,
185
+ label: entry.label,
186
+ summary: entry.summary,
187
+ workId: entry.workId,
188
+ filePath: entry.filePath,
189
+ architectureBlockId: entry.architectureBlockId,
190
+ traceRefs: [...entry.traceRefs].sort(compareText),
191
+ });
192
+ summaryChars = nextSummaryChars;
193
+ }
194
+
195
+ if (hits.length < scored.length) {
196
+ truncated = true;
197
+ }
198
+
199
+ return {
200
+ schema: SEMANTIC_SEARCH_RESULT_SCHEMA,
201
+ query: String(query ?? '').trim(),
202
+ mode: SEMANTIC_SEARCH_MODE_LEXICAL_V1,
203
+ truncated,
204
+ hitCount: hits.length,
205
+ summaryChars,
206
+ hits,
207
+ reviewRequired: false,
208
+ embeddingsUsed: false,
209
+ };
210
+ }
211
+
212
+ export async function searchSemanticWorkflowAsync(query, items, options = {}) {
213
+ const mode = options.mode ?? SEMANTIC_SEARCH_MODE_LEXICAL_V1;
214
+ const useHybrid = mode === SEMANTIC_SEARCH_MODE_HYBRID_V1
215
+ || mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1;
216
+ if (!useHybrid) {
217
+ return searchSemanticWorkflowLexical(query, items, options);
218
+ }
219
+
220
+ const tokens = tokenizeQuery(query);
221
+ const limit = Number.isInteger(options.limit) && options.limit > 0
222
+ ? options.limit
223
+ : DEFAULT_LIMIT;
224
+ const maxChars = Number.isInteger(options.maxChars) && options.maxChars > 0
225
+ ? options.maxChars
226
+ : DEFAULT_MAX_CHARS;
227
+
228
+ if (tokens.length === 0) {
229
+ return {
230
+ schema: SEMANTIC_SEARCH_RESULT_SCHEMA,
231
+ query: String(query ?? '').trim(),
232
+ mode,
233
+ truncated: false,
234
+ hitCount: 0,
235
+ summaryChars: 0,
236
+ hits: [],
237
+ reviewRequired: false,
238
+ embeddingsUsed: mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1,
239
+ vectorIndex: mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1 ? 'tfidf-v1' : null,
240
+ };
241
+ }
242
+
243
+ const baseDocuments = buildSemanticSearchDocuments(items, options);
244
+ const targetFilesByWorkId = new Map(
245
+ items.map((item) => [item.id, [...(item.targetFiles ?? [])]]),
246
+ );
247
+ const documents = await enrichSemanticDocumentsWithExcerpts(baseDocuments, {
248
+ ...options,
249
+ targetFilesByWorkId,
250
+ });
251
+
252
+ const lexicalScored = documents
253
+ .map((document) => ({
254
+ ...document,
255
+ score: scoreDocument(tokens, document.parts),
256
+ }))
257
+ .filter((entry) => entry.score > 0);
258
+
259
+ const bm25Index = buildBm25Index(documents);
260
+ const bm25Scores = scoreBm25(tokenizeForBm25(query), bm25Index, options);
261
+ const bm25Weight = Number(options.bm25Weight ?? 4);
262
+ const vectorWeight = Number(options.vectorWeight ?? 3);
263
+
264
+ let tfidfScores = new Map();
265
+ if (mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1) {
266
+ const tfidfIndex = buildTfidfIndex(documents);
267
+ tfidfScores = new Map(scoreTfidfCosine(query, tfidfIndex).map((entry) => [entry.id, entry.score]));
268
+ }
269
+
270
+ const candidatePool = documents
271
+ .map((document) => {
272
+ const lexicalScore = lexicalScored.find((entry) => entry.id === document.id)?.score ?? 0;
273
+ const bm25Score = bm25Scores.get(document.id) ?? 0;
274
+ const vectorScore = tfidfScores.get(document.id) ?? 0;
275
+ const score = lexicalScore
276
+ + bm25Weight * bm25Score
277
+ + (mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1 ? vectorWeight * vectorScore : 0);
278
+
279
+ return {
280
+ ...document,
281
+ lexicalScore,
282
+ bm25Score,
283
+ vectorScore,
284
+ score,
285
+ };
286
+ })
287
+ .filter((entry) => entry.score > 0)
288
+ .sort((left, right) => {
289
+ const byScore = right.score - left.score;
290
+ if (byScore !== 0) {
291
+ return byScore;
292
+ }
293
+
294
+ return compareText(left.id, right.id);
295
+ });
296
+
297
+ const hits = [];
298
+ let summaryChars = 0;
299
+ let truncated = false;
300
+
301
+ for (const entry of candidatePool) {
302
+ if (hits.length >= limit) {
303
+ truncated = true;
304
+ break;
305
+ }
306
+
307
+ const excerpt = entry.excerpt ? entry.excerpt.slice(0, 240) : null;
308
+ const summary = excerpt
309
+ ? `${entry.summary} | excerpt: ${excerpt}`
310
+ : entry.summary;
311
+
312
+ const nextSummaryChars = summaryChars + summary.length;
313
+ if (nextSummaryChars > maxChars && hits.length > 0) {
314
+ truncated = true;
315
+ continue;
316
+ }
317
+
318
+ hits.push({
319
+ id: entry.id,
320
+ score: Number(entry.score.toFixed(3)),
321
+ lexicalScore: entry.lexicalScore ?? 0,
322
+ bm25Score: entry.bm25Score ?? 0,
323
+ ...(mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1
324
+ ? { vectorScore: Number((entry.vectorScore ?? 0).toFixed(3)) }
325
+ : {}),
326
+ kind: entry.kind,
327
+ label: entry.label,
328
+ summary,
329
+ workId: entry.workId,
330
+ filePath: entry.filePath,
331
+ excerpt,
332
+ excerptSources: entry.excerptSources ?? [],
333
+ architectureBlockId: entry.architectureBlockId,
334
+ traceRefs: [...entry.traceRefs].sort(compareText),
335
+ });
336
+ summaryChars = nextSummaryChars;
337
+ }
338
+
339
+ if (hits.length < candidatePool.length) {
340
+ truncated = true;
341
+ }
342
+
343
+ return {
344
+ schema: SEMANTIC_SEARCH_RESULT_SCHEMA,
345
+ query: String(query ?? '').trim(),
346
+ mode,
347
+ truncated,
348
+ hitCount: hits.length,
349
+ summaryChars,
350
+ hits,
351
+ reviewRequired: false,
352
+ embeddingsUsed: mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1,
353
+ vectorIndex: mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1 ? 'tfidf-v1' : null,
354
+ };
355
+ }
356
+
357
+ export async function executeSemanticSearchFromRepo(options = {}) {
358
+ const { readWorkItemsFromRepo } = await import('./intentTreeWorkItems.mjs');
359
+ const items = options.items ?? await readWorkItemsFromRepo(options);
360
+ const mode = options.mode ?? SEMANTIC_SEARCH_MODE_LEXICAL_V1;
361
+ if (mode === SEMANTIC_SEARCH_MODE_HYBRID_V1 || mode === SEMANTIC_SEARCH_MODE_HYBRID_VECTOR_V1) {
362
+ return searchSemanticWorkflowAsync(options.query ?? '', items, options);
363
+ }
364
+
365
+ return searchSemanticWorkflow(options.query ?? '', items, options);
366
+ }