@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,145 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+
5
+ const DEFAULT_TIMEOUT_MS = 120_000;
6
+
7
+ export function resolveOnebaseCliBinary(env = process.env, options = {}) {
8
+ const fromEnv = String(env.ONEBASE_CLI ?? '').trim();
9
+ if (fromEnv !== '') {
10
+ return fromEnv;
11
+ }
12
+
13
+ const repoRoot = options.repoRoot ?? process.cwd();
14
+ const portableWin = resolve(repoRoot, '../onebase/onebase.exe');
15
+ const portableUnix = resolve(repoRoot, '../onebase/onebase');
16
+ if (process.platform === 'win32' && existsSync(portableWin)) {
17
+ return portableWin;
18
+ }
19
+ if (existsSync(portableUnix)) {
20
+ return portableUnix;
21
+ }
22
+
23
+ return 'onebase';
24
+ }
25
+
26
+ export function resolveDefaultOnebaseProjectRoot(options = {}) {
27
+ const fromEnv = String(options.env?.ONEBASE_PROJECT_ROOT ?? process.env.ONEBASE_PROJECT_ROOT ?? '').trim();
28
+ if (fromEnv !== '') {
29
+ return resolve(fromEnv);
30
+ }
31
+
32
+ if (options.projectRoot) {
33
+ return resolve(String(options.projectRoot));
34
+ }
35
+
36
+ return resolve(options.repoRoot ?? process.cwd(), '../onebase/examples/trade');
37
+ }
38
+
39
+ export function buildOnebaseProjectArgs(projectRoot) {
40
+ const root = String(projectRoot ?? '').trim();
41
+ return root === '' ? [] : ['--project', root];
42
+ }
43
+
44
+ export function runOnebaseCli(subcommand, extraArgs = [], options = {}) {
45
+ const spawnImpl = options.spawnSyncImpl ?? spawnSync;
46
+ const binary = resolveOnebaseCliBinary(options.env, { repoRoot: options.repoRoot });
47
+ const projectRoot = options.projectRoot ?? options.cwd;
48
+ const args = [
49
+ subcommand,
50
+ ...extraArgs,
51
+ ...buildOnebaseProjectArgs(projectRoot),
52
+ ];
53
+ const command = `${binary} ${args.join(' ')}`;
54
+
55
+ let spawnResult;
56
+ try {
57
+ spawnResult = spawnImpl(binary, args, {
58
+ cwd: options.cwd ?? projectRoot,
59
+ env: options.env ?? process.env,
60
+ encoding: 'utf8',
61
+ shell: false,
62
+ timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
63
+ });
64
+ } catch (error) {
65
+ const message = error instanceof Error ? error.message : String(error);
66
+ return {
67
+ ok: false,
68
+ exitCode: 1,
69
+ stdout: '',
70
+ stderr: message,
71
+ command,
72
+ args,
73
+ failureClass: message.includes('ENOENT') ? 'cli_missing' : 'cli_error',
74
+ message,
75
+ };
76
+ }
77
+
78
+ const exitCode = spawnResult.status ?? 1;
79
+ const stdout = String(spawnResult.stdout ?? '');
80
+ const stderr = String(spawnResult.stderr ?? '');
81
+ const combined = `${stdout}\n${stderr}`.toLowerCase();
82
+
83
+ if (spawnResult.error) {
84
+ const message = spawnResult.error.message;
85
+ return {
86
+ ok: false,
87
+ exitCode,
88
+ stdout,
89
+ stderr,
90
+ command,
91
+ args,
92
+ failureClass: message.includes('ENOENT') ? 'cli_missing' : 'cli_error',
93
+ message,
94
+ };
95
+ }
96
+
97
+ if (
98
+ exitCode !== 0
99
+ && (combined.includes('unknown command')
100
+ || combined.includes('not found')
101
+ || combined.includes('no such command'))
102
+ ) {
103
+ return {
104
+ ok: false,
105
+ exitCode,
106
+ stdout,
107
+ stderr,
108
+ command,
109
+ args,
110
+ failureClass: 'cli_command_unavailable',
111
+ message: `OneBase CLI subcommand "${subcommand}" is not available in this onebase build`,
112
+ };
113
+ }
114
+
115
+ return {
116
+ ok: exitCode === 0,
117
+ exitCode,
118
+ stdout,
119
+ stderr,
120
+ command,
121
+ args,
122
+ failureClass: exitCode === 0 ? undefined : 'cli_error',
123
+ message: exitCode === 0 ? undefined : stderr.trim() || stdout.trim() || `exit ${exitCode}`,
124
+ };
125
+ }
126
+
127
+ export function runOnebaseCheck(options = {}) {
128
+ return runOnebaseCli('check', [], options);
129
+ }
130
+
131
+ export function runOnebaseDescribeJson(options = {}) {
132
+ return runOnebaseCli('describe', ['--json'], options);
133
+ }
134
+
135
+ export function formatOnebaseCliResult(result) {
136
+ return JSON.stringify({
137
+ ok: result.ok,
138
+ exitCode: result.exitCode,
139
+ command: result.command,
140
+ failureClass: result.failureClass ?? null,
141
+ message: result.message ?? null,
142
+ stdout: result.stdout,
143
+ stderr: result.stderr,
144
+ }, null, 2);
145
+ }
@@ -0,0 +1,98 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const scriptDir = fileURLToPath(new URL('.', import.meta.url));
6
+ export const DEFAULT_ONEBASE_ROOT = path.resolve(scriptDir, '../../onebase');
7
+
8
+ /**
9
+ * Static cross-repo checks mirroring ../onebase/internal/project/trade_gross_profit_test.go.
10
+ * Does not replace go test ./...; validates artifact content when Go is unavailable.
11
+ *
12
+ * @param {string} [onebaseRoot]
13
+ */
14
+ export function verifyOnebaseGrossProfitWarehouseArtifacts(onebaseRoot = DEFAULT_ONEBASE_ROOT) {
15
+ const failures = [];
16
+ const checkedFiles = [];
17
+
18
+ const registerPath = path.join(onebaseRoot, 'examples/trade/registers/валовая_прибыль.yaml');
19
+ const postingPath = path.join(onebaseRoot, 'examples/trade/src/реализациятоваров.posting.os');
20
+ const reportPath = path.join(onebaseRoot, 'examples/trade/reports/валовая_прибыль.yaml');
21
+ const kpiPath = path.join(onebaseRoot, 'examples/trade/widgets/валовая_прибыль_kpi.yaml');
22
+
23
+ const register = readText(registerPath, failures, checkedFiles);
24
+ const posting = readText(postingPath, failures, checkedFiles);
25
+ const report = readText(reportPath, failures, checkedFiles);
26
+ const kpi = readText(kpiPath, failures, checkedFiles);
27
+
28
+ if (register) {
29
+ if (!hasYamlField(register, 'Номенклатура', 'reference:Номенклатура')) {
30
+ failures.push('register must keep Номенклатура dimension');
31
+ }
32
+ if (!hasYamlField(register, 'Склад', 'reference:Склад')) {
33
+ failures.push('register must include Склад dimension');
34
+ }
35
+ }
36
+
37
+ if (report) {
38
+ if (!hasReportParam(report, 'Склад', 'reference:Склад')) {
39
+ failures.push('report must expose Склад filter');
40
+ }
41
+ if (!report.includes('СГРУППИРОВАТЬ ПО Номенклатура, Склад')) {
42
+ failures.push('report must group by Номенклатура and Склад');
43
+ }
44
+ if (!report.includes('Склад = &Склад')) {
45
+ failures.push('report must filter by Склад');
46
+ }
47
+ }
48
+
49
+ if (kpi) {
50
+ if (kpi.includes('СГРУППИРОВАТЬ') || kpi.includes('Склад')) {
51
+ failures.push('gross-profit KPI must remain a total query');
52
+ }
53
+ }
54
+
55
+ if (posting && !posting.includes('ДвВП.Склад = this.Склад')) {
56
+ failures.push('РеализацияТоваров gross-profit movement must set Склад');
57
+ }
58
+
59
+ const testPath = path.join(onebaseRoot, 'internal/project/trade_gross_profit_test.go');
60
+ const testSource = readText(testPath, failures, checkedFiles);
61
+ if (testSource && !testSource.includes('TestTradeGrossProfitWarehouseDimension')) {
62
+ failures.push('targeted trade_gross_profit_test.go must include warehouse dimension test');
63
+ }
64
+
65
+ return {
66
+ ok: failures.length === 0,
67
+ failures,
68
+ checkedFiles,
69
+ onebaseRoot,
70
+ };
71
+ }
72
+
73
+ /** @param {string} filePath @param {string[]} failures @param {string[]} checkedFiles */
74
+ function readText(filePath, failures, checkedFiles) {
75
+ checkedFiles.push(filePath);
76
+ try {
77
+ return fs.readFileSync(filePath, 'utf8');
78
+ } catch (error) {
79
+ failures.push(`missing or unreadable file: ${filePath} (${error.message})`);
80
+ return null;
81
+ }
82
+ }
83
+
84
+ /** @param {string} yaml @param {string} name @param {string} type */
85
+ function hasYamlField(yaml, name, type) {
86
+ const block = yaml.match(/dimensions:[\s\S]*?(?=\nresources:|\n[a-z_]+:|$)/i);
87
+ if (!block) return false;
88
+ const lines = block[0];
89
+ return lines.includes(`name: ${name}`) && lines.includes(`type: ${type}`);
90
+ }
91
+
92
+ /** @param {string} yaml @param {string} name @param {string} type */
93
+ function hasReportParam(yaml, name, type) {
94
+ const block = yaml.match(/params:[\s\S]*?(?=\nquery:|$)/i);
95
+ if (!block) return false;
96
+ const lines = block[0];
97
+ return lines.includes(`name: ${name}`) && lines.includes(`type: ${type}`);
98
+ }
@@ -0,0 +1,88 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+
4
+ import { buildOneBaseMcpParityMatrix } from './onebaseWorkItemTemplate.mjs';
5
+ import {
6
+ probeOnebaseCliCapabilities,
7
+ resolveDefaultCapabilitiesPath,
8
+ } from './onebaseCliCapabilityProbe.mjs';
9
+
10
+ const CAPABILITY_TO_CLI = {
11
+ metadata_scan: null,
12
+ describe_config: 'describe',
13
+ check_config: 'check',
14
+ ai_guide: 'ai-guide',
15
+ read_config_file: null,
16
+ rest_read: null,
17
+ dev_health: null,
18
+ deterministic_verify: null,
19
+ };
20
+
21
+ export function attachCliAvailabilityToParityRows(rows, probe) {
22
+ const commandMap = probe?.commands ?? {};
23
+
24
+ return rows.map((row) => {
25
+ const cliCommand = CAPABILITY_TO_CLI[row.capability] ?? null;
26
+ if (!cliCommand) {
27
+ return { ...row, cliAvailable: null };
28
+ }
29
+
30
+ return {
31
+ ...row,
32
+ cliAvailable: Boolean(commandMap[cliCommand]),
33
+ cliCommand,
34
+ };
35
+ });
36
+ }
37
+
38
+ export function buildOnebaseParityEvidencePayload(probe, options = {}) {
39
+ const baseMatrix = buildOneBaseMcpParityMatrix();
40
+ const rows = attachCliAvailabilityToParityRows(baseMatrix.rows, probe);
41
+
42
+ return {
43
+ schema: 'onebase.parity-evidence.v1',
44
+ probedAt: probe.probedAt,
45
+ binary: probe.binary,
46
+ cliProbe: probe,
47
+ parity: {
48
+ ...baseMatrix,
49
+ rows,
50
+ },
51
+ evidenceLine: formatParityEvidenceLine(probe),
52
+ projectRoot: options.projectRoot ?? null,
53
+ };
54
+ }
55
+
56
+ export function formatParityEvidenceLine(probe) {
57
+ const check = probe.commands?.check ? 'available' : 'missing';
58
+ const describe = probe.commands?.describe ? 'available' : 'missing';
59
+ const aiGuide = probe.commands?.['ai-guide'] ? 'available' : 'missing';
60
+ return `onebase CLI probe ${probe.probedAt}: binary=${probe.binary}; check=${check}; describe=${describe}; ai-guide=${aiGuide}`;
61
+ }
62
+
63
+ export async function syncOnebaseParityEvidence(options = {}) {
64
+ const repoRoot = options.repoRoot ?? process.cwd();
65
+ const probe = options.probe ?? probeOnebaseCliCapabilities({ repoRoot, ...options });
66
+ const payload = buildOnebaseParityEvidencePayload(probe, options);
67
+ const outputPath = resolve(repoRoot, options.outputPath ?? resolveDefaultCapabilitiesPath({ repoRoot }));
68
+
69
+ if (options.writeFile !== false) {
70
+ await writeFile(outputPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
71
+ }
72
+
73
+ return {
74
+ ok: true,
75
+ outputPath,
76
+ payload,
77
+ probe,
78
+ };
79
+ }
80
+
81
+ export function readParityRowsWithCachedProbe(probePayload) {
82
+ const baseMatrix = buildOneBaseMcpParityMatrix();
83
+ if (!probePayload?.cliProbe) {
84
+ return baseMatrix.rows;
85
+ }
86
+
87
+ return attachCliAvailabilityToParityRows(baseMatrix.rows, probePayload.cliProbe);
88
+ }
@@ -0,0 +1,257 @@
1
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
+ import { join, relative, resolve } from 'node:path';
3
+
4
+ import { resolveOnebaseMetadataScanRoot } from './onebaseCliCapabilityProbe.mjs';
5
+
6
+ export const ONEBASE_PVRG_METADATA_DIRS = ['catalogs', 'documents', 'registers', 'inforegs', 'reports', 'constants'];
7
+ const YAML_EXT = /\.(yaml|yml)$/iu;
8
+ const POSTING_OS_EXT = /\.posting\.os$/iu;
9
+
10
+ function normalizeRelPath(path) {
11
+ return String(path).replace(/\\/g, '/');
12
+ }
13
+
14
+ function inferOnebaseKindFromPath(relPath) {
15
+ const normalized = normalizeRelPath(relPath).toLowerCase();
16
+ for (const dir of ONEBASE_PVRG_METADATA_DIRS) {
17
+ if (normalized.includes(`/${dir}/`) || normalized.startsWith(`${dir}/`)) {
18
+ if (dir === 'catalogs') {
19
+ return 'catalog';
20
+ }
21
+ if (dir === 'documents') {
22
+ return 'document';
23
+ }
24
+ return dir.endsWith('s') ? dir.slice(0, -1) : dir;
25
+ }
26
+ }
27
+ return 'artifact';
28
+ }
29
+
30
+ export function parseOnebaseYamlSummary(text, relPath) {
31
+ const nameMatch = String(text ?? '').match(/^name:\s*(.+)$/mu);
32
+ if (!nameMatch) {
33
+ return null;
34
+ }
35
+
36
+ const name = nameMatch[1].trim();
37
+ const posting = /^posting:\s*true/mu.test(text);
38
+
39
+ return {
40
+ kind: inferOnebaseKindFromPath(relPath),
41
+ name,
42
+ posting,
43
+ yamlPath: normalizeRelPath(relPath),
44
+ };
45
+ }
46
+
47
+ function listFilesRecursive(dir, prefix = '') {
48
+ const entries = [];
49
+ if (!existsSync(dir)) {
50
+ return entries;
51
+ }
52
+
53
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
54
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
55
+ const abs = join(dir, entry.name);
56
+ if (entry.isDirectory()) {
57
+ entries.push(...listFilesRecursive(abs, rel));
58
+ continue;
59
+ }
60
+ entries.push({ abs, rel: normalizeRelPath(rel) });
61
+ }
62
+
63
+ return entries;
64
+ }
65
+
66
+ function findPostingScriptPath(projectRoot, documentName) {
67
+ const srcDir = join(projectRoot, 'src');
68
+ if (!existsSync(srcDir)) {
69
+ return null;
70
+ }
71
+
72
+ const normalizedDocumentName = String(documentName).toLowerCase();
73
+ for (const file of listFilesRecursive(srcDir, 'src')) {
74
+ if (!POSTING_OS_EXT.test(file.rel)) {
75
+ continue;
76
+ }
77
+
78
+ const baseName = file.rel.split('/').pop()?.replace(/\.posting\.os$/iu, '') ?? '';
79
+ if (baseName.toLowerCase() === normalizedDocumentName) {
80
+ return file.rel;
81
+ }
82
+ }
83
+
84
+ return null;
85
+ }
86
+
87
+ export function scanOnebaseMetadataSync(projectRoot, options = {}) {
88
+ const root = resolve(projectRoot ?? process.cwd());
89
+ if (!existsSync(root)) {
90
+ return [];
91
+ }
92
+
93
+ const entries = [];
94
+ for (const file of listFilesRecursive(root)) {
95
+ if (!YAML_EXT.test(file.rel)) {
96
+ continue;
97
+ }
98
+
99
+ if (!ONEBASE_PVRG_METADATA_DIRS.some((dir) => file.rel.includes(`/${dir}/`) || file.rel.startsWith(`${dir}/`))) {
100
+ continue;
101
+ }
102
+
103
+ const summary = parseOnebaseYamlSummary(readFileSync(file.abs, 'utf8'), file.rel);
104
+ if (!summary) {
105
+ continue;
106
+ }
107
+
108
+ const postingOsPath = summary.kind === 'document' && summary.posting
109
+ ? findPostingScriptPath(root, summary.name)
110
+ : null;
111
+
112
+ entries.push({
113
+ ...summary,
114
+ traceId: `onebase:${summary.kind}:${summary.name}`,
115
+ ...(postingOsPath ? { postingOsPath } : {}),
116
+ });
117
+ }
118
+
119
+ return entries.sort((left, right) => left.yamlPath.localeCompare(right.yamlPath, 'en', { sensitivity: 'variant' }));
120
+ }
121
+
122
+ export function buildOnebaseArtifactNodeId(kind, name) {
123
+ return `onebase:${kind}:${name}`;
124
+ }
125
+
126
+ export function buildOnebasePvrgGraphNodes(metadataEntries = [], options = {}) {
127
+ const nodeById = new Map();
128
+ const edges = [];
129
+ const edgeKeys = new Set();
130
+
131
+ function ensureNode(node) {
132
+ if (!nodeById.has(node.id)) {
133
+ nodeById.set(node.id, node);
134
+ }
135
+ return nodeById.get(node.id);
136
+ }
137
+
138
+ function addEdge(edge) {
139
+ const key = `${edge.from}->${edge.to}:${edge.type}`;
140
+ if (edgeKeys.has(key)) {
141
+ return;
142
+ }
143
+ edgeKeys.add(key);
144
+ edges.push(edge);
145
+ }
146
+
147
+ for (const entry of metadataEntries) {
148
+ const artifactNode = ensureNode({
149
+ id: buildOnebaseArtifactNodeId(entry.kind, entry.name),
150
+ kind: 'onebase_artifact',
151
+ onebaseKind: entry.kind,
152
+ title: entry.name,
153
+ subtitle: entry.kind,
154
+ path: entry.yamlPath,
155
+ traceId: entry.traceId,
156
+ posting: entry.posting === true,
157
+ });
158
+
159
+ if (entry.postingOsPath) {
160
+ const scriptNode = ensureNode({
161
+ id: buildOnebaseArtifactNodeId('posting_script', entry.name),
162
+ kind: 'onebase_artifact',
163
+ onebaseKind: 'posting_script',
164
+ title: `${entry.name}.posting`,
165
+ subtitle: 'posting_script',
166
+ path: entry.postingOsPath,
167
+ traceId: `onebase:posting_script:${entry.name}`,
168
+ posting: true,
169
+ });
170
+ addEdge({
171
+ from: artifactNode.id,
172
+ to: scriptNode.id,
173
+ type: 'onebase_posting',
174
+ });
175
+ }
176
+ }
177
+
178
+ const nodes = [...nodeById.values()].sort((left, right) => left.id.localeCompare(right.id, 'en', { sensitivity: 'variant' }));
179
+ const sortedEdges = edges.sort((left, right) =>
180
+ `${left.from}\0${left.to}\0${left.type}`.localeCompare(`${right.from}\0${right.to}\0${right.type}`, 'en', { sensitivity: 'variant' }),
181
+ );
182
+
183
+ return {
184
+ schema: 'onebase.pvrg_graph_nodes.v1',
185
+ projectRoot: options.projectRoot ? normalizeRelPath(relative(options.repoRoot ?? process.cwd(), options.projectRoot)) : null,
186
+ nodes,
187
+ edges: sortedEdges,
188
+ counts: {
189
+ nodes: nodes.length,
190
+ edges: sortedEdges.length,
191
+ documents: nodes.filter((node) => node.onebaseKind === 'document').length,
192
+ catalogs: nodes.filter((node) => node.onebaseKind === 'catalog').length,
193
+ postingScripts: nodes.filter((node) => node.onebaseKind === 'posting_script').length,
194
+ },
195
+ };
196
+ }
197
+
198
+ export function buildOnebasePvrgGraphFromProjectRoot(options = {}) {
199
+ const repoRoot = options.repoRoot ?? process.cwd();
200
+ const projectRoot = options.projectRoot ?? resolveOnebaseMetadataScanRoot({ repoRoot });
201
+ if (!projectRoot) {
202
+ return buildOnebasePvrgGraphNodes([], { repoRoot, projectRoot: null });
203
+ }
204
+
205
+ const metadataEntries = scanOnebaseMetadataSync(projectRoot);
206
+ return buildOnebasePvrgGraphNodes(metadataEntries, { repoRoot, projectRoot });
207
+ }
208
+
209
+ export function mergeOnebaseGraphIntoBlockL2Graph(l2Graph, onebaseGraph, options = {}) {
210
+ if (!onebaseGraph || onebaseGraph.nodes.length === 0) {
211
+ return l2Graph;
212
+ }
213
+
214
+ const containerId = options.containerId ?? 'container:onebase-domain';
215
+ const maxNodes = options.maxNodes ?? l2Graph.counts?.nodes ?? Number.MAX_SAFE_INTEGER;
216
+ const mergedNodes = [...l2Graph.nodes];
217
+ const mergedEdges = [...l2Graph.edges];
218
+ const visibleIds = new Set(mergedNodes.map((node) => node.id));
219
+
220
+ for (const node of onebaseGraph.nodes) {
221
+ if (mergedNodes.length >= maxNodes) {
222
+ break;
223
+ }
224
+ mergedNodes.push(node);
225
+ visibleIds.add(node.id);
226
+ mergedEdges.push({
227
+ from: containerId,
228
+ to: node.id,
229
+ type: 'hosts_onebase',
230
+ });
231
+ }
232
+
233
+ for (const edge of onebaseGraph.edges) {
234
+ if (visibleIds.has(edge.from) && visibleIds.has(edge.to)) {
235
+ mergedEdges.push(edge);
236
+ }
237
+ }
238
+
239
+ const hiddenCount = Math.max(0, (l2Graph.hiddenCount ?? 0) + Math.max(0, onebaseGraph.nodes.length - (maxNodes - l2Graph.nodes.length)));
240
+
241
+ return {
242
+ ...l2Graph,
243
+ nodes: mergedNodes,
244
+ edges: mergedEdges.sort((left, right) =>
245
+ `${left.from}\0${left.to}\0${left.type}`.localeCompare(`${right.from}\0${right.to}\0${right.type}`, 'en', { sensitivity: 'variant' }),
246
+ ),
247
+ onebaseMerged: true,
248
+ hiddenCount,
249
+ capped: hiddenCount > 0,
250
+ counts: {
251
+ ...l2Graph.counts,
252
+ nodes: mergedNodes.length,
253
+ edges: mergedEdges.length,
254
+ onebaseArtifacts: onebaseGraph.nodes.length,
255
+ },
256
+ };
257
+ }