@devflow-tools/mcp-server 0.17.7 → 0.18.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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -2
  3. package/dist/command-registry.json +5 -5
  4. package/dist/domain-tool-registry.d.ts +3 -0
  5. package/dist/domain-tool-registry.d.ts.map +1 -0
  6. package/dist/domain-tool-registry.js +24 -0
  7. package/dist/domain-tool-registry.js.map +1 -0
  8. package/dist/enforcer/constitutional.js +1 -1
  9. package/dist/enforcer/constitutional.js.map +1 -1
  10. package/dist/enforcer/index.d.ts +2 -2
  11. package/dist/enforcer/index.d.ts.map +1 -1
  12. package/dist/enforcer/index.js +140 -49
  13. package/dist/enforcer/index.js.map +1 -1
  14. package/dist/enforcer/rule-engine.d.ts +1 -1
  15. package/dist/enforcer/rule-engine.d.ts.map +1 -1
  16. package/dist/enforcer/rule-engine.js +1 -1
  17. package/dist/enforcer/rule-engine.js.map +1 -1
  18. package/dist/index.js +8 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/resources.d.ts +1 -1
  21. package/dist/resources.d.ts.map +1 -1
  22. package/dist/retrieval-composition.d.ts +73 -0
  23. package/dist/retrieval-composition.d.ts.map +1 -0
  24. package/dist/retrieval-composition.js +611 -0
  25. package/dist/retrieval-composition.js.map +1 -0
  26. package/dist/runtime-composition.d.ts +42 -0
  27. package/dist/runtime-composition.d.ts.map +1 -0
  28. package/dist/runtime-composition.js +93 -0
  29. package/dist/runtime-composition.js.map +1 -0
  30. package/dist/sampling-evidence-reranker.d.ts +4 -0
  31. package/dist/sampling-evidence-reranker.d.ts.map +1 -0
  32. package/dist/sampling-evidence-reranker.js +82 -0
  33. package/dist/sampling-evidence-reranker.js.map +1 -0
  34. package/dist/semantic-sampling-resolver.d.ts +7 -6
  35. package/dist/semantic-sampling-resolver.d.ts.map +1 -1
  36. package/dist/semantic-sampling-resolver.js +191 -71
  37. package/dist/semantic-sampling-resolver.js.map +1 -1
  38. package/dist/server.d.ts +2 -1
  39. package/dist/server.d.ts.map +1 -1
  40. package/dist/server.js +15 -6
  41. package/dist/server.js.map +1 -1
  42. package/dist/task-evidence-service.d.ts +24 -0
  43. package/dist/task-evidence-service.d.ts.map +1 -0
  44. package/dist/task-evidence-service.js +202 -0
  45. package/dist/task-evidence-service.js.map +1 -0
  46. package/dist/tool-contracts.d.ts +26 -7
  47. package/dist/tool-contracts.d.ts.map +1 -1
  48. package/dist/tool-contracts.js +27 -6
  49. package/dist/tool-contracts.js.map +1 -1
  50. package/dist/tool-profile.d.ts +1 -0
  51. package/dist/tool-profile.d.ts.map +1 -1
  52. package/dist/tool-profile.js +13 -2
  53. package/dist/tool-profile.js.map +1 -1
  54. package/dist/tools.d.ts +11 -2
  55. package/dist/tools.d.ts.map +1 -1
  56. package/dist/tools.js +295 -335
  57. package/dist/tools.js.map +1 -1
  58. package/package.json +34 -11
@@ -0,0 +1,611 @@
1
+ import { stableRuntimeHash, } from '@devflow-tools/sdk';
2
+ import { openGlobalDevFlowDatabase } from '@devflow-tools/database';
3
+ import { RetrievalCoordinator, RetrievalSessionRepository, RetrievalTaskKernelAdapter, } from '@devflow-tools/retrieval-engine';
4
+ import { TaskEventStore, TaskKernel } from '@devflow-tools/task-runtime';
5
+ import { emitSemanticControlLog, SemanticRuntimeEventProjector } from '@devflow-tools/telemetry';
6
+ import { planDomainAction } from '@devflow-tools/semantic-engine';
7
+ import { createDomainToolRegistry } from './domain-tool-registry.js';
8
+ export { createDomainToolRegistry } from './domain-tool-registry.js';
9
+ export { createSamplingEvidenceReranker } from './sampling-evidence-reranker.js';
10
+ // A task turn has one canonical retrieval receipt. MCP may dispatch the three
11
+ // read-only projections concurrently, so serialize the coordinator execution
12
+ // by the immutable task identity and let every projection reuse its receipt.
13
+ const canonicalRetrievals = new Map();
14
+ const PUBLIC_EVIDENCE_TOP_K = 5;
15
+ export async function executeProjectEvidence(input) {
16
+ const key = stableRuntimeHash({
17
+ identity: input.context.identity,
18
+ taskRevision: input.definition.revision,
19
+ contextHash: input.context.contextHash,
20
+ taskDefinitionHash: input.definition.definitionHash,
21
+ reranker: input.reranker
22
+ ? { profileId: input.reranker.profileId, profileVersion: input.reranker.profileVersion }
23
+ : null,
24
+ });
25
+ let retrieval = canonicalRetrievals.get(key);
26
+ if (!retrieval) {
27
+ retrieval = runCanonicalRetrieval(input);
28
+ canonicalRetrievals.set(key, retrieval);
29
+ void retrieval.then(() => {
30
+ if (canonicalRetrievals.get(key) === retrieval)
31
+ canonicalRetrievals.delete(key);
32
+ }, () => {
33
+ if (canonicalRetrievals.get(key) === retrieval)
34
+ canonicalRetrievals.delete(key);
35
+ });
36
+ }
37
+ const result = await retrieval;
38
+ return {
39
+ envelope: projectCoordinatorResult(input.context, input.query, result.receipt, result.status, result.executionStatus),
40
+ receipt: result.receipt,
41
+ status: result.status,
42
+ };
43
+ }
44
+ async function runCanonicalRetrieval(input) {
45
+ const database = openGlobalDevFlowDatabase(undefined, { busyTimeoutMs: 500 });
46
+ try {
47
+ const coordinator = new RetrievalCoordinator({
48
+ code: input.engines.codeEvidence,
49
+ memory: input.engines.memoryQuery,
50
+ knowledge: input.engines.knowledgeQuery,
51
+ sessions: new RetrievalSessionRepository(database),
52
+ taskRuntime: new RetrievalTaskKernelAdapter(new TaskKernel(new TaskEventStore(database), new SemanticRuntimeEventProjector()), input.definition, 'mcp-retrieval-composition'),
53
+ ...(input.reranker ? { reranker: input.reranker } : {}),
54
+ observer: semanticRetrievalObserver,
55
+ });
56
+ const result = await coordinator.retrieve({
57
+ context: input.context,
58
+ taskRevision: input.definition.revision,
59
+ // The task definition owns the retrieval budget for the whole canonical
60
+ // turn. Individual MCP projections must not create a second session by
61
+ // supplying a different host-specific budget.
62
+ tokenBudget: input.definition.budgets.contextTokens,
63
+ });
64
+ recordSelectedEvidence(input.context, result.receipt);
65
+ return {
66
+ receipt: result.receipt,
67
+ status: result.status,
68
+ executionStatus: result.executionStatus,
69
+ };
70
+ }
71
+ finally {
72
+ database.close();
73
+ }
74
+ }
75
+ export async function retrieveProjectEvidence(input) {
76
+ return (await executeProjectEvidence(input)).envelope;
77
+ }
78
+ function recordSelectedEvidence(context, receipt) {
79
+ const database = openGlobalDevFlowDatabase(undefined, { busyTimeoutMs: 250 });
80
+ try {
81
+ for (const candidate of receipt.selectedEvidence ?? []) {
82
+ const identity = stableRuntimeHash({
83
+ requestId: context.identity.requestId,
84
+ contextHash: context.contextHash,
85
+ sourceType: candidate.channel,
86
+ sourceId: candidate.stableRef,
87
+ });
88
+ database.appendRetrievalLedgerEvent({
89
+ id: `retrieval:selected:${identity}`,
90
+ projectRoot: context.identity.projectRoot,
91
+ sessionId: context.identity.sessionId,
92
+ executionId: context.identity.executionId,
93
+ turnId: context.identity.turnId,
94
+ requestId: context.identity.requestId,
95
+ contextReceipt: context.contextHash,
96
+ sourceType: candidate.channel,
97
+ sourceId: candidate.stableRef,
98
+ taskSpecHash: context.taskDefinitionHash,
99
+ actor: 'mcp:retrieval-composition',
100
+ sourceVersion: candidate.evidence.sourceRevision,
101
+ sourceContentHash: candidate.evidence.contentHash,
102
+ evidenceIds: [candidate.evidence.ref],
103
+ reasonCode: 'retrieval_selection_completed',
104
+ stage: 'selected',
105
+ rank: candidate.rank,
106
+ finalScore: candidate.score,
107
+ applicability: arrayStrings(candidate.payload.applicability),
108
+ toolEvidence: [],
109
+ payload: {
110
+ returnedFinalScore: candidate.score ?? 0,
111
+ receiptHash: receipt.receiptHash,
112
+ ...releaseEvidenceIdentity(),
113
+ },
114
+ createdAt: receipt.createdAt,
115
+ });
116
+ }
117
+ }
118
+ finally {
119
+ database.close();
120
+ }
121
+ }
122
+ function releaseEvidenceIdentity() {
123
+ const releaseRunId = process.env.DEVFLOW_RELEASE_RUN_ID?.trim();
124
+ const bundleId = process.env.DEVFLOW_EVALUATION_BUNDLE_ID?.trim();
125
+ return releaseRunId && bundleId ? { releaseRunId, bundleId } : {};
126
+ }
127
+ export function loadSemanticExecutionContext(input) {
128
+ if (!input.sessionId || !input.turnId)
129
+ return null;
130
+ const database = openGlobalDevFlowDatabase(undefined, { busyTimeoutMs: 250 });
131
+ try {
132
+ const latest = database.getLatestSemanticExecutionContext({
133
+ projectRoot: input.projectRoot, sessionId: input.sessionId, turnId: input.turnId,
134
+ });
135
+ if (!latest)
136
+ return null;
137
+ const { context, revision } = latest;
138
+ const snapshot = database.getTaskAggregateSnapshot(input.projectRoot, input.sessionId, input.turnId, revision);
139
+ const definition = database.getTaskDefinitionV2(context.taskDefinitionHash);
140
+ const activation = database.getRuntimeActivation(input.projectRoot, input.sessionId, input.turnId, revision);
141
+ if (!snapshot || !definition || !activation
142
+ || snapshot.semanticFactsHash !== context.facts.factsHash
143
+ || snapshot.semanticContextHash !== context.contextHash
144
+ || snapshot.channelPlanHash !== context.plan.planHash
145
+ || context.taskDefinitionHash !== definition.definitionHash
146
+ || context.activationSnapshotHash !== activation.snapshotHash)
147
+ return null;
148
+ return { definition, context };
149
+ }
150
+ finally {
151
+ database.close();
152
+ }
153
+ }
154
+ export function projectDiagnosticCodeResult(result, freshnessMs, input) {
155
+ const now = Date.now();
156
+ const requestId = input.requestId;
157
+ const requiredPaths = new Set(result.requiredFiles.files);
158
+ const codeFiles = result.selectedEvidence.map(candidate => {
159
+ const path = String(candidate.payload.path ?? candidate.evidence.sourceId);
160
+ const required = requiredPaths.has(path);
161
+ return {
162
+ ...selectedEvidenceProvenance(candidate, 'code'),
163
+ rank: candidate.rank,
164
+ contributingLegs: candidate.contributingLegs,
165
+ excerpt: selectedEvidenceExcerpt(candidate, candidate.payload.excerpt),
166
+ path,
167
+ role: required ? 'target' : 'dependency',
168
+ artifactRole: required ? 'operation_target' : 'supporting_file',
169
+ score: candidate.score ?? strengthScore(candidate.strength),
170
+ symbols: typeof candidate.payload.symbol === 'string' ? [candidate.payload.symbol] : [],
171
+ evidence: candidate.contributingLegs.map(leg => leg.leg),
172
+ freshness: {
173
+ exists: true, indexed: true, current: candidate.freshness?.current ?? true,
174
+ indexedHash: candidate.evidence.contentHash,
175
+ currentHash: candidate.evidence.contentHash,
176
+ ...(candidate.freshness?.reason ? { reason: candidate.freshness.reason } : {}),
177
+ },
178
+ };
179
+ });
180
+ const envelopeBody = {
181
+ request: {
182
+ requestId,
183
+ turnId: input.turnId,
184
+ sessionId: input.sessionId,
185
+ executionId: input.executionId,
186
+ projectRoot: input.projectRoot,
187
+ host: input.host,
188
+ query: input.query,
189
+ intent: 'unknown',
190
+ action: 'unknown',
191
+ requiredPolicyFacets: [], entities: [], symbols: result.keySymbols.map(symbol => symbol.name),
192
+ knowledgeNeeds: [], targetAnchors: result.requiredFiles.files, projectVersions: {},
193
+ tokenBudget: Math.max(result.tokenCount, 1),
194
+ },
195
+ code: { files: codeFiles, symbols: result.keySymbols.map(symbol => symbol.name) },
196
+ memory: { entries: [] },
197
+ knowledge: { entries: [] },
198
+ quality: {
199
+ status: 'insufficient',
200
+ code: { selected: codeFiles.length, rejected: 0, targetHashCurrent: true },
201
+ memory: { selected: 0, rejected: 0 },
202
+ knowledge: { selected: 0, rejected: 0, compatibleSources: [] },
203
+ },
204
+ allowedFollowups: [],
205
+ warnings: [{
206
+ category: 'diagnostic_code_projection',
207
+ reason: 'Diagnostic Code evidence has no canonical task authority.',
208
+ }],
209
+ };
210
+ const contextHash = stableRuntimeHash(envelopeBody);
211
+ const taskEnvelope = {
212
+ ...envelopeBody,
213
+ receipt: {
214
+ requestId, issuedAt: now, expiresAt: now + 10 * 60_000,
215
+ hash: contextHash, contextHash,
216
+ },
217
+ };
218
+ const { selectedEvidence: _selectedEvidence, ...publicResult } = result;
219
+ return {
220
+ ...publicResult,
221
+ authority: 'diagnostic',
222
+ taskEnvelope,
223
+ _devflow_unique: {
224
+ search_method: 'diagnostic_code', task_oriented: false, risk_aware: true,
225
+ memory_injected: false, knowledge_injected: false, token_estimated: true,
226
+ required_vs_optional: true,
227
+ },
228
+ _accuracy: {
229
+ data_freshness_ms: freshnessMs, source_layer: 'composite', execution_status: 'executed',
230
+ },
231
+ };
232
+ }
233
+ export async function getDiagnosticMemoryResult(memory, options, metadata) {
234
+ const startedAt = Date.now();
235
+ const result = await memory.getAll(options);
236
+ const vectorCoverage = memory.getObservationVectorCoverage();
237
+ const projected = {
238
+ ...result,
239
+ authority: 'diagnostic',
240
+ _devflow_unique: { memory_version: 1, structured_storage: true, project_context_included: true },
241
+ _accuracy: {
242
+ data_freshness_ms: 0, source_layer: 'memory',
243
+ execution_status: vectorCoverage.missing > 0 ? 'unavailable' : 'executed',
244
+ },
245
+ };
246
+ emitDiagnosticRetrievalLog({
247
+ metadata, channel: 'memory', selectedCount: result.memories.length,
248
+ rejectedCount: result.retrieval?.rejectedCount ?? 0,
249
+ executionStatus: projected._accuracy.execution_status, startedAt, query: options.query,
250
+ sessionId: options.sessionId, executionId: options.executionId, requestId: options.requestId,
251
+ });
252
+ return projected;
253
+ }
254
+ export async function getDiagnosticKnowledgeResult(knowledge, args, metadata) {
255
+ const startedAt = Date.now();
256
+ const scope = args.scope?.trim() || 'all';
257
+ const available = knowledge.getScopes();
258
+ if (scope !== 'all' && available.length > 0 && !available.includes(scope)) {
259
+ throw new Error(`Unknown knowledge scope ${JSON.stringify(scope)}. Available scopes: ${available.join(', ')}`);
260
+ }
261
+ const options = {
262
+ ...(scope === 'all' ? {} : { sources: [scope] }),
263
+ retrievalIntent: 'explicit',
264
+ ...(args.budgetTokens !== undefined ? { budgetTokens: args.budgetTokens } : {}),
265
+ };
266
+ const detailed = await knowledge.searchWithStatus(args.query, options);
267
+ const projected = {
268
+ results: detailed.entries, warnings: detailed.warnings,
269
+ authority: 'diagnostic',
270
+ budgetTokens: detailed.budgetTokens ?? args.budgetTokens ?? 3_000,
271
+ tokenCount: detailed.tokenCount, truncatedCount: detailed.truncatedCount ?? 0,
272
+ rejectedLowScore: detailed.rejectedLowScore,
273
+ rejectedIncompatibleSources: detailed.rejectedIncompatibleSources,
274
+ retrievalDiagnostics: detailed.retrievalDiagnostics,
275
+ _devflow_unique: { source_versioned: true, code_examples_included: true, search_scope: scope },
276
+ _accuracy: {
277
+ data_freshness_ms: 0, source_layer: 'knowledge',
278
+ execution_status: detailed.warnings.length > 0 ? 'unavailable' : 'executed',
279
+ },
280
+ };
281
+ emitDiagnosticRetrievalLog({
282
+ metadata, channel: 'knowledge', selectedCount: detailed.entries.length,
283
+ rejectedCount: (detailed.rejectedLowScore ?? 0) + (detailed.rejectedIncompatibleSources ?? 0),
284
+ executionStatus: projected._accuracy.execution_status, startedAt, query: args.query,
285
+ });
286
+ return projected;
287
+ }
288
+ export function projectCoordinatorResult(context, query, receipt, status, executionStatus) {
289
+ const evidence = (receipt.selectedEvidence ?? []).filter((candidate) => {
290
+ const channelCount = (receipt.selectedEvidence ?? [])
291
+ .filter((item) => item.channel === candidate.channel)
292
+ .indexOf(candidate);
293
+ return channelCount < PUBLIC_EVIDENCE_TOP_K;
294
+ });
295
+ const code = evidence.filter(item => item.channel === 'code');
296
+ const memory = evidence.filter(item => item.channel === 'memory');
297
+ const knowledge = evidence.filter(item => item.channel === 'knowledge');
298
+ const required = code.filter(item => item.strength === 'strong');
299
+ const optional = code.filter(item => item.strength !== 'strong');
300
+ const activeSkill = context.scopeBindings.skill?.id;
301
+ const primaryIntent = context.facts.intents[0] ?? 'unknown';
302
+ const primaryAction = context.facts.actions[0] ?? 'analyze';
303
+ const registry = createDomainToolRegistry(activeSkill);
304
+ const targetStateEvidence = buildTargetStateEvidence(context, required);
305
+ const objectKind = primaryIntent === 'performance'
306
+ ? 'performance'
307
+ : activeSkill === 'devflow:react' && ['create', 'modify'].includes(primaryAction)
308
+ ? 'component' : undefined;
309
+ const actionPlan = registry.tools.length > 0
310
+ ? planDomainAction({
311
+ identity: context.identity,
312
+ taskRevisionHash: context.taskDefinitionHash,
313
+ taskDefinitionHash: context.taskDefinitionHash,
314
+ semanticContextHash: context.contextHash,
315
+ facts: context.facts,
316
+ actionAuthority: context.actionAuthority,
317
+ objectKind,
318
+ activeSkill,
319
+ registry,
320
+ targetStateEvidence,
321
+ phase: 'final',
322
+ }) : undefined;
323
+ const toolDefinition = actionPlan?.selectedTool
324
+ ? registry.tools.find(tool => tool.tool === actionPlan.selectedTool) : undefined;
325
+ const actionInput = toolDefinition ? buildCanonicalActionInput(toolDefinition.tool, context) : undefined;
326
+ const canonicalAction = actionPlan?.status === 'selected' && toolDefinition && actionInput
327
+ ? buildCanonicalAction({ context, receipt, actionPlan, toolDefinition, input: actionInput })
328
+ : undefined;
329
+ if (actionPlan) {
330
+ emitSemanticControlLog({
331
+ event: actionPlan.status === 'selected' ? 'domain.action.planned'
332
+ : actionPlan.status === 'needs_condition_evidence' ? 'domain.action.conditional'
333
+ : actionPlan.status === 'conflicted' ? 'domain.action.conflicted' : 'domain.action.abstained',
334
+ identity: { ...context.identity, actionReceipt: actionPlan.planHash },
335
+ level: actionPlan.status === 'selected' ? 'info' : 'warn', timestamp: Date.now(),
336
+ data: {
337
+ status: actionPlan.status, reasonCode: actionPlan.reasonCode,
338
+ selectedTool: actionPlan.selectedTool, registryHash: actionPlan.registryHash,
339
+ candidateCount: actionPlan.candidates.length,
340
+ },
341
+ });
342
+ emitSemanticControlLog({
343
+ event: 'canonical.tool.resolved',
344
+ identity: { ...context.identity, actionReceipt: actionPlan.planHash },
345
+ level: actionPlan.status === 'selected' ? 'info' : 'warn',
346
+ timestamp: Date.now(),
347
+ data: {
348
+ status: actionPlan.status,
349
+ reasonCode: actionPlan.reasonCode,
350
+ selectedTool: actionPlan.selectedTool,
351
+ registryHash: actionPlan.registryHash,
352
+ candidateCount: actionPlan.candidates.length,
353
+ },
354
+ });
355
+ }
356
+ const taskEnvelope = {
357
+ request: {
358
+ requestId: context.identity.requestId, turnId: context.identity.turnId,
359
+ sessionId: context.identity.sessionId, executionId: context.identity.executionId,
360
+ projectRoot: context.identity.projectRoot, host: context.identity.hostId, query,
361
+ intent: primaryIntent, action: primaryAction,
362
+ requiredPolicyFacets: [], entities: context.facts.entities,
363
+ symbols: context.plan.code.requirement === 'prohibited' ? [] : context.plan.code.typedQuery.symbols,
364
+ knowledgeNeeds: context.facts.knowledgeNeeds,
365
+ targetAnchors: context.facts.targets, projectVersions: {}, tokenBudget: 8_000,
366
+ queryPlanHash: context.plan.planHash,
367
+ },
368
+ code: {
369
+ files: code.map(item => ({
370
+ ...selectedEvidenceProvenance(item, 'code'),
371
+ rank: item.rank,
372
+ contributingLegs: item.contributingLegs,
373
+ excerpt: selectedEvidenceExcerpt(item, item.payload.excerpt),
374
+ path: String(item.payload.path ?? item.evidence.sourceId),
375
+ role: item.strength === 'strong' ? 'target' : 'dependency',
376
+ artifactRole: item.strength === 'strong' ? 'operation_target' : 'supporting_file',
377
+ score: item.score ?? strengthScore(item.strength),
378
+ symbols: typeof item.payload.symbol === 'string' ? [item.payload.symbol] : [],
379
+ evidence: item.contributingLegs.map(leg => leg.leg),
380
+ freshness: {
381
+ exists: true, indexed: true, current: item.freshness?.current ?? true,
382
+ ...(item.evidence.contentHash ? {
383
+ indexedHash: item.evidence.contentHash,
384
+ currentHash: item.evidence.contentHash,
385
+ } : {}),
386
+ ...(item.freshness?.reason ? { reason: item.freshness.reason } : {}),
387
+ },
388
+ })),
389
+ symbols: code.flatMap(item => typeof item.payload.symbol === 'string' ? [item.payload.symbol] : []),
390
+ },
391
+ memory: { entries: memory.map(item => ({
392
+ ...selectedEvidenceProvenance(item, 'memory'),
393
+ rank: item.rank,
394
+ contributingLegs: item.contributingLegs,
395
+ id: String(item.payload.id ?? item.evidence.sourceId), title: String(item.payload.title ?? ''),
396
+ excerpt: selectedEvidenceExcerpt(item, item.payload.content ?? item.payload.title),
397
+ type: String(item.payload.type ?? 'unknown'), score: item.score ?? 0,
398
+ applicability: arrayStrings(item.payload.applicability),
399
+ evidenceStatus: item.payload.evidenceStatus === 'verified' ? 'verified' : 'unverified',
400
+ })) },
401
+ knowledge: { entries: knowledge.map(item => ({
402
+ ...selectedEvidenceProvenance(item, 'knowledge'),
403
+ rank: item.rank,
404
+ contributingLegs: item.contributingLegs,
405
+ id: String(item.payload.id ?? item.evidence.sourceId), source: String(item.payload.source ?? ''),
406
+ title: String(item.payload.title ?? ''), excerpt: selectedEvidenceExcerpt(item, item.payload.excerpt),
407
+ url: String(item.payload.url ?? ''),
408
+ ...(typeof item.payload.version === 'string' ? { version: item.payload.version } : {}),
409
+ score: item.score ?? 0, applicability: arrayStrings(item.payload.applicability),
410
+ })) },
411
+ quality: {
412
+ status: status === 'sufficient' ? 'healthy' : 'insufficient',
413
+ code: { selected: code.length, rejected: receipt.rejectedRefs.length, targetHashCurrent: required.every(item => item.freshness?.current) },
414
+ memory: { selected: memory.length, rejected: 0 },
415
+ knowledge: { selected: knowledge.length, rejected: 0, compatibleSources: [...new Set(knowledge.map(item => String(item.payload.source ?? '')))] },
416
+ },
417
+ allowedFollowups: receipt.gaps.map(gap => ({ kind: gap.kind, target: gap.target, reason: gap.reason })),
418
+ ...(canonicalAction ? { canonicalNextAction: canonicalAction } : {}),
419
+ warnings: [
420
+ ...receipt.gaps.map(gap => ({ category: gap.kind, reason: gap.reason })),
421
+ ...(actionPlan && actionPlan.status !== 'selected'
422
+ ? [{ category: `domain_action_${actionPlan.status}`, reason: actionPlan.reasonCode }]
423
+ : []),
424
+ ],
425
+ receipt: {
426
+ requestId: context.identity.requestId, issuedAt: receipt.createdAt,
427
+ expiresAt: receipt.createdAt + 10 * 60_000, hash: receipt.receiptHash,
428
+ contextHash: context.contextHash, queryPlanHash: context.plan.planHash,
429
+ },
430
+ };
431
+ const reasoning = code.map(item => ({
432
+ source: 'dependency_trace',
433
+ fileGroup: String(item.payload.path ?? item.evidence.sourceId),
434
+ explanation: `${item.strength} evidence: ${item.contributingLegs.map(leg => leg.leg).join(', ')}`,
435
+ }));
436
+ return {
437
+ authority: 'authoritative_task',
438
+ _devflow_evidence_refs: evidence.map(item => item.stableRef),
439
+ taskType: legacyTaskType(primaryIntent),
440
+ requiredFiles: group(required, reasoning), optionalFiles: group(optional, reasoning),
441
+ keySymbols: code.flatMap(item => typeof item.payload.symbol === 'string' ? [{
442
+ name: item.payload.symbol, file: String(item.payload.path ?? ''),
443
+ kind: String(item.payload.kind ?? 'unknown'), relevance: item.strength === 'strong' ? 'direct' : 'indirect',
444
+ }] : []),
445
+ graphSummary: { roots: required.map(item => item.evidence.sourceId), traversalDepth: context.plan.code.requirement === 'prohibited' ? 0 : context.plan.code.typedQuery.maxDepth, relatedNodeCount: code.length },
446
+ riskHints: [], nextActions: [], reasoning,
447
+ confidence: code.some(item => item.strength === 'strong') ? 0.9 : code.length > 0 ? 0.5 : 0,
448
+ tokenCount: evidence.reduce((sum, item) => sum + (item.estimatedTokens ?? 0), 0),
449
+ warnings: receipt.gaps.map(gap => gap.reason), taskEnvelope,
450
+ _devflow_unique: {
451
+ search_method: receipt.reranker ? 'rrf_reranker' : 'rrf', task_oriented: true,
452
+ risk_aware: true, memory_injected: memory.length > 0, knowledge_injected: knowledge.length > 0,
453
+ token_estimated: true, required_vs_optional: true,
454
+ },
455
+ _accuracy: {
456
+ data_freshness_ms: 0, source_layer: 'composite',
457
+ execution_status: executionStatus,
458
+ },
459
+ };
460
+ }
461
+ function buildTargetStateEvidence(context, targets) {
462
+ return context.facts.targets.flatMap(anchor => {
463
+ const matched = targets.find(item => String(item.payload.path ?? '') === anchor);
464
+ if (!matched)
465
+ return [];
466
+ const body = {
467
+ schemaVersion: 'target-state-evidence.v1',
468
+ taskRevisionHash: context.taskDefinitionHash,
469
+ semanticContextHash: context.contextHash,
470
+ targetAnchor: anchor,
471
+ state: 'existing',
472
+ authority: 'code_receipt',
473
+ evidenceIds: [matched.stableRef],
474
+ };
475
+ return [{ ...body, evidenceHash: stableRuntimeHash(body) }];
476
+ });
477
+ }
478
+ function buildCanonicalActionInput(tool, context) {
479
+ const target = context.facts.targets[0]
480
+ ?? (context.plan.code.requirement === 'prohibited' ? undefined : context.plan.code.typedQuery.targetAnchors[0]);
481
+ const componentName = context.facts.entities.find(entity => /^[A-Z][A-Za-z0-9_$]*$/u.test(entity))
482
+ ?? target?.split('/').pop()?.replace(/\.[^.]+$/u, '')
483
+ ?? 'Component';
484
+ return {
485
+ projectRoot: context.identity.projectRoot,
486
+ ...(target && ['react_refactor_component', 'react_audit_performance'].includes(tool) ? { filePath: target } : {}),
487
+ ...(tool === 'react_new_component' ? { componentName } : {}),
488
+ };
489
+ }
490
+ function buildCanonicalAction(input) {
491
+ const { context, receipt, actionPlan, toolDefinition } = input;
492
+ const required = context.actionAuthority.mutation === 'authorized';
493
+ const action = context.facts.actions[0] ?? 'unknown';
494
+ const operationMode = ['create', 'modify', 'delete', 'analyze', 'debug', 'format'].includes(action)
495
+ ? action : 'unknown';
496
+ return {
497
+ tool: toolDefinition.tool,
498
+ projectedTool: context.identity.hostId === 'claude-code' ? `mcp__devflow__${toolDefinition.tool}` : toolDefinition.tool,
499
+ input: input.input,
500
+ status: required ? 'required' : 'recommended',
501
+ required,
502
+ reason: actionPlan.reasonCode,
503
+ binding: {
504
+ projectRoot: context.identity.projectRoot,
505
+ sessionId: context.identity.sessionId,
506
+ executionId: context.identity.executionId,
507
+ requestId: context.identity.requestId,
508
+ turnId: context.identity.turnId,
509
+ queryPlanHash: context.plan.planHash,
510
+ domainActionPlanHash: actionPlan.planHash,
511
+ ...(context.scopeBindings.skill ? { activeSkill: context.scopeBindings.skill.id } : {}),
512
+ targetAnchors: context.facts.targets,
513
+ requiredContextReceipt: receipt.receiptHash,
514
+ requiredPolicyFacets: [],
515
+ operationMode,
516
+ normalizedInputHash: stableRuntimeHash(input.input),
517
+ operationTargets: context.facts.targets.map(path => ({
518
+ path, expectedState: toolDefinition.targetState === 'existing' ? 'existing' : 'unknown',
519
+ })),
520
+ },
521
+ verificationPlan: toolDefinition.verification,
522
+ };
523
+ }
524
+ const semanticRetrievalObserver = {
525
+ record(event) {
526
+ emitSemanticControlLog({
527
+ event: event.name, identity: event.identity,
528
+ level: event.name === 'retrieval.cycle.stopped' && event.data.sufficiency !== 'sufficient' ? 'warn' : 'info',
529
+ data: event.data, timestamp: event.timestamp,
530
+ });
531
+ },
532
+ };
533
+ function strengthScore(value) {
534
+ return value === 'strong' ? 1 : value === 'supporting' ? 0.65 : 0.3;
535
+ }
536
+ function selectedEvidenceProvenance(candidate, channel) {
537
+ const sourceRevision = candidate.evidence.sourceRevision;
538
+ const contentHash = candidate.evidence.contentHash;
539
+ const retrievalProfile = candidate.retrievalProfile;
540
+ const generation = candidate.generation;
541
+ const vectorEvidence = candidate.contributingLegs.some(leg => leg.leg.endsWith(':vector'));
542
+ if (candidate.channel !== channel) {
543
+ throw new Error(`SELECTED_EVIDENCE_CHANNEL_MISMATCH:${candidate.stableRef}`);
544
+ }
545
+ if (!sourceRevision || !contentHash
546
+ || vectorEvidence && (!retrievalProfile || generation === undefined)
547
+ || Boolean(retrievalProfile) !== (generation !== undefined)
548
+ || generation !== undefined && (!Number.isSafeInteger(generation) || generation < 1)) {
549
+ throw new Error(`SELECTED_EVIDENCE_PROVENANCE_INCOMPLETE:${candidate.stableRef}`);
550
+ }
551
+ return {
552
+ channel, stableRef: candidate.stableRef, sourceRevision, contentHash,
553
+ ...(retrievalProfile && generation !== undefined ? { retrievalProfile, generation } : {}),
554
+ provenanceStatus: 'complete',
555
+ provenance: {
556
+ sourceId: candidate.evidence.sourceId,
557
+ producer: candidate.evidence.producer,
558
+ producerVersion: candidate.evidence.producerVersion,
559
+ parentRefs: candidate.evidence.parentRefs,
560
+ },
561
+ };
562
+ }
563
+ function arrayStrings(value) {
564
+ return Array.isArray(value) ? value.map(String) : [];
565
+ }
566
+ function boundedExcerpt(value) {
567
+ return typeof value === 'string' ? value.slice(0, 2_000) : '';
568
+ }
569
+ function selectedEvidenceExcerpt(candidate, value) {
570
+ const excerpt = boundedExcerpt(value);
571
+ if (!excerpt.trim()) {
572
+ throw new Error(`SELECTED_EVIDENCE_EXCERPT_MISSING:${candidate.stableRef}`);
573
+ }
574
+ return excerpt;
575
+ }
576
+ function emitDiagnosticRetrievalLog(input) {
577
+ emitSemanticControlLog({
578
+ event: 'retrieval.diagnostic.completed',
579
+ identity: {
580
+ projectRoot: input.metadata.projectRoot,
581
+ sessionId: input.sessionId,
582
+ executionId: input.executionId,
583
+ requestId: input.requestId,
584
+ },
585
+ level: input.executionStatus === 'executed' ? 'info' : 'warn',
586
+ timestamp: Date.now(),
587
+ data: {
588
+ authority: 'diagnostic',
589
+ channel: input.channel,
590
+ adapter: input.metadata.adapter,
591
+ selectedCount: input.selectedCount,
592
+ rejectedCount: input.rejectedCount,
593
+ executionStatus: input.executionStatus,
594
+ durationMs: Date.now() - input.startedAt,
595
+ ...(input.query ? { queryHash: stableRuntimeHash({ query: input.query }) } : {}),
596
+ },
597
+ });
598
+ }
599
+ function legacyTaskType(value) {
600
+ return ['debug', 'feature', 'refactor', 'understand', 'review'].includes(value)
601
+ ? value : 'unknown';
602
+ }
603
+ function group(values, reasoning) {
604
+ const files = [...new Set(values.map(item => String(item.payload.path ?? item.evidence.sourceId)))];
605
+ return {
606
+ files,
607
+ symbols: values.flatMap(item => typeof item.payload.symbol === 'string' ? [item.payload.symbol] : []),
608
+ reasoning: reasoning.filter(item => files.includes(item.fileGroup)),
609
+ };
610
+ }
611
+ //# sourceMappingURL=retrieval-composition.js.map