@devflow-tools/mcp-server 0.17.3 → 0.17.4

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.
package/dist/tools.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type EngineSet } from "@devflow-tools/context-engine";
2
- import type { DevFlowPlugin } from "@devflow-tools/sdk";
2
+ import { type ChannelQueryPlan, type DevFlowPlugin, type ImmutableTaskIntentArtifact } from "@devflow-tools/sdk";
3
+ import type { SemanticSamplingResolver } from './semantic-sampling-resolver.js';
3
4
  export interface ToolDef {
4
5
  name: string;
5
6
  description: string;
@@ -20,7 +21,28 @@ export declare const GUARDED_CORE_TOOL_NAMES: ReadonlySet<string>;
20
21
  export declare function getGuardedToolNames(pluginTools: readonly Pick<ToolDef, "name">[]): ReadonlySet<string>;
21
22
  export declare function getCoreTools(knowledgeScopes?: string[]): ToolDef[];
22
23
  export type ToolHandlers = Record<string, (args: Record<string, unknown>) => Promise<unknown>>;
23
- export declare function createToolHandlers(engines: EngineSet, boundProjectRoot: string): ToolHandlers;
24
+ declare function resolveBoundContextTask(input: {
25
+ projectRoot: string;
26
+ sessionId?: string;
27
+ requestId?: string;
28
+ turnId?: string;
29
+ intentArtifactHash?: string;
30
+ agentQuery: string;
31
+ expandedTerms?: string;
32
+ }): {
33
+ query: string;
34
+ expandedTerms?: string;
35
+ requestId?: string;
36
+ turnId?: string;
37
+ intentArtifact?: ImmutableTaskIntentArtifact;
38
+ queryPlan?: ChannelQueryPlan;
39
+ };
40
+ export declare function resolveBoundContextTaskWithSemantics(input: Parameters<typeof resolveBoundContextTask>[0], engines: EngineSet, dependencies: ToolHandlerDependencies): Promise<ReturnType<typeof resolveBoundContextTask>>;
41
+ export interface ToolHandlerDependencies {
42
+ semanticSampling?: SemanticSamplingResolver;
43
+ }
44
+ export declare function createToolHandlers(engines: EngineSet, boundProjectRoot: string, dependencies?: ToolHandlerDependencies): ToolHandlers;
24
45
  export declare function getPluginTools(plugins: DevFlowPlugin[]): ToolDef[];
25
46
  export declare function createPluginHandlers(engines: EngineSet, plugins: DevFlowPlugin[], boundProjectRoot: string): Record<string, (args: Record<string, unknown>) => Promise<unknown>>;
47
+ export {};
26
48
  //# sourceMappingURL=tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAEV,aAAa,EAGd,MAAM,oBAAoB,CAAC;AAoB5B,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE;QACZ,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;CACH;AAED,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CActD,CAAC;AA0BH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,GAC5C,WAAW,CAAC,MAAM,CAAC,CAKrB;AAED,wBAAgB,YAAY,CAAC,eAAe,GAAE,MAAM,EAAO,GAAG,OAAO,EAAE,CAwWtE;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAkT/F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,GAAG,YAAY,CA+kC7F;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAqClE;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,aAAa,EAAE,EACxB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAkErE"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/dist/tools.js CHANGED
@@ -1,4 +1,5 @@
1
- import { getKnowledgeResult, getMemoryResult, getProjectContextResult, } from "@devflow-tools/context-engine";
1
+ import { buildChannelQueryPlan, buildRetrievalTaskPlan, extractStructuralSemanticEvidence, getKnowledgeResult, getMemoryResult, getProjectContextResult, mergeSemanticAuthority, parseIntent, } from "@devflow-tools/context-engine";
2
+ import { assertTaskSemanticFrameV2, projectSemanticFrameToLegacyIntent, resolveSemanticResolutionMode, } from "@devflow-tools/sdk";
2
3
  import { resolveCapabilityRollout } from "@devflow-tools/sdk/capability-rollout";
3
4
  import { canonicalizeProjectRoot, wrapHandlerRequireRoot } from "./plugin-guards.js";
4
5
  import { getReportResourceUri, readToolReport } from "./report-store.js";
@@ -640,15 +641,303 @@ function resolveBoundContextTask(input) {
640
641
  database.close();
641
642
  }
642
643
  }
644
+ export async function resolveBoundContextTaskWithSemantics(input, engines, dependencies) {
645
+ const legacy = resolveBoundContextTask(input);
646
+ const artifact = legacy.intentArtifact;
647
+ if (!artifact)
648
+ return legacy;
649
+ const semanticMode = resolveSemanticResolutionMode(input.projectRoot);
650
+ if (semanticMode === 'off' || !engines.semanticRouter)
651
+ return legacy;
652
+ const database = openGlobalDevFlowDatabase(undefined, { busyTimeoutMs: 250 });
653
+ try {
654
+ const latest = database.getLatestSemanticResolution(artifact.identity.projectRoot, artifact.identity.sessionId, artifact.identity.turnId);
655
+ if (!latest)
656
+ return legacy;
657
+ if (latest.artifactRevision >= 2) {
658
+ const resolvedArtifact = database.getTaskIntentArtifact(latest.artifactHash);
659
+ const resolvedPlan = resolvedArtifact && database.getChannelQueryPlanForIntent({
660
+ projectRoot: resolvedArtifact.projectRoot,
661
+ sessionId: resolvedArtifact.sessionId,
662
+ turnId: resolvedArtifact.turnId,
663
+ sourceIntentHash: resolvedArtifact.artifactHash,
664
+ });
665
+ if (resolvedArtifact && resolvedPlan && semanticMode !== 'shadow') {
666
+ return boundTaskFromRecords(legacy, resolvedArtifact, resolvedPlan);
667
+ }
668
+ return legacy;
669
+ }
670
+ let provisional;
671
+ try {
672
+ assertTaskSemanticFrameV2(latest.frame, artifact.normalizedPrompt);
673
+ provisional = latest.frame;
674
+ }
675
+ catch {
676
+ return legacy;
677
+ }
678
+ const structural = extractStructuralSemanticEvidence({
679
+ prompt: artifact.normalizedPrompt,
680
+ command: artifact.command,
681
+ targetAnchors: artifact.targetAnchors,
682
+ });
683
+ const route = await engines.semanticRouter.route(structural.normalizedPrompt);
684
+ emitSemanticControlLog({
685
+ event: 'semantic.route.scored',
686
+ identity: { ...artifact.identity, intentArtifactHash: artifact.artifactHash },
687
+ level: route.status === 'unavailable' ? 'warn' : 'info',
688
+ timestamp: Date.now(),
689
+ data: {
690
+ mode: semanticMode,
691
+ status: route.status,
692
+ modelId: route.modelId,
693
+ modelRevision: route.modelRevision,
694
+ thresholdVersion: route.thresholdVersion,
695
+ margin: route.margin,
696
+ candidates: route.candidates.slice(0, 8),
697
+ latencyMs: route.latencyMs,
698
+ reason: route.reason,
699
+ },
700
+ });
701
+ emitSemanticControlLog({
702
+ event: 'semantic.model.profile_evaluated',
703
+ identity: { ...artifact.identity, intentArtifactHash: artifact.artifactHash },
704
+ level: 'debug', timestamp: Date.now(),
705
+ data: {
706
+ mode: semanticMode, modelId: route.modelId, modelRevision: route.modelRevision,
707
+ thresholdVersion: route.thresholdVersion, catalogVersion: provisional.resolver.routeCatalogVersion,
708
+ status: route.status, latencyMs: route.latencyMs,
709
+ },
710
+ });
711
+ let sampled;
712
+ if ((route.status === 'escalation_required' || hasCompositionalStructure(structural))
713
+ && dependencies.semanticSampling) {
714
+ emitSemanticControlLog({
715
+ event: 'semantic.resolution.escalated', identity: artifact.identity, level: 'info', timestamp: Date.now(),
716
+ data: { mode: semanticMode, frameHash: provisional.frameHash, reason: route.reason },
717
+ });
718
+ sampled = await dependencies.semanticSampling({
719
+ normalizedPrompt: structural.normalizedPrompt,
720
+ sourceHash: artifact.sourceHash,
721
+ structural,
722
+ route,
723
+ provisionalFrame: provisional,
724
+ timeoutMs: 3_000,
725
+ });
726
+ }
727
+ const resolved = mergeSemanticAuthority({
728
+ sourceHash: artifact.sourceHash,
729
+ structural,
730
+ route,
731
+ ...(sampled?.status === 'resolved' && sampled.frame ? { sampledFrame: sampled.frame } : {}),
732
+ provisionalFrame: provisional,
733
+ });
734
+ const finalResolution = withSamplingResult(resolved, sampled);
735
+ const projection = projectSemanticFrameToLegacyIntent(finalResolution.frame);
736
+ const revisedBody = {
737
+ ...artifact,
738
+ version: 2,
739
+ supersedesHash: artifact.artifactHash,
740
+ intent: projection.intent,
741
+ action: projection.action,
742
+ entities: finalResolution.frame.entities,
743
+ targetAnchors: finalResolution.frame.targetAnchors,
744
+ policyConstraints: finalResolution.frame.constraints,
745
+ classificationEvidence: finalResolution.frame.evidence.flatMap((evidence) => {
746
+ const field = evidence.field === 'negation' || evidence.field === 'condition'
747
+ ? 'constraint'
748
+ : evidence.field;
749
+ if (field !== 'intent' && field !== 'action' && field !== 'entity'
750
+ && field !== 'target' && field !== 'constraint')
751
+ return [];
752
+ const source = evidence.source === 'structural'
753
+ || evidence.source === 'lexical_feature'
754
+ ? 'deterministic_parser'
755
+ : evidence.source === 'host_sampling'
756
+ ? 'host_semantic'
757
+ : evidence.source;
758
+ return [{
759
+ source,
760
+ field,
761
+ value: evidence.value,
762
+ reason: `semantic_frame:${finalResolution.frame.frameHash}`,
763
+ confidence: evidence.confidence,
764
+ }];
765
+ }),
766
+ createdAt: finalResolution.frame.createdAt,
767
+ };
768
+ const { artifactHash: _oldHash, ...unhashedArtifact } = revisedBody;
769
+ const revisedArtifact = {
770
+ ...unhashedArtifact,
771
+ artifactHash: hashCanonical(unhashedArtifact),
772
+ };
773
+ const taskPlan = buildRetrievalTaskPlan({
774
+ query: legacy.query,
775
+ parsedIntent: parseIntent(legacy.query),
776
+ targetAnchors: revisedArtifact.targetAnchors,
777
+ activeSkill: revisedArtifact.activeSkill,
778
+ command: revisedArtifact.command,
779
+ authoritativeArtifact: revisedArtifact,
780
+ semanticFrame: finalResolution.frame,
781
+ });
782
+ const revisedPlan = buildChannelQueryPlan({
783
+ artifact: revisedArtifact,
784
+ taskPlan,
785
+ expandedTerms: legacy.expandedTerms,
786
+ generatedBy: 'hybrid',
787
+ });
788
+ database.appendTaskIntentArtifact(toTaskIntentRecord(revisedArtifact));
789
+ database.appendChannelQueryPlan(toChannelQueryPlanRecord(revisedPlan));
790
+ database.appendSemanticResolution({
791
+ frameHash: finalResolution.frame.frameHash,
792
+ ...artifact.identity,
793
+ sourceHash: artifact.sourceHash,
794
+ artifactHash: revisedArtifact.artifactHash,
795
+ artifactRevision: 2,
796
+ supersedesFrameHash: provisional.frameHash,
797
+ state: finalResolution.frame.state,
798
+ generatedBy: finalResolution.frame.resolver.generatedBy,
799
+ modelId: finalResolution.frame.resolver.modelId,
800
+ modelRevision: finalResolution.frame.resolver.modelRevision,
801
+ routeCatalogVersion: finalResolution.frame.resolver.routeCatalogVersion,
802
+ thresholdVersion: finalResolution.frame.resolver.thresholdVersion,
803
+ route: finalResolution.route,
804
+ sampling: finalResolution.sampling,
805
+ conflicts: finalResolution.conflicts,
806
+ frame: finalResolution.frame,
807
+ durationMs: Math.round(finalResolution.route.latencyMs + (finalResolution.sampling.latencyMs ?? 0)),
808
+ createdAt: finalResolution.frame.createdAt,
809
+ });
810
+ logSemanticResolution(artifact, semanticMode, finalResolution, projection);
811
+ return semanticMode === 'shadow'
812
+ ? legacy
813
+ : { ...legacy, intentArtifact: revisedArtifact, queryPlan: revisedPlan };
814
+ }
815
+ finally {
816
+ database.close();
817
+ }
818
+ }
819
+ function boundTaskFromRecords(legacy, artifactRecord, planRecord) {
820
+ return {
821
+ ...legacy,
822
+ intentArtifact: toSdkIntentArtifact(artifactRecord),
823
+ queryPlan: toSdkChannelQueryPlan(planRecord),
824
+ };
825
+ }
826
+ function hasCompositionalStructure(structural) {
827
+ return structural.conditions.length > 0 || structural.prohibitions.length > 0
828
+ || new Set(structural.positiveActionSpans.map(item => item.value)).size > 1;
829
+ }
830
+ function withSamplingResult(resolution, sampled) {
831
+ if (!sampled)
832
+ return resolution;
833
+ return {
834
+ ...resolution,
835
+ sampling: {
836
+ attempted: true,
837
+ status: sampled.status,
838
+ ...(sampled.model ? { model: sampled.model } : {}),
839
+ latencyMs: sampled.latencyMs,
840
+ ...(sampled.responseHash ? { responseHash: sampled.responseHash } : {}),
841
+ },
842
+ };
843
+ }
844
+ function logSemanticResolution(artifact, mode, resolution, projection) {
845
+ const event = resolution.frame.state === 'resolved'
846
+ ? 'semantic.resolution.completed'
847
+ : 'semantic.resolution.abstained';
848
+ emitSemanticControlLog({
849
+ event, identity: { ...artifact.identity, intentArtifactHash: artifact.artifactHash },
850
+ level: resolution.frame.state === 'resolved' ? 'info' : 'warn', timestamp: Date.now(),
851
+ data: {
852
+ mode, frameHash: resolution.frame.frameHash, state: resolution.frame.state,
853
+ permission: resolution.frame.mutationPermission, intent: projection.intent,
854
+ action: projection.action, samplingStatus: resolution.sampling.status,
855
+ conflictCount: resolution.conflicts.length,
856
+ },
857
+ });
858
+ if (resolution.conflicts.length > 0)
859
+ emitSemanticControlLog({
860
+ event: 'semantic.authority.conflicted', identity: artifact.identity, level: 'warn', timestamp: Date.now(),
861
+ data: { frameHash: resolution.frame.frameHash, conflicts: resolution.conflicts },
862
+ });
863
+ if (projection.intent !== artifact.intent || projection.action !== artifact.action)
864
+ emitSemanticControlLog({
865
+ event: 'semantic.regex.shadow_mismatch', identity: artifact.identity, level: 'info', timestamp: Date.now(),
866
+ data: { mode, frameHash: resolution.frame.frameHash, legacyIntent: artifact.intent,
867
+ legacyAction: artifact.action, semanticIntent: projection.intent, semanticAction: projection.action },
868
+ });
869
+ }
870
+ function toTaskIntentRecord(artifact) {
871
+ return {
872
+ ...artifact.identity, version: artifact.version, supersedesHash: artifact.supersedesHash,
873
+ rawPrompt: artifact.rawPrompt, normalizedPrompt: artifact.normalizedPrompt,
874
+ command: artifact.command, slashArgs: artifact.slashArgs, activeSkill: artifact.activeSkill,
875
+ intent: artifact.intent, action: artifact.action, entities: artifact.entities,
876
+ targetAnchors: artifact.targetAnchors, policyConstraints: artifact.policyConstraints,
877
+ classificationEvidence: artifact.classificationEvidence.map(item => ({ ...item })),
878
+ sourceEventIds: artifact.sourceEventIds, sourceHash: artifact.sourceHash,
879
+ artifactHash: artifact.artifactHash, createdAt: artifact.createdAt,
880
+ };
881
+ }
882
+ function toChannelQueryPlanRecord(plan) {
883
+ return {
884
+ ...plan.identity, sourceIntentHash: plan.sourceIntentHash, planHash: plan.planHash,
885
+ code: plan.code.map(item => ({ ...item })), memory: plan.memory.map(item => ({ ...item })),
886
+ knowledge: plan.knowledge.map(item => ({ ...item })), generatedBy: plan.generatedBy,
887
+ ...(plan.degradation ? { degradation: { ...plan.degradation } } : {}), createdAt: plan.createdAt,
888
+ };
889
+ }
890
+ function toSdkIntentArtifact(record) {
891
+ return {
892
+ identity: { projectRoot: record.projectRoot, projectId: record.projectId, hostId: record.hostId,
893
+ sessionId: record.sessionId, turnId: record.turnId, requestId: record.requestId,
894
+ ...(record.executionId ? { executionId: record.executionId } : {}) },
895
+ version: record.version, ...(record.supersedesHash ? { supersedesHash: record.supersedesHash } : {}),
896
+ rawPrompt: record.rawPrompt, normalizedPrompt: record.normalizedPrompt,
897
+ ...(record.command ? { command: record.command } : {}), slashArgs: record.slashArgs,
898
+ ...(record.activeSkill ? { activeSkill: record.activeSkill } : {}), intent: record.intent,
899
+ action: record.action, entities: record.entities, targetAnchors: record.targetAnchors,
900
+ policyConstraints: record.policyConstraints, classificationEvidence: record.classificationEvidence,
901
+ sourceEventIds: record.sourceEventIds, sourceHash: record.sourceHash,
902
+ artifactHash: record.artifactHash, createdAt: record.createdAt,
903
+ };
904
+ }
905
+ function toSdkChannelQueryPlan(record) {
906
+ return { identity: { projectRoot: record.projectRoot, projectId: record.projectId, hostId: record.hostId,
907
+ sessionId: record.sessionId, turnId: record.turnId, requestId: record.requestId,
908
+ ...(record.executionId ? { executionId: record.executionId } : {}) },
909
+ sourceIntentHash: record.sourceIntentHash, planHash: record.planHash, code: record.code,
910
+ memory: record.memory, knowledge: record.knowledge, generatedBy: record.generatedBy,
911
+ ...(record.degradation ? { degradation: record.degradation } : {}), createdAt: record.createdAt };
912
+ }
913
+ function hashCanonical(value) {
914
+ return createHash('sha256').update(stableCanonicalJson(value)).digest('hex');
915
+ }
916
+ function stableCanonicalJson(value) {
917
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
918
+ return JSON.stringify(value);
919
+ if (typeof value === 'number')
920
+ return Number.isFinite(value) ? JSON.stringify(value) : 'null';
921
+ if (Array.isArray(value))
922
+ return `[${value.map(stableCanonicalJson).join(',')}]`;
923
+ if (!value || typeof value !== 'object')
924
+ return JSON.stringify(String(value));
925
+ const record = value;
926
+ return `{${Object.keys(record).sort().filter(key => record[key] !== undefined)
927
+ .map(key => `${JSON.stringify(key)}:${stableCanonicalJson(record[key])}`).join(',')}}`;
928
+ }
643
929
  function stripArtifactCommand(prompt, command) {
644
930
  if (!command)
645
931
  return prompt;
646
932
  const escaped = command.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
647
933
  return prompt.replace(new RegExp(`^\\/${escaped}\\b`, 'iu'), '').trim() || prompt;
648
934
  }
649
- export function createToolHandlers(engines, boundProjectRoot) {
935
+ export function createToolHandlers(engines, boundProjectRoot, dependencies = {}) {
650
936
  const hasBoundProjectRoot = typeof boundProjectRoot === 'string' && boundProjectRoot.trim().length > 0;
651
937
  const canonicalProjectRoot = canonicalizeProjectRoot(String(boundProjectRoot ?? process.cwd()));
938
+ // Resolution is invoked by the rollout-aware context path in the next stage.
939
+ // Retaining the injected dependency here keeps handler construction backward compatible.
940
+ void dependencies.semanticSampling;
652
941
  function getFreshnessMs() {
653
942
  try {
654
943
  const stats = engines.codegraph.getStats();
@@ -660,7 +949,7 @@ export function createToolHandlers(engines, boundProjectRoot) {
660
949
  }
661
950
  const handlers = {
662
951
  get_project_context: async ({ query, mode, expandedTerms, retrievalSessionId, baselineReceipt, missingContext, _devflow_session_id, _devflow_execution_id, _devflow_request_id, _devflow_turn_id, _devflow_intent_artifact_hash, _devflow_active_skill, activeSkill }) => {
663
- const boundTask = resolveBoundContextTask({
952
+ const boundTask = await resolveBoundContextTaskWithSemantics({
664
953
  projectRoot: canonicalProjectRoot,
665
954
  sessionId: typeof _devflow_session_id === 'string' ? _devflow_session_id : undefined,
666
955
  requestId: typeof _devflow_request_id === 'string' ? _devflow_request_id : undefined,
@@ -668,7 +957,7 @@ export function createToolHandlers(engines, boundProjectRoot) {
668
957
  intentArtifactHash: typeof _devflow_intent_artifact_hash === 'string' ? _devflow_intent_artifact_hash : undefined,
669
958
  agentQuery: query,
670
959
  expandedTerms: typeof expandedTerms === 'string' ? expandedTerms : undefined,
671
- });
960
+ }, engines, dependencies);
672
961
  return getProjectContextResult(engines.context, {
673
962
  query: boundTask.query,
674
963
  mode: mode ?? "fast",