@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,372 @@
1
+ const compareText = (left, right) => String(left).localeCompare(String(right), 'en', { sensitivity: 'variant' });
2
+
3
+ /** @typedef {'keep' | 'replace' | 'defer'} ToolAuditCategory */
4
+
5
+ export const WORKGRAPH_LIVE_LOOP_REQUIRED_TOOLS = [
6
+ 'workGraph.claimNext',
7
+ 'workGraph.buildSnapshot',
8
+ 'workGraph.recordEvidence',
9
+ 'workGraph.transitionStatus',
10
+ 'worker.buildWorkerInputFromTask',
11
+ 'worker.runLocalWorker',
12
+ 'worker.runAgentWorkerLiveLoop',
13
+ 'verification.buildVerificationSummary',
14
+ ];
15
+
16
+ /** @type {Array<{ iohascTool: string, category: ToolAuditCategory, workGraphEquivalent: string | null, liveLoopRequired: boolean, notes: string }>} */
17
+ export const IOHASC_TOOL_AUDIT_ROWS = [
18
+ { iohascTool: 'agentWorkGraphSnapshot', category: 'replace', workGraphEquivalent: 'workGraph.buildSnapshot', liveLoopRequired: true, notes: 'Snapshot v1 from backlog parse' },
19
+ { iohascTool: 'agentWorkGraphSelectNext', category: 'replace', workGraphEquivalent: 'workGraph.claimNext', liveLoopRequired: true, notes: 'Read-only next eligible' },
20
+ { iohascTool: 'agentWorkGraphClaimNext', category: 'replace', workGraphEquivalent: 'workGraph.claimNext', liveLoopRequired: true, notes: 'Claim policy in runtime' },
21
+ { iohascTool: 'agentWorkGraphAddEvidence', category: 'replace', workGraphEquivalent: 'workGraph.recordEvidence', liveLoopRequired: true, notes: 'Evidence gate for done' },
22
+ { iohascTool: 'agentWorkGraphUpdateStatus', category: 'replace', workGraphEquivalent: 'workGraph.transitionStatus', liveLoopRequired: true, notes: 'Policy-gated transitions' },
23
+ { iohascTool: 'agentWorkGraphRunAutonomousLoop', category: 'replace', workGraphEquivalent: 'worker.runAgentWorkerLiveLoop', liveLoopRequired: true, notes: 'observe→stop phases' },
24
+ { iohascTool: 'agentWorkGraphSchedulerTick', category: 'replace', workGraphEquivalent: 'daemon.runWorkGraphDaemonTick', liveLoopRequired: false, notes: 'Scheduler tick wrapper' },
25
+ { iohascTool: 'readFile', category: 'replace', workGraphEquivalent: 'worker.boundedTargetFileRead', liveLoopRequired: false, notes: 'Bounded read on targetFiles only (workGraphBoundedTargetFileRead.mjs)' },
26
+ { iohascTool: 'writeFile', category: 'defer', workGraphEquivalent: null, liveLoopRequired: false, notes: 'Phase 10+ verified file ops skill' },
27
+ { iohascTool: 'runCommand', category: 'defer', workGraphEquivalent: 'verification.allowlistedCommand', liveLoopRequired: false, notes: 'Verification matrix allowlist only' },
28
+ { iohascTool: 'semanticCodeSearch', category: 'defer', workGraphEquivalent: null, liveLoopRequired: false, notes: 'Phase 8+ Graph RAG bundle optional' },
29
+ { iohascTool: 'getPvrgSubgraph', category: 'defer', workGraphEquivalent: 'pvrg.buildPvrgTaskScopeSlice', liveLoopRequired: false, notes: 'Derived projection exists; agent tool deferred' },
30
+ { iohascTool: 'getGraphRagBundle', category: 'defer', workGraphEquivalent: null, liveLoopRequired: false, notes: 'Optional context bundle' },
31
+ { iohascTool: 'onebaseListMetadata', category: 'replace', workGraphEquivalent: 'onebase.listMetadata', liveLoopRequired: false, notes: 'Builtin worker tool; MCP parity optional discovery' },
32
+ { iohascTool: 'onebaseRestCall', category: 'defer', workGraphEquivalent: 'mcp.rest_get', liveLoopRequired: false, notes: 'MCP/sidecar lane; optional REST evidence only' },
33
+ { iohascTool: 'iohascCodeGap', category: 'replace', workGraphEquivalent: 'codegen.buildCodeGapBacklogFeed', liveLoopRequired: false, notes: 'Feeder contract in phase 5' },
34
+ { iohascTool: 'todoWrite', category: 'defer', workGraphEquivalent: null, liveLoopRequired: false, notes: 'Not Work Graph source of truth' },
35
+ ];
36
+
37
+ export function buildWorkGraphToolSurfaceAudit() {
38
+ const rows = [...IOHASC_TOOL_AUDIT_ROWS].sort((left, right) => compareText(left.iohascTool, right.iohascTool));
39
+ const byCategory = {
40
+ keep: rows.filter((row) => row.category === 'keep'),
41
+ replace: rows.filter((row) => row.category === 'replace'),
42
+ defer: rows.filter((row) => row.category === 'defer'),
43
+ };
44
+
45
+ return {
46
+ schema: 'workgraph.tool.surface.audit.v1',
47
+ liveLoopRequiredTools: [...WORKGRAPH_LIVE_LOOP_REQUIRED_TOOLS],
48
+ summary: {
49
+ total: rows.length,
50
+ keep: byCategory.keep.length,
51
+ replace: byCategory.replace.length,
52
+ defer: byCategory.defer.length,
53
+ liveLoopRequired: rows.filter((row) => row.liveLoopRequired).length,
54
+ },
55
+ rows,
56
+ byCategory,
57
+ policy: {
58
+ allowFileWriteDefault: false,
59
+ allowNetworkDefault: false,
60
+ allowShellDefault: false,
61
+ verificationViaAllowlist: true,
62
+ llmTransportIsNotTool: true,
63
+ },
64
+ };
65
+ }
66
+
67
+ export const TOOL_TRANSPORT_LANES = ['builtin', 'sidecar', 'mcp', 'forbidden'];
68
+
69
+ export const DEFAULT_TRANSPORT_POLICY_GATES = {
70
+ allowShell: false,
71
+ allowNetwork: false,
72
+ allowFileWrite: false,
73
+ requireTargetFilesAllowlist: true,
74
+ requireEvidenceLogging: true,
75
+ secretsRedaction: true,
76
+ defaultTimeoutMs: 60_000,
77
+ cancellationSupported: false,
78
+ };
79
+
80
+ /** @typedef {'builtin' | 'sidecar' | 'mcp' | 'forbidden'} ToolTransportLane */
81
+
82
+ /** @type {Array<{ capability: string, lanes: ToolTransportLane[], requiresTargetFiles: boolean, requiresShell: boolean, requiresNetwork: boolean, requiresFileWrite: boolean, notes: string }>} */
83
+ export const TOOL_TRANSPORT_BOUNDARY_ROWS = [
84
+ { capability: 'workGraph.claimNext', lanes: ['builtin'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'Work Graph runtime only' },
85
+ { capability: 'workGraph.buildSnapshot', lanes: ['builtin'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'Parse backlog snapshot' },
86
+ { capability: 'workGraph.recordEvidence', lanes: ['builtin'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: false, requiresFileWrite: true, notes: 'Persist evidence via Work Graph apply path only' },
87
+ { capability: 'workGraph.transitionStatus', lanes: ['builtin'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: false, requiresFileWrite: true, notes: 'Policy-gated transitions' },
88
+ { capability: 'worker.runLocalWorker', lanes: ['builtin'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'Mandatory CI provider path' },
89
+ { capability: 'worker.boundedTargetFileRead', lanes: ['builtin', 'sidecar'], requiresTargetFiles: true, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'Sidecar may proxy read with same allowlist' },
90
+ { capability: 'verification.allowlistedCommand', lanes: ['builtin', 'sidecar'], requiresTargetFiles: false, requiresShell: true, requiresNetwork: false, requiresFileWrite: false, notes: 'Shell only via verification matrix allowlist' },
91
+ { capability: 'onebase.listMetadata', lanes: ['builtin', 'mcp'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'Prefer builtin; MCP list_metadata for discovery' },
92
+ { capability: 'onebase.readConfigFile', lanes: ['builtin', 'mcp'], requiresTargetFiles: true, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'Bounded paths only' },
93
+ { capability: 'onebase.staticVerify', lanes: ['builtin'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'Deterministic static gate' },
94
+ { capability: 'onebase.runVerificationCommand', lanes: ['builtin', 'sidecar'], requiresTargetFiles: false, requiresShell: true, requiresNetwork: false, requiresFileWrite: false, notes: 'go test blocked unless allowShell' },
95
+ { capability: 'mcp.list_metadata', lanes: ['mcp'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'External MCP server' },
96
+ { capability: 'mcp.read_config_file', lanes: ['mcp'], requiresTargetFiles: true, requiresShell: false, requiresNetwork: false, requiresFileWrite: false, notes: 'External MCP bounded read' },
97
+ { capability: 'mcp.rest_get', lanes: ['mcp', 'sidecar'], requiresTargetFiles: false, requiresShell: false, requiresNetwork: true, requiresFileWrite: false, notes: 'Optional REST evidence; never CI gate' },
98
+ { capability: 'sidecar.runCommand', lanes: ['sidecar'], requiresTargetFiles: false, requiresShell: true, requiresNetwork: false, requiresFileWrite: false, notes: 'Proxy shell with policy envelope' },
99
+ { capability: 'sidecar.writeFile', lanes: ['sidecar'], requiresTargetFiles: true, requiresShell: false, requiresNetwork: false, requiresFileWrite: true, notes: 'Deferred verified file ops' },
100
+ { capability: 'writeFile', lanes: ['forbidden'], requiresTargetFiles: true, requiresShell: false, requiresNetwork: false, requiresFileWrite: true, notes: 'Default deny; use sidecar proxy + policy' },
101
+ { capability: 'runCommand', lanes: ['forbidden'], requiresTargetFiles: false, requiresShell: true, requiresNetwork: false, requiresFileWrite: false, notes: 'Default deny; use verification allowlist path' },
102
+ { capability: 'generateFromCharter', lanes: ['forbidden'], requiresTargetFiles: true, requiresShell: true, requiresNetwork: false, requiresFileWrite: true, notes: 'Deferred until sidecar boundary implemented' },
103
+ ];
104
+
105
+ const SECRET_REDACTION_PATTERNS = [
106
+ /\b(?:api[_-]?key|token|secret|password|authorization)\s*[:=]\s*[^\s,;]+/giu,
107
+ /\bBearer\s+[A-Za-z0-9\-._~+/]+=*/giu,
108
+ /\bsk-[A-Za-z0-9]{8,}\b/gu,
109
+ ];
110
+
111
+ export function buildToolTransportBoundary() {
112
+ const rows = [...TOOL_TRANSPORT_BOUNDARY_ROWS].sort((left, right) => compareText(left.capability, right.capability));
113
+ const laneCounts = Object.fromEntries(TOOL_TRANSPORT_LANES.map((lane) => [lane, 0]));
114
+
115
+ for (const row of rows) {
116
+ for (const lane of row.lanes) {
117
+ laneCounts[lane] = (laneCounts[lane] ?? 0) + 1;
118
+ }
119
+ }
120
+
121
+ return {
122
+ schema: 'workgraph.tool.transport.boundary.v1',
123
+ protocolId: 'sidecar-mcp-execution-boundary-v1',
124
+ lanes: [...TOOL_TRANSPORT_LANES],
125
+ defaultPolicyGates: { ...DEFAULT_TRANSPORT_POLICY_GATES },
126
+ summary: {
127
+ total: rows.length,
128
+ laneCounts,
129
+ forbiddenDefault: rows.filter((row) => row.lanes.length === 1 && row.lanes[0] === 'forbidden').length,
130
+ },
131
+ rows,
132
+ rules: [
133
+ 'LLM HTTP transport is not a tool lane',
134
+ 'Mandatory CI uses builtin lane only',
135
+ 'Sidecar/MCP adapters must not mutate work/backlog.bvc directly',
136
+ 'Policy gates apply before transport selection',
137
+ ],
138
+ };
139
+ }
140
+
141
+ export function findToolTransportBoundaryRow(capability) {
142
+ const normalized = String(capability ?? '').trim();
143
+ return TOOL_TRANSPORT_BOUNDARY_ROWS.find((row) => row.capability === normalized) ?? null;
144
+ }
145
+
146
+ export function resolveToolCapabilityRequest(request = {}, context = {}) {
147
+ const capability = String(request.capability ?? '').trim();
148
+ const row = findToolTransportBoundaryRow(capability);
149
+
150
+ if (!row) {
151
+ return {
152
+ schema: 'workgraph.tool.capability.request.v1',
153
+ capability,
154
+ allowed: false,
155
+ allowedLanes: [],
156
+ effectivePolicy: mergeTransportPolicy(request.policy, context.policy),
157
+ blockedReason: 'unknown_capability',
158
+ };
159
+ }
160
+
161
+ const effectivePolicy = mergeTransportPolicy(DEFAULT_TRANSPORT_POLICY_GATES, context.policy, request.policy);
162
+ const gate = evaluateTransportPolicyGate({ capability, row, targetFiles: request.targetFiles }, effectivePolicy);
163
+
164
+ return {
165
+ schema: 'workgraph.tool.capability.request.v1',
166
+ capability,
167
+ allowed: gate.allowed,
168
+ allowedLanes: gate.allowed ? row.lanes : [],
169
+ effectivePolicy: gate.effectivePolicy,
170
+ blockedReason: gate.blockedReason,
171
+ requiresTargetFiles: row.requiresTargetFiles,
172
+ transportHint: request.transportHint ?? null,
173
+ };
174
+ }
175
+
176
+ export function evaluateTransportPolicyGate(request = {}, policy = {}) {
177
+ const row = request.row ?? findToolTransportBoundaryRow(request.capability);
178
+ const effectivePolicy = mergeTransportPolicy(DEFAULT_TRANSPORT_POLICY_GATES, policy);
179
+
180
+ if (!row) {
181
+ return {
182
+ allowed: false,
183
+ blockedReason: 'unknown_capability',
184
+ effectivePolicy,
185
+ };
186
+ }
187
+
188
+ if (row.lanes.length === 1 && row.lanes[0] === 'forbidden') {
189
+ return {
190
+ allowed: false,
191
+ blockedReason: 'forbidden_by_default',
192
+ effectivePolicy,
193
+ };
194
+ }
195
+
196
+ if (row.requiresShell && effectivePolicy.allowShell !== true) {
197
+ return {
198
+ allowed: false,
199
+ blockedReason: 'shell_not_allowed',
200
+ effectivePolicy,
201
+ };
202
+ }
203
+
204
+ if (row.requiresNetwork && effectivePolicy.allowNetwork !== true) {
205
+ return {
206
+ allowed: false,
207
+ blockedReason: 'network_not_allowed',
208
+ effectivePolicy,
209
+ };
210
+ }
211
+
212
+ if (row.requiresFileWrite && effectivePolicy.allowFileWrite !== true) {
213
+ return {
214
+ allowed: false,
215
+ blockedReason: 'file_write_not_allowed',
216
+ effectivePolicy,
217
+ };
218
+ }
219
+
220
+ if (row.requiresTargetFiles && effectivePolicy.requireTargetFilesAllowlist !== false) {
221
+ const targetFiles = request.targetFiles ?? policy.targetFiles ?? [];
222
+ if (!Array.isArray(targetFiles) || targetFiles.length === 0) {
223
+ return {
224
+ allowed: false,
225
+ blockedReason: 'target_files_required',
226
+ effectivePolicy,
227
+ };
228
+ }
229
+ }
230
+
231
+ return {
232
+ allowed: true,
233
+ blockedReason: null,
234
+ effectivePolicy,
235
+ };
236
+ }
237
+
238
+ export function redactTransportSecrets(payload) {
239
+ if (payload === null || payload === undefined) {
240
+ return payload;
241
+ }
242
+
243
+ if (typeof payload === 'string') {
244
+ return redactSecretString(payload);
245
+ }
246
+
247
+ if (Array.isArray(payload)) {
248
+ return payload.map((entry) => redactTransportSecrets(entry));
249
+ }
250
+
251
+ if (typeof payload === 'object') {
252
+ const redacted = {};
253
+ for (const [key, value] of Object.entries(payload)) {
254
+ if (/secret|token|password|authorization|api[_-]?key/iu.test(key)) {
255
+ redacted[key] = '[REDACTED]';
256
+ continue;
257
+ }
258
+ redacted[key] = redactTransportSecrets(value);
259
+ }
260
+ return redacted;
261
+ }
262
+
263
+ return payload;
264
+ }
265
+
266
+ function mergeTransportPolicy(...policies) {
267
+ return {
268
+ ...DEFAULT_TRANSPORT_POLICY_GATES,
269
+ ...policies.filter(Boolean).reduce((merged, policy) => ({ ...merged, ...policy }), {}),
270
+ };
271
+ }
272
+
273
+ function redactSecretString(value) {
274
+ let next = String(value);
275
+ for (const pattern of SECRET_REDACTION_PATTERNS) {
276
+ next = next.replace(pattern, '[REDACTED]');
277
+ }
278
+ return next;
279
+ }
280
+
281
+ export const ROLE_CHAIN_PROFILES_V1 = {
282
+ product_architect: { mode: 'dry-run', allowFileWrite: false, allowShell: false, focus: 'planning' },
283
+ feature_engineer: { mode: 'execute', allowFileWrite: true, allowShell: true, focus: 'implementation' },
284
+ domain_architect: { mode: 'dry-run', allowFileWrite: false, allowShell: false, focus: 'domain-bridge' },
285
+ agent_platform_architect: { mode: 'dry-run', allowFileWrite: false, allowShell: false, focus: 'runtime-audit' },
286
+ qa_automation: { mode: 'verify-only', allowFileWrite: false, allowShell: true, focus: 'verification' },
287
+ frontend_architect: { mode: 'execute', allowFileWrite: true, allowShell: false, focus: 'ui' },
288
+ };
289
+
290
+ export function resolveRoleChainHandoff(ownerRole, options = {}) {
291
+ const role = String(ownerRole ?? '').trim() || 'feature_engineer';
292
+ const profile = ROLE_CHAIN_PROFILES_V1[role] ?? ROLE_CHAIN_PROFILES_V1.feature_engineer;
293
+
294
+ return {
295
+ schema: 'role_chain.handoff.v1',
296
+ ownerRole: role,
297
+ roleProfile: profile.focus,
298
+ policy: {
299
+ mode: options.mode ?? profile.mode,
300
+ allowFileWrite: options.allowFileWrite ?? profile.allowFileWrite,
301
+ allowShell: options.allowShell ?? profile.allowShell,
302
+ allowNetwork: false,
303
+ timeoutMs: options.timeoutMs ?? 0,
304
+ },
305
+ providerHints: {
306
+ role,
307
+ roleProfile: profile.focus,
308
+ deterministic: profile.mode === 'dry-run' || profile.mode === 'verify-only',
309
+ },
310
+ };
311
+ }
312
+
313
+ export const PROMPT_EVAL_WORKGRAPH_FIXTURES_V1 = [
314
+ {
315
+ id: 'claim-no-eligible',
316
+ tier: 'optional-llm',
317
+ failureClass: 'model_failure',
318
+ description: 'Empty ready queue — agent must stop without inventing a task id',
319
+ allowedTools: ['workGraph.claimNext', 'workGraph.buildSnapshot'],
320
+ expectedKeywords: ['no claimable', 'no eligible', 'stop'],
321
+ },
322
+ {
323
+ id: 'policy-denial-dry-run',
324
+ tier: 'mandatory-deterministic',
325
+ failureClass: 'code_failure',
326
+ description: 'Local runner rejects non-dry-run policy — covered by agentWorkerLocalRunner.test.mjs',
327
+ allowedTools: ['worker.runLocalWorker'],
328
+ expectedKeywords: ['unsupported local runner mode', 'failed'],
329
+ },
330
+ {
331
+ id: 'trace-gate-without-evidence',
332
+ tier: 'mandatory-deterministic',
333
+ failureClass: 'code_failure',
334
+ description: 'transitionStatus to done without evidence — workGraphRuntime policy',
335
+ allowedTools: ['workGraph.transitionStatus'],
336
+ expectedKeywords: ['cannot mark done without evidence'],
337
+ },
338
+ {
339
+ id: 'blocked-onebase-go-preflight',
340
+ tier: 'optional-env',
341
+ failureClass: 'env_blocker',
342
+ description: 'OneBase go version missing — blocked evidence not failed verify',
343
+ allowedTools: ['verification.buildVerificationSummary'],
344
+ expectedKeywords: ['blocked', 'go version', 'preflight'],
345
+ },
346
+ {
347
+ id: 'worker-dry-run-verify-proposal',
348
+ tier: 'mandatory-deterministic',
349
+ failureClass: null,
350
+ description: 'Dry-run worker proposes verify transition — agentWorkerLiveLoop.test.mjs',
351
+ allowedTools: ['worker.runAgentWorkerLiveLoop'],
352
+ expectedKeywords: ['verify', 'succeeded', 'dry-run'],
353
+ },
354
+ {
355
+ id: 'loop-hint-repeat-tool',
356
+ tier: 'optional-llm',
357
+ failureClass: 'model_failure',
358
+ description: 'Repeated identical tool call should surface LOOP_HINT (defer port from ioHasC orchestrator)',
359
+ allowedTools: ['worker.runLocalWorker'],
360
+ expectedKeywords: ['LOOP_HINT', 'loopAborted'],
361
+ },
362
+ ];
363
+
364
+ export function buildPromptEvalWorkGraphFixtureCatalog() {
365
+ const fixtures = [...PROMPT_EVAL_WORKGRAPH_FIXTURES_V1].sort((left, right) => compareText(left.id, right.id));
366
+ return {
367
+ schema: 'prompt-eval.workgraph.fixtures.v1',
368
+ mandatoryCount: fixtures.filter((fixture) => fixture.tier === 'mandatory-deterministic').length,
369
+ optionalCount: fixtures.filter((fixture) => fixture.tier !== 'mandatory-deterministic').length,
370
+ fixtures,
371
+ };
372
+ }
@@ -0,0 +1,195 @@
1
+ import {
2
+ evaluateTransportPolicyGate,
3
+ findToolTransportBoundaryRow,
4
+ redactTransportSecrets,
5
+ resolveToolCapabilityRequest,
6
+ } from './workGraphToolSurfaceAudit.mjs';
7
+
8
+ export const TOOL_TRANSPORT_INVOKE_SCHEMA = 'workgraph.tool.transport.invoke.v1';
9
+
10
+ const LANE_PRIORITY = ['builtin', 'sidecar', 'mcp'];
11
+
12
+ export function selectTransportLane(resolved, preferredLane = null) {
13
+ const allowedLanes = resolved?.allowedLanes ?? [];
14
+ if (allowedLanes.length === 0) {
15
+ return null;
16
+ }
17
+
18
+ const preferred = String(preferredLane ?? resolved?.transportHint ?? '').trim();
19
+ if (preferred && allowedLanes.includes(preferred)) {
20
+ return preferred;
21
+ }
22
+
23
+ for (const lane of LANE_PRIORITY) {
24
+ if (allowedLanes.includes(lane)) {
25
+ return lane;
26
+ }
27
+ }
28
+
29
+ return allowedLanes[0] ?? null;
30
+ }
31
+
32
+ export function createBuiltinTransportHandlers(handlers = {}) {
33
+ return {
34
+ lane: 'builtin',
35
+ async invoke(call) {
36
+ const handler = handlers[call.capability];
37
+ if (typeof handler !== 'function') {
38
+ return {
39
+ ok: false,
40
+ error: 'builtin_handler_missing',
41
+ evidence: { capability: call.capability, lane: 'builtin' },
42
+ };
43
+ }
44
+
45
+ const result = await handler(call);
46
+ return {
47
+ ok: result?.ok !== false,
48
+ result: result?.result ?? result,
49
+ evidence: result?.evidence ?? { capability: call.capability, lane: 'builtin' },
50
+ };
51
+ },
52
+ };
53
+ }
54
+
55
+ export function createMockSidecarTransport(options = {}) {
56
+ const invoke = options.invoke ?? (async (call) => ({
57
+ ok: true,
58
+ result: { proxied: true, capability: call.capability },
59
+ evidence: {
60
+ capability: call.capability,
61
+ lane: 'sidecar',
62
+ summary: options.summary ?? 'sidecar proxy invoke',
63
+ },
64
+ }));
65
+
66
+ return {
67
+ lane: 'sidecar',
68
+ invoke,
69
+ };
70
+ }
71
+
72
+ export function createMockMcpTransport(options = {}) {
73
+ const invoke = options.invoke ?? (async (call) => ({
74
+ ok: true,
75
+ result: { mcp: true, capability: call.capability },
76
+ evidence: {
77
+ capability: call.capability,
78
+ lane: 'mcp',
79
+ summary: options.summary ?? 'mcp tool invoke',
80
+ authorization: options.includeSecrets ? 'Bearer sk-testsecret123456' : undefined,
81
+ },
82
+ }));
83
+
84
+ return {
85
+ lane: 'mcp',
86
+ invoke,
87
+ };
88
+ }
89
+
90
+ export function buildDefaultTransportRegistry(options = {}) {
91
+ const builtinHandlers = options.builtinHandlers ?? {};
92
+ return {
93
+ builtin: createBuiltinTransportHandlers(builtinHandlers),
94
+ sidecar: options.sidecarTransport ?? null,
95
+ mcp: options.mcpTransport ?? null,
96
+ };
97
+ }
98
+
99
+ export async function invokeToolCapability(request = {}, options = {}) {
100
+ const capability = String(request.capability ?? '').trim();
101
+ const targetFiles = request.targetFiles ?? options.targetFiles ?? [];
102
+ const resolved = resolveToolCapabilityRequest(
103
+ {
104
+ ...request,
105
+ capability,
106
+ targetFiles,
107
+ },
108
+ {
109
+ policy: {
110
+ ...(options.policy ?? {}),
111
+ targetFiles,
112
+ },
113
+ },
114
+ );
115
+
116
+ if (!resolved.allowed) {
117
+ return {
118
+ schema: TOOL_TRANSPORT_INVOKE_SCHEMA,
119
+ ok: false,
120
+ capability,
121
+ lane: null,
122
+ blockedReason: resolved.blockedReason ?? 'capability_denied',
123
+ result: null,
124
+ evidence: redactTransportSecrets({
125
+ capability,
126
+ blockedReason: resolved.blockedReason ?? 'capability_denied',
127
+ }),
128
+ };
129
+ }
130
+
131
+ const lane = selectTransportLane(resolved, request.transportHint ?? options.lane);
132
+ if (!lane || !resolved.allowedLanes.includes(lane)) {
133
+ return {
134
+ schema: TOOL_TRANSPORT_INVOKE_SCHEMA,
135
+ ok: false,
136
+ capability,
137
+ lane: lane ?? null,
138
+ blockedReason: 'lane_not_allowed',
139
+ result: null,
140
+ evidence: redactTransportSecrets({ capability, blockedReason: 'lane_not_allowed' }),
141
+ };
142
+ }
143
+
144
+ const row = findToolTransportBoundaryRow(capability);
145
+ const gate = evaluateTransportPolicyGate(
146
+ { capability, row, targetFiles },
147
+ resolved.effectivePolicy,
148
+ );
149
+
150
+ if (!gate.allowed) {
151
+ return {
152
+ schema: TOOL_TRANSPORT_INVOKE_SCHEMA,
153
+ ok: false,
154
+ capability,
155
+ lane,
156
+ blockedReason: gate.blockedReason ?? 'policy_denied',
157
+ result: null,
158
+ evidence: redactTransportSecrets({ capability, blockedReason: gate.blockedReason }),
159
+ };
160
+ }
161
+
162
+ const transports = options.transports ?? buildDefaultTransportRegistry(options);
163
+ const transport = transports[lane];
164
+ if (!transport || typeof transport.invoke !== 'function') {
165
+ return {
166
+ schema: TOOL_TRANSPORT_INVOKE_SCHEMA,
167
+ ok: false,
168
+ capability,
169
+ lane,
170
+ blockedReason: 'transport_not_configured',
171
+ result: null,
172
+ evidence: redactTransportSecrets({ capability, lane, blockedReason: 'transport_not_configured' }),
173
+ };
174
+ }
175
+
176
+ const startedAt = Date.now();
177
+ const transportResult = await transport.invoke({
178
+ capability,
179
+ args: request.args ?? {},
180
+ policy: resolved.effectivePolicy,
181
+ targetFiles,
182
+ timeoutMs: resolved.effectivePolicy.defaultTimeoutMs,
183
+ });
184
+
185
+ return {
186
+ schema: TOOL_TRANSPORT_INVOKE_SCHEMA,
187
+ ok: transportResult.ok !== false,
188
+ capability,
189
+ lane,
190
+ blockedReason: transportResult.ok === false ? (transportResult.error ?? 'transport_failed') : null,
191
+ result: redactTransportSecrets(transportResult.result ?? null),
192
+ evidence: redactTransportSecrets(transportResult.evidence ?? transportResult),
193
+ durationMs: Date.now() - startedAt,
194
+ };
195
+ }