@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,586 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { spawnSync } from 'node:child_process';
4
+
5
+ import {
6
+ DEFAULT_ONEBASE_ROOT,
7
+ verifyOnebaseGrossProfitWarehouseArtifacts,
8
+ } from './onebaseGrossProfitStaticVerify.mjs';
9
+ import { runOnebaseCheck, runOnebaseDescribeJson } from './onebaseCliRunner.mjs';
10
+ import { buildOnebaseRestEvidenceAdapterResult } from './onebaseRestEvidenceAdapter.mjs';
11
+ import { extractJsonYamlFacts } from './languageAdapters/jsonYamlAdapter.mjs';
12
+ import { extractOnebaseOsFacts } from './languageAdapters/onebaseOsAdapter.mjs';
13
+
14
+ export const ONEBASE_WORKER_TOOL_IDS = [
15
+ 'onebase.listMetadata',
16
+ 'onebase.readConfigFile',
17
+ 'onebase.staticVerify',
18
+ 'onebase.runVerificationCommand',
19
+ 'onebase.describeCli',
20
+ 'onebase.checkCli',
21
+ ];
22
+
23
+ export const ONEBASE_METADATA_DIRS = [
24
+ 'catalogs',
25
+ 'documents',
26
+ 'registers',
27
+ 'inforegs',
28
+ 'reports',
29
+ 'constants',
30
+ 'widgets',
31
+ ];
32
+
33
+ const YAML_EXT = /\.(yaml|yml)$/iu;
34
+ const MAX_READ_CHARS = 32_000;
35
+
36
+ export function resolveOnebaseProjectRoot(options = {}) {
37
+ const fromEnv = String(process.env.ONEBASE_PROJECT_ROOT ?? '').trim();
38
+ if (fromEnv !== '') {
39
+ return path.resolve(fromEnv);
40
+ }
41
+
42
+ if (options.onebaseRoot) {
43
+ return path.resolve(String(options.onebaseRoot));
44
+ }
45
+
46
+ return DEFAULT_ONEBASE_ROOT;
47
+ }
48
+
49
+ export function isOnebaseDomainTask(task) {
50
+ if (!task || typeof task !== 'object') {
51
+ return false;
52
+ }
53
+
54
+ const domainId = String(task.labels?.['domain.id'] ?? '').trim();
55
+ if (domainId === 'onebase') {
56
+ return true;
57
+ }
58
+
59
+ if (task.department === 'domain-onebase') {
60
+ return true;
61
+ }
62
+
63
+ const haystack = [
64
+ ...(task.checks ?? []),
65
+ ...(task.evidence ?? []),
66
+ task.nextAction ?? '',
67
+ ...(task.targetFiles ?? []),
68
+ ].join('\n').toLowerCase();
69
+
70
+ return haystack.includes('onebase')
71
+ || haystack.includes('verifyonebase')
72
+ || haystack.includes('test:optional:onebase');
73
+ }
74
+
75
+ export function resolveOnebaseAllowedTools(task) {
76
+ if (!isOnebaseDomainTask(task)) {
77
+ return [];
78
+ }
79
+
80
+ return [...ONEBASE_WORKER_TOOL_IDS];
81
+ }
82
+
83
+ export function executeOnebaseListMetadata(onebaseRoot = DEFAULT_ONEBASE_ROOT, options = {}) {
84
+ const root = path.resolve(onebaseRoot);
85
+ const entries = [];
86
+ const failures = [];
87
+
88
+ if (!fs.existsSync(root)) {
89
+ return {
90
+ ok: false,
91
+ toolId: 'onebase.listMetadata',
92
+ onebaseRoot: root,
93
+ entries: [],
94
+ summary: { total: 0, byKind: {} },
95
+ failures: [`onebase root not found: ${root}`],
96
+ };
97
+ }
98
+
99
+ for (const dirName of ONEBASE_METADATA_DIRS) {
100
+ const dirPath = path.join(root, dirName);
101
+ if (!fs.existsSync(dirPath)) {
102
+ continue;
103
+ }
104
+
105
+ collectMetadataEntries(dirPath, root, dirName, entries, failures, options);
106
+ }
107
+
108
+ entries.sort((left, right) => left.yamlPath.localeCompare(right.yamlPath, 'en'));
109
+
110
+ const byKind = {};
111
+ for (const entry of entries) {
112
+ byKind[entry.kind] = (byKind[entry.kind] ?? 0) + 1;
113
+ }
114
+
115
+ return {
116
+ ok: failures.length === 0,
117
+ toolId: 'onebase.listMetadata',
118
+ onebaseRoot: root,
119
+ entries,
120
+ summary: {
121
+ total: entries.length,
122
+ byKind,
123
+ },
124
+ failures,
125
+ };
126
+ }
127
+
128
+ export function executeOnebaseReadConfigFile(onebaseRoot, relativePath, options = {}) {
129
+ const root = path.resolve(onebaseRoot);
130
+ const normalized = normalizeBoundedRelativePath(relativePath);
131
+
132
+ if (!normalized.ok) {
133
+ return {
134
+ ok: false,
135
+ toolId: 'onebase.readConfigFile',
136
+ relativePath: String(relativePath ?? ''),
137
+ text: '',
138
+ truncated: false,
139
+ facts: null,
140
+ error: normalized.error,
141
+ };
142
+ }
143
+
144
+ const absolutePath = path.join(root, normalized.relativePath);
145
+ if (!absolutePath.startsWith(root)) {
146
+ return {
147
+ ok: false,
148
+ toolId: 'onebase.readConfigFile',
149
+ relativePath: normalized.relativePath,
150
+ text: '',
151
+ truncated: false,
152
+ facts: null,
153
+ error: 'path escapes onebase root',
154
+ };
155
+ }
156
+
157
+ if (!fs.existsSync(absolutePath)) {
158
+ return {
159
+ ok: false,
160
+ toolId: 'onebase.readConfigFile',
161
+ relativePath: normalized.relativePath,
162
+ text: '',
163
+ truncated: false,
164
+ facts: null,
165
+ error: `file not found: ${normalized.relativePath}`,
166
+ };
167
+ }
168
+
169
+ const maxChars = options.maxChars ?? MAX_READ_CHARS;
170
+ const rawText = fs.readFileSync(absolutePath, 'utf8');
171
+ const truncated = rawText.length > maxChars;
172
+ const text = truncated ? rawText.slice(0, maxChars) : rawText;
173
+ const facts = buildArtifactFacts(normalized.relativePath, text);
174
+
175
+ return {
176
+ ok: true,
177
+ toolId: 'onebase.readConfigFile',
178
+ relativePath: normalized.relativePath,
179
+ text,
180
+ truncated,
181
+ facts,
182
+ error: null,
183
+ };
184
+ }
185
+
186
+ export function executeOnebaseStaticVerify(onebaseRoot = DEFAULT_ONEBASE_ROOT) {
187
+ const result = verifyOnebaseGrossProfitWarehouseArtifacts(onebaseRoot);
188
+
189
+ return {
190
+ ok: result.ok,
191
+ toolId: 'onebase.staticVerify',
192
+ onebaseRoot: result.onebaseRoot,
193
+ failures: result.failures,
194
+ checkedFiles: result.checkedFiles.map((filePath) => path.relative(result.onebaseRoot, filePath).replace(/\\/gu, '/')),
195
+ };
196
+ }
197
+
198
+ export function executeOnebaseVerificationCommand(options = {}) {
199
+ const policy = options.policy ?? {};
200
+ if (policy.allowShell !== true) {
201
+ return {
202
+ ok: false,
203
+ toolId: 'onebase.runVerificationCommand',
204
+ blocked: true,
205
+ reason: 'allowShell=false',
206
+ command: null,
207
+ exitCode: null,
208
+ stdout: '',
209
+ stderr: '',
210
+ };
211
+ }
212
+
213
+ const onebaseRoot = resolveOnebaseProjectRoot(options);
214
+ const command = options.command ?? 'go test ./...';
215
+ const spawnImpl = options.spawnSyncImpl ?? spawnSync;
216
+ const preflight = spawnImpl('go', ['version'], {
217
+ cwd: onebaseRoot,
218
+ encoding: 'utf8',
219
+ shell: process.platform === 'win32',
220
+ });
221
+
222
+ if (preflight.status !== 0) {
223
+ return {
224
+ ok: false,
225
+ toolId: 'onebase.runVerificationCommand',
226
+ blocked: false,
227
+ reason: 'go preflight failed',
228
+ command: 'go version',
229
+ exitCode: preflight.status ?? 1,
230
+ stdout: preflight.stdout ?? '',
231
+ stderr: preflight.stderr ?? '',
232
+ };
233
+ }
234
+
235
+ const result = spawnImpl(command, {
236
+ cwd: onebaseRoot,
237
+ encoding: 'utf8',
238
+ shell: true,
239
+ });
240
+
241
+ return {
242
+ ok: result.status === 0,
243
+ toolId: 'onebase.runVerificationCommand',
244
+ blocked: false,
245
+ reason: result.status === 0 ? null : 'verification command failed',
246
+ command,
247
+ exitCode: result.status ?? 1,
248
+ stdout: result.stdout ?? '',
249
+ stderr: result.stderr ?? '',
250
+ };
251
+ }
252
+
253
+ export function executeOnebaseDescribeCli(options = {}) {
254
+ const projectRoot = resolveOnebaseProjectRoot(options);
255
+ const cliResult = runOnebaseDescribeJson({
256
+ ...options,
257
+ projectRoot,
258
+ cwd: options.cwd ?? projectRoot,
259
+ });
260
+
261
+ const adapter = buildOnebaseRestEvidenceAdapterResult(
262
+ 'describe',
263
+ cliResult,
264
+ options.taskId ?? 'onebase-task',
265
+ options.evidenceOptions,
266
+ );
267
+
268
+ return {
269
+ ok: cliResult.ok === true && adapter.ok === true,
270
+ toolId: 'onebase.describeCli',
271
+ blocked: cliResult.failureClass === 'cli_missing' || cliResult.failureClass === 'cli_command_unavailable',
272
+ reason: cliResult.message ?? null,
273
+ command: cliResult.command,
274
+ exitCode: cliResult.exitCode,
275
+ stdout: cliResult.stdout,
276
+ stderr: cliResult.stderr,
277
+ failureClass: cliResult.failureClass ?? null,
278
+ evidenceRecords: adapter.records,
279
+ evidenceLines: adapter.legacyLines,
280
+ };
281
+ }
282
+
283
+ export function executeOnebaseCheckCli(options = {}) {
284
+ const projectRoot = resolveOnebaseProjectRoot(options);
285
+ const cliResult = runOnebaseCheck({
286
+ ...options,
287
+ projectRoot,
288
+ cwd: options.cwd ?? projectRoot,
289
+ });
290
+
291
+ const adapter = buildOnebaseRestEvidenceAdapterResult(
292
+ 'check',
293
+ cliResult,
294
+ options.taskId ?? 'onebase-task',
295
+ options.evidenceOptions,
296
+ );
297
+
298
+ return {
299
+ ok: cliResult.ok === true,
300
+ toolId: 'onebase.checkCli',
301
+ blocked: cliResult.failureClass === 'cli_missing' || cliResult.failureClass === 'cli_command_unavailable',
302
+ reason: cliResult.message ?? null,
303
+ command: cliResult.command,
304
+ exitCode: cliResult.exitCode,
305
+ stdout: cliResult.stdout,
306
+ stderr: cliResult.stderr,
307
+ failureClass: cliResult.failureClass ?? null,
308
+ evidenceRecords: adapter.records,
309
+ evidenceLines: adapter.legacyLines,
310
+ };
311
+ }
312
+
313
+ export function buildOnebaseWorkerEvidence(toolResult) {
314
+ if (!toolResult || typeof toolResult !== 'object') {
315
+ return {
316
+ kind: 'onebase_tool',
317
+ source: 'onebase-worker-tools',
318
+ result: 'failed',
319
+ summary: 'invalid tool result',
320
+ };
321
+ }
322
+
323
+ const toolId = toolResult.toolId ?? 'onebase.unknown';
324
+ const ok = toolResult.ok === true && toolResult.blocked !== true;
325
+
326
+ if (toolId === 'onebase.listMetadata') {
327
+ return {
328
+ kind: 'onebase_metadata',
329
+ source: 'onebase-worker-tools',
330
+ result: ok ? 'succeeded' : 'failed',
331
+ summary: `metadata entries=${toolResult.summary?.total ?? 0}`,
332
+ toolId,
333
+ details: toolResult.summary,
334
+ };
335
+ }
336
+
337
+ if (toolId === 'onebase.readConfigFile') {
338
+ return {
339
+ kind: 'onebase_artifact',
340
+ source: 'onebase-worker-tools',
341
+ result: ok ? 'succeeded' : 'failed',
342
+ summary: ok
343
+ ? `read ${toolResult.relativePath}${toolResult.truncated ? ' (truncated)' : ''}`
344
+ : (toolResult.error ?? 'read failed'),
345
+ toolId,
346
+ relativePath: toolResult.relativePath ?? null,
347
+ };
348
+ }
349
+
350
+ if (toolId === 'onebase.staticVerify') {
351
+ return {
352
+ kind: 'onebase_verify',
353
+ source: 'onebase-worker-tools',
354
+ result: ok ? 'succeeded' : 'failed',
355
+ summary: ok
356
+ ? `static verify passed (${toolResult.checkedFiles?.length ?? 0} files)`
357
+ : `static verify failed: ${(toolResult.failures ?? []).slice(0, 2).join('; ')}`,
358
+ toolId,
359
+ failures: toolResult.failures ?? [],
360
+ };
361
+ }
362
+
363
+ if (toolId === 'onebase.runVerificationCommand') {
364
+ if (toolResult.blocked) {
365
+ return {
366
+ kind: 'onebase_verify',
367
+ source: 'onebase-worker-tools',
368
+ result: 'blocked',
369
+ summary: `verification blocked (${toolResult.reason ?? 'policy'})`,
370
+ toolId,
371
+ };
372
+ }
373
+
374
+ return {
375
+ kind: 'onebase_verify',
376
+ source: 'onebase-worker-tools',
377
+ result: ok ? 'succeeded' : 'failed',
378
+ summary: ok
379
+ ? `verification command succeeded (${toolResult.command ?? 'go test'})`
380
+ : `verification command failed (${toolResult.command ?? 'go test'})`,
381
+ toolId,
382
+ exitCode: toolResult.exitCode ?? null,
383
+ };
384
+ }
385
+
386
+ if (toolId === 'onebase.describeCli' || toolId === 'onebase.checkCli') {
387
+ const summary = Array.isArray(toolResult.evidenceLines) && toolResult.evidenceLines.length > 0
388
+ ? toolResult.evidenceLines[0]
389
+ : `${toolId} ${ok ? 'ok' : 'failed'}`;
390
+
391
+ return {
392
+ kind: 'onebase_rest_evidence',
393
+ source: 'onebase-rest-evidence-adapter',
394
+ result: toolResult.blocked ? 'blocked' : (ok ? 'succeeded' : 'failed'),
395
+ summary,
396
+ toolId,
397
+ evidenceRecordIds: (toolResult.evidenceRecords ?? []).map((record) => record.id),
398
+ recordCount: toolResult.evidenceRecords?.length ?? 0,
399
+ };
400
+ }
401
+
402
+ return {
403
+ kind: 'onebase_tool',
404
+ source: 'onebase-worker-tools',
405
+ result: ok ? 'succeeded' : 'failed',
406
+ summary: `${toolId} ${ok ? 'ok' : 'failed'}`,
407
+ toolId,
408
+ };
409
+ }
410
+
411
+ export function executeOnebaseWorkerTool(toolId, args = {}, context = {}) {
412
+ const onebaseRoot = resolveOnebaseProjectRoot(context);
413
+
414
+ switch (toolId) {
415
+ case 'onebase.listMetadata':
416
+ return executeOnebaseListMetadata(onebaseRoot, context);
417
+ case 'onebase.readConfigFile':
418
+ return executeOnebaseReadConfigFile(onebaseRoot, args.relativePath, context);
419
+ case 'onebase.staticVerify':
420
+ return executeOnebaseStaticVerify(onebaseRoot);
421
+ case 'onebase.runVerificationCommand':
422
+ return executeOnebaseVerificationCommand({ ...context, policy: context.policy ?? {} });
423
+ case 'onebase.describeCli':
424
+ return executeOnebaseDescribeCli({ ...context, taskId: context.task?.id ?? context.taskId });
425
+ case 'onebase.checkCli':
426
+ return executeOnebaseCheckCli({ ...context, taskId: context.task?.id ?? context.taskId });
427
+ default:
428
+ return {
429
+ ok: false,
430
+ toolId,
431
+ error: `unknown onebase worker tool: ${toolId}`,
432
+ };
433
+ }
434
+ }
435
+
436
+ export function runOnebaseWorkerPreflight(task, options = {}) {
437
+ if (!isOnebaseDomainTask(task)) {
438
+ return { ok: true, skipped: true, evidence: [], toolResults: [] };
439
+ }
440
+
441
+ const onebaseRoot = resolveOnebaseProjectRoot(options);
442
+ const toolResults = [
443
+ executeOnebaseListMetadata(onebaseRoot, options),
444
+ executeOnebaseStaticVerify(onebaseRoot),
445
+ executeOnebaseDescribeCli({ ...options, taskId: task.id }),
446
+ executeOnebaseCheckCli({ ...options, taskId: task.id }),
447
+ executeOnebaseVerificationCommand({ ...options, policy: options.policy ?? { allowShell: false } }),
448
+ ];
449
+
450
+ const firstReadable = pickReadableOnebaseTarget(task, onebaseRoot);
451
+ if (firstReadable) {
452
+ toolResults.push(executeOnebaseReadConfigFile(onebaseRoot, firstReadable, options));
453
+ }
454
+
455
+ const evidence = toolResults.map((result) => buildOnebaseWorkerEvidence(result));
456
+ const ok = toolResults.every((result) => result.ok === true || result.blocked === true);
457
+
458
+ return {
459
+ ok,
460
+ skipped: false,
461
+ onebaseRoot,
462
+ evidence,
463
+ toolResults,
464
+ summary: {
465
+ metadataTotal: toolResults.find((result) => result.toolId === 'onebase.listMetadata')?.summary?.total ?? 0,
466
+ staticVerifyOk: toolResults.find((result) => result.toolId === 'onebase.staticVerify')?.ok === true,
467
+ verificationBlocked: toolResults.find((result) => result.toolId === 'onebase.runVerificationCommand')?.blocked === true,
468
+ },
469
+ };
470
+ }
471
+
472
+ function collectMetadataEntries(dirPath, root, dirName, entries, failures, options) {
473
+ let dirEntries;
474
+ try {
475
+ dirEntries = fs.readdirSync(dirPath, { withFileTypes: true });
476
+ } catch (error) {
477
+ failures.push(`failed to read directory ${path.relative(root, dirPath)}: ${error instanceof Error ? error.message : String(error)}`);
478
+ return;
479
+ }
480
+
481
+ for (const entry of dirEntries) {
482
+ const absolutePath = path.join(dirPath, entry.name);
483
+ if (entry.isDirectory()) {
484
+ collectMetadataEntries(absolutePath, root, dirName, entries, failures, options);
485
+ continue;
486
+ }
487
+
488
+ if (!YAML_EXT.test(entry.name)) {
489
+ continue;
490
+ }
491
+
492
+ const relativePath = path.relative(root, absolutePath).replace(/\\/gu, '/');
493
+ try {
494
+ const text = fs.readFileSync(absolutePath, 'utf8');
495
+ const facts = extractJsonYamlFacts(text, { filePath: relativePath, extension: path.extname(entry.name) });
496
+ const metadata = facts.domainMetadata ?? {};
497
+ entries.push({
498
+ yamlPath: relativePath,
499
+ kind: metadata.artifactKind === 'yaml' || !metadata.artifactKind
500
+ ? dirName.replace(/s$/u, '')
501
+ : metadata.artifactKind,
502
+ name: metadata.name ?? path.basename(entry.name, path.extname(entry.name)),
503
+ posting: metadata.posting ?? null,
504
+ fieldCount: metadata.fields?.length ?? 0,
505
+ });
506
+ } catch (error) {
507
+ failures.push(`failed to read ${relativePath}: ${error instanceof Error ? error.message : String(error)}`);
508
+ }
509
+ }
510
+ }
511
+
512
+ function normalizeBoundedRelativePath(relativePath) {
513
+ const raw = String(relativePath ?? '').trim().replace(/\\/gu, '/');
514
+ if (raw === '') {
515
+ return { ok: false, error: 'relativePath is required' };
516
+ }
517
+
518
+ if (path.isAbsolute(raw) || raw.includes('..')) {
519
+ return { ok: false, error: 'relativePath must stay inside onebase root' };
520
+ }
521
+
522
+ const normalized = raw.replace(/^\/+/u, '');
523
+ const lower = normalized.toLowerCase();
524
+
525
+ const inMetadataDir = ONEBASE_METADATA_DIRS.some((dirName) =>
526
+ lower === dirName || lower.startsWith(`${dirName}/`));
527
+ const inSrcOs = lower.startsWith('src/') && lower.endsWith('.os');
528
+ const inExamples = lower.startsWith('examples/');
529
+
530
+ if (!inMetadataDir && !inSrcOs && !inExamples) {
531
+ return { ok: false, error: 'relativePath must be under metadata dirs, src/*.os or examples/' };
532
+ }
533
+
534
+ return { ok: true, relativePath: normalized };
535
+ }
536
+
537
+ function buildArtifactFacts(relativePath, text) {
538
+ const lower = relativePath.toLowerCase();
539
+ if (lower.endsWith('.os')) {
540
+ return extractOnebaseOsFacts(text, { filePath: relativePath });
541
+ }
542
+
543
+ return extractJsonYamlFacts(text, {
544
+ filePath: relativePath,
545
+ extension: path.extname(relativePath),
546
+ });
547
+ }
548
+
549
+ function pickReadableOnebaseTarget(task, onebaseRoot) {
550
+ for (const target of task.targetFiles ?? []) {
551
+ const normalized = String(target).replace(/\\/gu, '/');
552
+ if (!normalized.includes('onebase')) {
553
+ continue;
554
+ }
555
+
556
+ const marker = 'onebase/';
557
+ const index = normalized.toLowerCase().indexOf(marker);
558
+ if (index === -1) {
559
+ continue;
560
+ }
561
+
562
+ const relativePath = normalized.slice(index + marker.length);
563
+ const bounded = normalizeBoundedRelativePath(relativePath);
564
+ if (!bounded.ok) {
565
+ continue;
566
+ }
567
+
568
+ const absolutePath = path.join(onebaseRoot, bounded.relativePath);
569
+ if (fs.existsSync(absolutePath)) {
570
+ return bounded.relativePath;
571
+ }
572
+ }
573
+
574
+ const defaultCandidates = [
575
+ 'examples/trade/registers/валовая_прибыль.yaml',
576
+ 'examples/trade/src/реализациятоваров.posting.os',
577
+ ];
578
+
579
+ for (const candidate of defaultCandidates) {
580
+ if (fs.existsSync(path.join(onebaseRoot, candidate))) {
581
+ return candidate;
582
+ }
583
+ }
584
+
585
+ return null;
586
+ }
@@ -0,0 +1,102 @@
1
+ import { classifyWorkItemBlock } from './architectureSnapshot.mjs';
2
+ import { buildIntentHierarchySnapshot } from './intentHierarchy.mjs';
3
+ import { buildOperatorDashboardSnapshot } from './workGraphRuntime.mjs';
4
+ import { buildRunnerQueueProjectionFromItems } from './workGraphRunnerQueueProjection.mjs';
5
+ import { buildKanbanBoardProjection } from './kanbanBoardProjection.mjs';
6
+ import {
7
+ buildCycleSliceProjection,
8
+ DEFAULT_DONE_ARCHIVE_CAP,
9
+ PHASE_EPIC_PATTERN,
10
+ } from './workGraphCycleSlice.mjs';
11
+
12
+ const compareText = (left, right) => String(left).localeCompare(String(right), 'en', { sensitivity: 'variant' });
13
+
14
+ export const OPERATOR_SHELL_SCHEMA = 'operator-shell.snapshot.v2';
15
+ export const STARTUP_BUDGET_V1 = {
16
+ maxInitialFetchMs: 800,
17
+ lazyViews: ['graph', 'architecture', 'schematic'],
18
+ deferUntilVisible: true,
19
+ };
20
+
21
+ export function buildSemanticCrossHighlightMap(items) {
22
+ return [...items]
23
+ .sort((left, right) => compareText(left.id, right.id))
24
+ .map((item) => ({
25
+ workId: item.id,
26
+ title: item.title,
27
+ status: item.status,
28
+ architectureBlockId: classifyWorkItemBlock(item),
29
+ intentPath: item.labels?.['intent.path'] ?? null,
30
+ targetFiles: [...(item.targetFiles ?? [])],
31
+ }));
32
+ }
33
+
34
+ export function buildPhaseRoadmap(items) {
35
+ return [...items]
36
+ .filter((item) => PHASE_EPIC_PATTERN.test(item.id))
37
+ .sort((left, right) => compareText(left.id, right.id))
38
+ .map((item) => ({
39
+ id: item.id,
40
+ title: item.title,
41
+ status: item.status,
42
+ nextAction: item.nextAction,
43
+ }));
44
+ }
45
+
46
+ export function buildOperatorShellSnapshotV2(workGraphSnapshot, options = {}) {
47
+ const items = Array.isArray(workGraphSnapshot?.items) ? workGraphSnapshot.items : [];
48
+ const dashboard = buildOperatorDashboardSnapshot(workGraphSnapshot, options.dashboard ?? options);
49
+ const cycleSlice = buildCycleSliceProjection(items, {
50
+ doneArchiveCap: options.doneArchiveCap ?? DEFAULT_DONE_ARCHIVE_CAP,
51
+ currentCycle: options.currentCycle,
52
+ });
53
+ const intentSidebar = buildIntentHierarchySnapshot(items.map((item) => ({ item })));
54
+ const semanticCrossHighlight = buildSemanticCrossHighlightMap(items);
55
+ const runnerQueue = buildRunnerQueueProjectionFromItems(items, {
56
+ workerRuns: options.workerRuns ?? [],
57
+ recordedAt: options.recordedAt,
58
+ });
59
+ const kanbanBoard = buildKanbanBoardProjection(items, { includeItems: options.includeKanbanItems === true });
60
+
61
+ return {
62
+ schema: OPERATOR_SHELL_SCHEMA,
63
+ sourceSchema: workGraphSnapshot.schema,
64
+ dashboard,
65
+ cycleSlice,
66
+ intentSidebar,
67
+ semanticCrossHighlight,
68
+ runnerQueue,
69
+ kanbanBoard,
70
+ phaseRoadmap: buildPhaseRoadmap(items),
71
+ startupBudget: STARTUP_BUDGET_V1,
72
+ };
73
+ }
74
+
75
+ export function buildIntentSidebarReadModel(intentHierarchySnapshot) {
76
+ const domains = intentHierarchySnapshot?.domains ?? [];
77
+ return {
78
+ schema: 'intent.sidebar.read.v1',
79
+ domains: domains.map((domain) => ({
80
+ id: domain.id,
81
+ label: domain.label,
82
+ count: domain.count,
83
+ workIds: [...domain.workIds],
84
+ })),
85
+ };
86
+ }
87
+
88
+ export function findCrossHighlightTargets(shellSnapshot, workId) {
89
+ const row = shellSnapshot?.semanticCrossHighlight?.find((entry) => entry.workId === workId);
90
+ if (!row) {
91
+ return { architectureBlockId: null, relatedWorkIds: [] };
92
+ }
93
+
94
+ const relatedWorkIds = (shellSnapshot.semanticCrossHighlight ?? [])
95
+ .filter((entry) => entry.architectureBlockId === row.architectureBlockId && entry.workId !== workId)
96
+ .map((entry) => entry.workId);
97
+
98
+ return {
99
+ architectureBlockId: row.architectureBlockId,
100
+ relatedWorkIds,
101
+ };
102
+ }