@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,115 @@
1
+ import {
2
+ persistWorkItemUpdateToRepo,
3
+ readWorkItemsFromRepo,
4
+ } from './intentTreeWorkItems.mjs';
5
+ import {
6
+ evaluateCharterPreflightForPromoteFromRepo,
7
+ } from './charterPreflightPromoteGate.mjs';
8
+ import {
9
+ evaluatePromoteReadyEligibility,
10
+ transitionStatus,
11
+ } from './workGraphRuntime.mjs';
12
+
13
+ export const PROMOTE_READY_RESPONSE_SCHEMA = 'operator.promote-ready.response.v1';
14
+
15
+ export function parsePromoteReadyRequestBody(rawBody) {
16
+ if (rawBody === undefined || rawBody === null) {
17
+ return {};
18
+ }
19
+
20
+ if (typeof rawBody === 'string' && rawBody.trim() === '') {
21
+ return {};
22
+ }
23
+
24
+ const body = typeof rawBody === 'string' ? JSON.parse(rawBody) : rawBody;
25
+
26
+ if (!body || typeof body !== 'object' || Array.isArray(body)) {
27
+ throw new TypeError('promote-ready body must be a JSON object');
28
+ }
29
+
30
+ return body;
31
+ }
32
+
33
+ export function buildPromoteReadyResponse(result) {
34
+ return {
35
+ schema: PROMOTE_READY_RESPONSE_SCHEMA,
36
+ ok: Boolean(result.ok),
37
+ error: result.error ?? null,
38
+ workId: result.workId ?? null,
39
+ previousStatus: result.previousStatus ?? null,
40
+ newStatus: result.newStatus ?? null,
41
+ unsatisfiedDependencies: result.unsatisfiedDependencies ?? [],
42
+ currentStatus: result.currentStatus ?? null,
43
+ persistedBacklog: Boolean(result.persistedBacklog),
44
+ persistBacklogError: result.persistBacklogError ?? null,
45
+ charterPreflight: result.charterPreflight ?? null,
46
+ charterViolations: result.charterViolations ?? [],
47
+ item: result.item ?? null,
48
+ };
49
+ }
50
+
51
+ export async function executePromoteReady(options = {}) {
52
+ const cwd = options.cwd ?? process.cwd();
53
+ const body = parsePromoteReadyRequestBody(options.body ?? {});
54
+ const workId = String(body.workId ?? body.taskId ?? '').trim();
55
+
56
+ if (workId === '') {
57
+ return buildPromoteReadyResponse({ ok: false, error: 'work_id_required' });
58
+ }
59
+
60
+ const items = await readWorkItemsFromRepo({ ...options, cwd });
61
+ const item = items.find((entry) => entry.id === workId);
62
+ if (!item) {
63
+ return buildPromoteReadyResponse({ ok: false, error: 'task_not_found', workId });
64
+ }
65
+
66
+ const charterPreflight = options.skipCharterPreflight === true
67
+ ? { ok: true, skipped: true }
68
+ : await evaluateCharterPreflightForPromoteFromRepo(item, options);
69
+
70
+ const eligibility = evaluatePromoteReadyEligibility(items, workId, {
71
+ charterPreflight: options.skipCharterPreflight === true ? undefined : charterPreflight,
72
+ });
73
+
74
+ if (!eligibility.ok) {
75
+ return buildPromoteReadyResponse(eligibility);
76
+ }
77
+
78
+ const previousStatus = eligibility.item.status;
79
+ let updatedItem = transitionStatus(eligibility.item, 'ready', {
80
+ evidence: `promote-ready: ${previousStatus}→ready via operator board`,
81
+ });
82
+
83
+ let persistedBacklog = false;
84
+ let persistBacklogError = null;
85
+
86
+ if (body.persistBacklog !== false && options.persistBacklog !== false) {
87
+ try {
88
+ await persistWorkItemUpdateToRepo({
89
+ ...options,
90
+ cwd,
91
+ item: updatedItem,
92
+ });
93
+ persistedBacklog = true;
94
+ } catch (error) {
95
+ persistBacklogError = error instanceof Error ? error.message : String(error);
96
+ }
97
+ }
98
+
99
+ const ok = persistBacklogError === null && (persistedBacklog || body.persistBacklog === false || options.persistBacklog === false);
100
+
101
+ return buildPromoteReadyResponse({
102
+ ok,
103
+ error: persistBacklogError ? 'persist_failed' : null,
104
+ workId,
105
+ previousStatus,
106
+ newStatus: updatedItem.status,
107
+ persistedBacklog,
108
+ persistBacklogError,
109
+ item: {
110
+ id: updatedItem.id,
111
+ title: updatedItem.title,
112
+ status: updatedItem.status,
113
+ },
114
+ });
115
+ }
@@ -0,0 +1,124 @@
1
+ export const RECOVERY_PRESETS = {
2
+ WORKER_FAILED_FIRST: 'worker_failed_first',
3
+ WORKER_FAILED_REPEATED: 'worker_failed_repeated',
4
+ ENV_BLOCKER: 'env_blocker',
5
+ VERIFICATION_FAILED: 'verification_failed',
6
+ RATE_LIMIT_RETRY: 'rate_limit_retry',
7
+ NO_CLAIMABLE_TASK: 'no_claimable_task',
8
+ SUCCEEDED: 'succeeded',
9
+ };
10
+
11
+ export const RECOVERY_ACTIONS = {
12
+ RETRY_READY: 'retry_ready',
13
+ STAY_BLOCKED: 'stay_blocked',
14
+ STAY_VERIFY: 'stay_verify',
15
+ ESCALATE_HUMAN: 'escalate_human',
16
+ NOOP: 'noop',
17
+ };
18
+
19
+ const DEFAULT_MAX_RETRIES = 2;
20
+
21
+ export function classifyFailure(output, context = {}) {
22
+ if (context.noClaimableTask) {
23
+ return 'no_task';
24
+ }
25
+
26
+ if (!output || output.status === 'succeeded') {
27
+ return 'succeeded';
28
+ }
29
+
30
+ const reason = String(output.failureReason || output.transitionRequest?.reason || '').toLowerCase();
31
+
32
+ if (reason.includes('go') || reason.includes('env') || reason.includes('eaddrinuse') || reason.includes('toolchain')) {
33
+ return 'env_blocker';
34
+ }
35
+
36
+ if (reason.includes('policy') || reason.includes('denied') || reason.includes('unsupported')) {
37
+ return 'policy_denied';
38
+ }
39
+
40
+ if (reason.includes('rate limit') || reason.includes('429')) {
41
+ return 'rate_limit';
42
+ }
43
+
44
+ if (reason.includes('verify') || reason.includes('test:') || context.taskStatus === 'verify') {
45
+ return 'verification_failed';
46
+ }
47
+
48
+ return 'model_failure';
49
+ }
50
+
51
+ export function suggestRecovery(failureClass, context = {}) {
52
+ const retryCount = Number(context.retryCount ?? 0);
53
+ const maxRetries = Number(context.maxRetries ?? DEFAULT_MAX_RETRIES);
54
+ const taskStatus = context.taskStatus ?? '';
55
+
56
+ if (failureClass === 'succeeded') {
57
+ return {
58
+ preset: RECOVERY_PRESETS.SUCCEEDED,
59
+ action: taskStatus === 'verify' ? RECOVERY_ACTIONS.STAY_VERIFY : RECOVERY_ACTIONS.NOOP,
60
+ reason: 'worker run succeeded',
61
+ retryAdvice: '',
62
+ };
63
+ }
64
+
65
+ if (failureClass === 'no_task') {
66
+ return {
67
+ preset: RECOVERY_PRESETS.NO_CLAIMABLE_TASK,
68
+ action: RECOVERY_ACTIONS.NOOP,
69
+ reason: 'no claimable ready task in snapshot',
70
+ retryAdvice: 'add ready WorkItem or resolve dependencies',
71
+ };
72
+ }
73
+
74
+ if (failureClass === 'env_blocker') {
75
+ return {
76
+ preset: RECOVERY_PRESETS.ENV_BLOCKER,
77
+ action: RECOVERY_ACTIONS.STAY_BLOCKED,
78
+ reason: 'environment blocker detected',
79
+ retryAdvice: 'fix environment gate and rerun tick',
80
+ };
81
+ }
82
+
83
+ if (failureClass === 'rate_limit') {
84
+ return {
85
+ preset: RECOVERY_PRESETS.RATE_LIMIT_RETRY,
86
+ action: RECOVERY_ACTIONS.RETRY_READY,
87
+ reason: 'rate limit detected; schedule retry with backoff',
88
+ retryAdvice: 'wait and rerun daemon tick',
89
+ };
90
+ }
91
+
92
+ if (failureClass === 'verification_failed') {
93
+ return {
94
+ preset: RECOVERY_PRESETS.VERIFICATION_FAILED,
95
+ action: RECOVERY_ACTIONS.RETRY_READY,
96
+ reason: 'verification gate failed',
97
+ retryAdvice: 'fix failing verification command and rerun tick',
98
+ };
99
+ }
100
+
101
+ if (retryCount >= maxRetries) {
102
+ return {
103
+ preset: RECOVERY_PRESETS.WORKER_FAILED_REPEATED,
104
+ action: RECOVERY_ACTIONS.ESCALATE_HUMAN,
105
+ reason: `worker failed ${retryCount + 1} times`,
106
+ retryAdvice: 'review worker-run evidence and narrow task scope or switch provider',
107
+ };
108
+ }
109
+
110
+ return {
111
+ preset: RECOVERY_PRESETS.WORKER_FAILED_FIRST,
112
+ action: failureClass === 'policy_denied' ? RECOVERY_ACTIONS.STAY_BLOCKED : RECOVERY_ACTIONS.RETRY_READY,
113
+ reason: failureClass === 'policy_denied' ? 'worker policy denied execution' : 'first worker failure',
114
+ retryAdvice: 'retry daemon tick after adjusting worker input or task scope',
115
+ };
116
+ }
117
+
118
+ export function buildRecoverySuggestionFromWorkerOutput(output, context = {}) {
119
+ const failureClass = classifyFailure(output, context);
120
+ return {
121
+ failureClass,
122
+ ...suggestRecovery(failureClass, context),
123
+ };
124
+ }
@@ -0,0 +1,187 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readWorkerRunJournal } from './agentWorkerLiveLoop.mjs';
3
+ import { readWorkItemsFromRepo } from './intentTreeWorkItems.mjs';
4
+
5
+ const compareText = (left, right) => String(left).localeCompare(String(right), 'en', { sensitivity: 'variant' });
6
+
7
+ export const RUNNER_QUEUE_PROJECTION_SCHEMA = 'workgraph.runner.queue.projection.v1';
8
+ export const RUNNER_QUEUE_SQLITE_DDL = `
9
+ CREATE TABLE IF NOT EXISTS workgraph_runner_queue_v1 (
10
+ task_id TEXT PRIMARY KEY,
11
+ status TEXT NOT NULL,
12
+ priority TEXT NOT NULL DEFAULT 'medium',
13
+ retry_count INTEGER NOT NULL DEFAULT 0,
14
+ next_run_at TEXT,
15
+ last_run_id TEXT,
16
+ last_run_status TEXT,
17
+ provider_id TEXT,
18
+ policy_hash TEXT NOT NULL,
19
+ updated_at TEXT NOT NULL
20
+ );
21
+ `.trim();
22
+
23
+ export function computeRunnerQueuePolicyHash(item) {
24
+ const payload = JSON.stringify({
25
+ id: item.id,
26
+ status: item.status,
27
+ dependsOn: [...(item.dependsOn ?? [])].sort(compareText),
28
+ priority: item.priority ?? 'medium',
29
+ });
30
+
31
+ return createHash('sha256').update(payload).digest('hex').slice(0, 16);
32
+ }
33
+
34
+ export function indexWorkerRunsByTaskId(entries) {
35
+ const byTask = new Map();
36
+
37
+ for (const entry of entries ?? []) {
38
+ if (!entry || typeof entry.taskId !== 'string' || entry.taskId.trim() === '') {
39
+ continue;
40
+ }
41
+
42
+ const existing = byTask.get(entry.taskId);
43
+ if (!existing || String(entry.recordedAt ?? '') > String(existing.recordedAt ?? '')) {
44
+ byTask.set(entry.taskId, entry);
45
+ }
46
+ }
47
+
48
+ return byTask;
49
+ }
50
+
51
+ export function buildRunnerQueueProjectionFromItems(items, options = {}) {
52
+ if (!Array.isArray(items)) {
53
+ throw new TypeError('items must be an array');
54
+ }
55
+
56
+ const journalByTask = indexWorkerRunsByTaskId(options.workerRuns ?? []);
57
+ const runnableStatuses = new Set(options.runnableStatuses ?? ['ready', 'claimed', 'verify', 'in_progress']);
58
+ const recordedAt = options.recordedAt ?? new Date(0).toISOString();
59
+
60
+ const rows = items
61
+ .filter((item) => runnableStatuses.has(item.status))
62
+ .map((item) => {
63
+ const lastRun = journalByTask.get(item.id);
64
+ return {
65
+ taskId: item.id,
66
+ title: item.title,
67
+ status: item.status,
68
+ priority: item.priority ?? 'medium',
69
+ retryCount: Number(lastRun?.retryCount ?? 0),
70
+ nextRunAt: item.status === 'ready' ? recordedAt : null,
71
+ lastRunId: lastRun?.runId ?? null,
72
+ lastRunStatus: lastRun?.status ?? null,
73
+ providerId: lastRun?.provider ?? null,
74
+ policyHash: computeRunnerQueuePolicyHash(item),
75
+ ownerRole: item.ownerRole ?? '',
76
+ dependsOn: [...(item.dependsOn ?? [])].sort(compareText),
77
+ };
78
+ })
79
+ .sort((left, right) => compareText(left.taskId, right.taskId));
80
+
81
+ return {
82
+ schema: RUNNER_QUEUE_PROJECTION_SCHEMA,
83
+ recordedAt,
84
+ source: options.source ?? 'workgraph.snapshot.v1',
85
+ rows,
86
+ summary: {
87
+ total: rows.length,
88
+ ready: rows.filter((row) => row.status === 'ready').length,
89
+ claimed: rows.filter((row) => row.status === 'claimed').length,
90
+ withLastRun: rows.filter((row) => row.lastRunId).length,
91
+ },
92
+ sqlite: {
93
+ ddl: RUNNER_QUEUE_SQLITE_DDL,
94
+ optional: true,
95
+ rebuildPolicy: 'delete-db-and-rebuild-from-step-canonical',
96
+ },
97
+ };
98
+ }
99
+
100
+ export async function syncRunnerQueueProjectionToSqlite(projection, options = {}) {
101
+ if (!projection || projection.schema !== RUNNER_QUEUE_PROJECTION_SCHEMA) {
102
+ throw new TypeError('projection must be workgraph.runner.queue.projection.v1');
103
+ }
104
+
105
+ let DatabaseSync;
106
+ try {
107
+ ({ DatabaseSync } = await import('node:sqlite'));
108
+ } catch {
109
+ return {
110
+ ok: false,
111
+ skipped: true,
112
+ reason: 'node:sqlite is not available in this runtime',
113
+ rowCount: 0,
114
+ };
115
+ }
116
+
117
+ const dbPath = options.dbPath;
118
+ if (!dbPath) {
119
+ return {
120
+ ok: false,
121
+ skipped: true,
122
+ reason: 'dbPath is required for sqlite sync',
123
+ rowCount: 0,
124
+ };
125
+ }
126
+
127
+ const db = new DatabaseSync(dbPath);
128
+ try {
129
+ db.exec(RUNNER_QUEUE_SQLITE_DDL);
130
+ const upsert = db.prepare(`
131
+ INSERT INTO workgraph_runner_queue_v1 (
132
+ task_id, status, priority, retry_count, next_run_at,
133
+ last_run_id, last_run_status, provider_id, policy_hash, updated_at
134
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
135
+ ON CONFLICT(task_id) DO UPDATE SET
136
+ status=excluded.status,
137
+ priority=excluded.priority,
138
+ retry_count=excluded.retry_count,
139
+ next_run_at=excluded.next_run_at,
140
+ last_run_id=excluded.last_run_id,
141
+ last_run_status=excluded.last_run_status,
142
+ provider_id=excluded.provider_id,
143
+ policy_hash=excluded.policy_hash,
144
+ updated_at=excluded.updated_at
145
+ `);
146
+
147
+ for (const row of projection.rows) {
148
+ upsert.run(
149
+ row.taskId,
150
+ row.status,
151
+ row.priority,
152
+ row.retryCount,
153
+ row.nextRunAt,
154
+ row.lastRunId,
155
+ row.lastRunStatus,
156
+ row.providerId,
157
+ row.policyHash,
158
+ projection.recordedAt,
159
+ );
160
+ }
161
+
162
+ return {
163
+ ok: true,
164
+ skipped: false,
165
+ reason: '',
166
+ rowCount: projection.rows.length,
167
+ dbPath,
168
+ };
169
+ } finally {
170
+ db.close();
171
+ }
172
+ }
173
+
174
+ export async function readRunnerQueueProjectionFromRepo(options = {}) {
175
+ const cwd = options.cwd ?? process.cwd();
176
+ const items = await readWorkItemsFromRepo({ ...options, cwd });
177
+ const workerRuns = await readWorkerRunJournal({
178
+ cwd,
179
+ journalPath: options.journalPath ?? 'work/worker-runs.jsonl',
180
+ });
181
+
182
+ return buildRunnerQueueProjectionFromItems(items, {
183
+ workerRuns,
184
+ recordedAt: options.recordedAt,
185
+ source: options.source ?? (options.backlogPath ?? 'intent/index.bvc'),
186
+ });
187
+ }