@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,288 @@
1
+ import {
2
+ buildWorkerPromptFromInput,
3
+ normalizeWorkerOutput,
4
+ } from './agentWorkerOpenAiProvider.mjs';
5
+ import {
6
+ formatBoundedTargetFilesForPrompt,
7
+ readBoundedTargetFiles,
8
+ } from './workGraphBoundedTargetFileRead.mjs';
9
+ import {
10
+ buildTargetFileFactsProjection,
11
+ formatLanguageFileFactsForPrompt,
12
+ } from './languageAdapterRegistry.mjs';
13
+
14
+ const INPUT_SCHEMA = 'agent-worker.input.v1';
15
+ const OUTPUT_SCHEMA = 'agent-worker.output.v1';
16
+
17
+ export function resolveClaudeProviderEnv(options = {}) {
18
+ const env = options.env ?? process.env;
19
+ return {
20
+ enabled: (options.enabled ?? env.IOHASC_CLAUDE_WORKER) === '1',
21
+ baseUrl: String(options.baseUrl ?? env.IOHASC_ANTHROPIC_BASE_URL ?? 'https://api.anthropic.com').replace(/\/+$/u, ''),
22
+ model: String(options.model ?? env.IOHASC_CLAUDE_MODEL ?? 'claude-3-5-sonnet-latest').trim(),
23
+ apiKey: String(options.apiKey ?? env.IOHASC_CLAUDE_API_KEY ?? env.ANTHROPIC_API_KEY ?? '').trim(),
24
+ apiVersion: String(options.apiVersion ?? env.IOHASC_ANTHROPIC_VERSION ?? '2023-06-01').trim(),
25
+ timeoutMs: Number(options.timeoutMs ?? env.IOHASC_CLAUDE_TIMEOUT_MS ?? 120_000),
26
+ };
27
+ }
28
+
29
+ export function buildClaudeMessagesRequestFromInput(input, options = {}) {
30
+ const env = resolveClaudeProviderEnv(options);
31
+ const prompt = buildWorkerPromptFromInput(input, {
32
+ targetFileContents: options.targetFileContents ?? '',
33
+ });
34
+
35
+ const systemMessage = prompt.messages.find((entry) => entry.role === 'system')?.content ?? '';
36
+ const userMessages = prompt.messages
37
+ .filter((entry) => entry.role !== 'system')
38
+ .map((entry) => ({ role: entry.role === 'assistant' ? 'assistant' : 'user', content: entry.content }));
39
+
40
+ return {
41
+ schema: 'claude-sdk-api.worker.request.v1',
42
+ runId: input.runId,
43
+ taskId: input.task?.id ?? '',
44
+ model: env.model,
45
+ system: systemMessage,
46
+ messages: userMessages,
47
+ maxTokens: options.maxTokens ?? 4096,
48
+ policy: { ...(input.policy ?? {}) },
49
+ allowedTools: [...(input.allowedTools ?? [])],
50
+ targetFiles: [...(input.targetFiles ?? [])],
51
+ providerHints: { ...(input.providerHints ?? {}), provider: 'claude-sdk-api' },
52
+ };
53
+ }
54
+
55
+ export function parseClaudeResponsePayload(payload) {
56
+ if (!payload || typeof payload !== 'object') {
57
+ throw new Error('claude response payload must be an object');
58
+ }
59
+
60
+ const blocks = payload.content;
61
+ if (!Array.isArray(blocks) || blocks.length === 0) {
62
+ throw new Error('claude response missing content blocks');
63
+ }
64
+
65
+ const text = blocks
66
+ .filter((block) => block && block.type === 'text' && typeof block.text === 'string')
67
+ .map((block) => block.text)
68
+ .join('\n')
69
+ .trim();
70
+
71
+ if (text === '') {
72
+ throw new Error('claude response did not include text content');
73
+ }
74
+
75
+ return text;
76
+ }
77
+
78
+ export function validateClaudeStructuredOutput(output) {
79
+ const errors = [];
80
+
81
+ if (!output || typeof output !== 'object') {
82
+ return ['output must be an object'];
83
+ }
84
+
85
+ if (output.schema !== OUTPUT_SCHEMA) {
86
+ errors.push(`schema must be ${OUTPUT_SCHEMA}`);
87
+ }
88
+
89
+ if (typeof output.runId !== 'string' || output.runId.trim() === '') {
90
+ errors.push('runId must be a non-empty string');
91
+ }
92
+
93
+ if (typeof output.taskId !== 'string' || output.taskId.trim() === '') {
94
+ errors.push('taskId must be a non-empty string');
95
+ }
96
+
97
+ if (!['succeeded', 'failed', 'cancelled', 'needs_human'].includes(output.status)) {
98
+ errors.push('status must be a Worker Output status');
99
+ }
100
+
101
+ if (!output.patchSummary || typeof output.patchSummary !== 'object') {
102
+ errors.push('patchSummary is required');
103
+ }
104
+
105
+ if (!output.transitionRequest || typeof output.transitionRequest !== 'object') {
106
+ errors.push('transitionRequest is required');
107
+ }
108
+
109
+ return errors;
110
+ }
111
+
112
+ export function normalizeClaudeWorkerOutput(raw, input) {
113
+ const normalized = normalizeWorkerOutput(raw, input);
114
+
115
+ if (Array.isArray(normalized.evidence) && normalized.evidence.length > 0) {
116
+ normalized.evidence = normalized.evidence.map((entry) => ({
117
+ ...entry,
118
+ source: entry.source === 'openai-compatible' ? 'claude-sdk-api' : (entry.source ?? 'claude-sdk-api'),
119
+ }));
120
+ }
121
+
122
+ return normalized;
123
+ }
124
+
125
+ export async function runClaudeSdkApiWorker(input, options = {}) {
126
+ const validationError = validateClaudeWorkerInput(input);
127
+ if (validationError !== null) {
128
+ return buildClaudeFailureOutput(input, validationError, 'code_failure');
129
+ }
130
+
131
+ const env = resolveClaudeProviderEnv(options);
132
+ if (!env.enabled && options.requireLive !== false) {
133
+ return buildClaudeFailureOutput(
134
+ input,
135
+ 'Claude SDK/API provider skipped: set IOHASC_CLAUDE_WORKER=1 for live path',
136
+ 'skipped',
137
+ );
138
+ }
139
+
140
+ if (env.apiKey === '' && options.requireApiKey !== false) {
141
+ return buildClaudeFailureOutput(
142
+ input,
143
+ 'Claude SDK/API provider blocked: IOHASC_CLAUDE_API_KEY or ANTHROPIC_API_KEY is required',
144
+ 'env_blocker',
145
+ );
146
+ }
147
+
148
+ const includeTargetFiles = options.includeTargetFiles !== false;
149
+ let targetFileContents = '';
150
+ if (includeTargetFiles && (input.targetFiles?.length ?? 0) > 0) {
151
+ const readResult = await readBoundedTargetFiles(input, {
152
+ repoRoot: options.repoRoot ?? options.cwd,
153
+ readFile: options.readFile,
154
+ maxBytesPerFile: options.maxBytesPerFile,
155
+ maxTotalBytes: options.maxTotalBytes,
156
+ });
157
+ const factsBlock = formatLanguageFileFactsForPrompt(buildTargetFileFactsProjection(readResult));
158
+ targetFileContents = formatBoundedTargetFilesForPrompt(readResult);
159
+ if (factsBlock) {
160
+ targetFileContents = `${targetFileContents}\n\n${factsBlock}`;
161
+ }
162
+ }
163
+
164
+ const request = buildClaudeMessagesRequestFromInput(input, { ...options, targetFileContents });
165
+ const fetchImpl = options.fetch ?? globalThis.fetch;
166
+ if (typeof fetchImpl !== 'function') {
167
+ return buildClaudeFailureOutput(input, 'fetch is not available in this runtime', 'env_blocker');
168
+ }
169
+
170
+ let response;
171
+ try {
172
+ response = await fetchImpl(`${env.baseUrl}/v1/messages`, {
173
+ method: 'POST',
174
+ headers: {
175
+ 'Content-Type': 'application/json',
176
+ 'x-api-key': env.apiKey,
177
+ 'anthropic-version': env.apiVersion,
178
+ },
179
+ body: JSON.stringify({
180
+ model: env.model,
181
+ max_tokens: request.maxTokens,
182
+ system: request.system,
183
+ messages: request.messages,
184
+ temperature: 0,
185
+ }),
186
+ signal: options.signal,
187
+ });
188
+ } catch (error) {
189
+ const message = error instanceof Error ? error.message : String(error);
190
+ const failureClass = error?.name === 'AbortError' ? 'timeout' : 'env_blocker';
191
+ return buildClaudeFailureOutput(input, `Claude API request failed: ${message}`, failureClass);
192
+ }
193
+
194
+ if (!response.ok) {
195
+ const body = await response.text();
196
+ return buildClaudeFailureOutput(
197
+ input,
198
+ `Claude API HTTP ${response.status}: ${body.slice(0, 500)}`,
199
+ 'model_failure',
200
+ );
201
+ }
202
+
203
+ const payload = await response.json();
204
+
205
+ try {
206
+ const text = parseClaudeResponsePayload(payload);
207
+ const parsedRaw = parseRawWorkerOutputJson(text);
208
+ const structureErrors = validateClaudeStructuredOutput(parsedRaw);
209
+ if (structureErrors.length > 0) {
210
+ return buildClaudeFailureOutput(
211
+ input,
212
+ `Claude structured output validation failed: ${structureErrors.join('; ')}`,
213
+ 'model_failure',
214
+ );
215
+ }
216
+
217
+ return normalizeClaudeWorkerOutput(parsedRaw, input);
218
+ } catch (error) {
219
+ const message = error instanceof Error ? error.message : String(error);
220
+ return buildClaudeFailureOutput(input, `Failed to parse Claude JSON output: ${message}`, 'model_failure');
221
+ }
222
+ }
223
+
224
+ function validateClaudeWorkerInput(input) {
225
+ if (!input || typeof input !== 'object') {
226
+ return 'input must be an object';
227
+ }
228
+
229
+ if (input.schema !== INPUT_SCHEMA) {
230
+ return `unsupported input schema: ${String(input.schema)}`;
231
+ }
232
+
233
+ if (!input.task || typeof input.task.id !== 'string' || input.task.id.trim() === '') {
234
+ return 'task.id must be a non-empty string';
235
+ }
236
+
237
+ if (input.policy?.allowShell === true || input.policy?.allowFileWrite === true) {
238
+ return 'claude-sdk-api provider MVP rejects shell/file-write policy flags';
239
+ }
240
+
241
+ return null;
242
+ }
243
+
244
+ function parseRawWorkerOutputJson(text) {
245
+ const trimmed = String(text ?? '').trim();
246
+ const jsonStart = trimmed.indexOf('{');
247
+ const jsonEnd = trimmed.lastIndexOf('}');
248
+
249
+ if (jsonStart === -1 || jsonEnd === -1 || jsonEnd <= jsonStart) {
250
+ throw new Error('model response did not contain JSON object');
251
+ }
252
+
253
+ return JSON.parse(trimmed.slice(jsonStart, jsonEnd + 1));
254
+ }
255
+
256
+ function buildClaudeFailureOutput(input, failureReason, failureClass) {
257
+ const runId = typeof input?.runId === 'string' && input.runId.trim() !== '' ? input.runId : 'claude-invalid-input';
258
+ const taskId = typeof input?.task?.id === 'string' && input.task.id.trim() !== '' ? input.task.id : '';
259
+
260
+ return {
261
+ schema: OUTPUT_SCHEMA,
262
+ runId,
263
+ taskId,
264
+ status: 'failed',
265
+ patchSummary: {
266
+ changedFiles: [],
267
+ summary: failureClass === 'skipped'
268
+ ? 'Claude SDK/API provider skipped (env-gated mode).'
269
+ : 'Claude SDK/API provider failed before producing a patch summary.',
270
+ },
271
+ evidence: [{
272
+ kind: 'worker_run',
273
+ source: 'claude-sdk-api',
274
+ result: 'failed',
275
+ summary: failureReason,
276
+ failureClass,
277
+ }],
278
+ transitionRequest: {
279
+ status: 'blocked',
280
+ reason: failureReason,
281
+ },
282
+ logs: [{ level: failureClass === 'skipped' ? 'info' : 'error', message: failureReason }],
283
+ failureReason,
284
+ retryAdvice: failureClass === 'skipped'
285
+ ? 'Set IOHASC_CLAUDE_WORKER=1 and configure IOHASC_CLAUDE_API_KEY / IOHASC_CLAUDE_MODEL.'
286
+ : 'Verify Claude endpoint availability and JSON output quality, then retry.',
287
+ };
288
+ }
@@ -0,0 +1,156 @@
1
+ import {
2
+ buildWorkerPromptFromInput,
3
+ normalizeWorkerOutput,
4
+ } from './agentWorkerOpenAiProvider.mjs';
5
+
6
+ const INPUT_SCHEMA = 'agent-worker.input.v1';
7
+ const OUTPUT_SCHEMA = 'agent-worker.output.v1';
8
+
9
+ export function resolveCursorSdkProviderEnv(options = {}) {
10
+ const env = options.env ?? process.env;
11
+ return {
12
+ enabled: (options.enabled ?? env.IOHASC_CURSOR_SDK_WORKER) === '1',
13
+ workspaceRoot: String(options.workspaceRoot ?? env.IOHASC_CURSOR_SDK_WORKSPACE ?? process.cwd()).trim(),
14
+ model: String(options.model ?? env.IOHASC_CURSOR_SDK_MODEL ?? 'default').trim(),
15
+ };
16
+ }
17
+
18
+ export function buildCursorSdkAgentRequestFromInput(input, options = {}) {
19
+ if (!input || typeof input !== 'object') {
20
+ throw new TypeError('input must be an object');
21
+ }
22
+
23
+ const env = resolveCursorSdkProviderEnv(options);
24
+ const prompt = buildWorkerPromptFromInput(input, {
25
+ targetFileContents: options.targetFileContents ?? '',
26
+ });
27
+
28
+ return {
29
+ schema: 'cursor-sdk.worker.request.v1',
30
+ runId: input.runId,
31
+ taskId: input.task?.id ?? '',
32
+ workspaceRoot: env.workspaceRoot,
33
+ model: env.model,
34
+ policy: { ...(input.policy ?? {}) },
35
+ allowedTools: [...(input.allowedTools ?? [])],
36
+ targetFiles: [...(input.targetFiles ?? [])],
37
+ prompt,
38
+ providerHints: { ...(input.providerHints ?? {}), provider: 'cursor-sdk' },
39
+ };
40
+ }
41
+
42
+ export async function runCursorSdkWorker(input, options = {}) {
43
+ const validationError = validateCursorSdkWorkerInput(input);
44
+ if (validationError !== null) {
45
+ return buildCursorSdkFailureOutput(input, validationError, 'code_failure');
46
+ }
47
+
48
+ const env = resolveCursorSdkProviderEnv(options);
49
+ if (!env.enabled && options.requireLive !== false) {
50
+ return buildCursorSdkFailureOutput(
51
+ input,
52
+ 'Cursor SDK provider skipped: set IOHASC_CURSOR_SDK_WORKER=1 for live path',
53
+ 'skipped',
54
+ );
55
+ }
56
+
57
+ const request = buildCursorSdkAgentRequestFromInput(input, options);
58
+ const runAgent = options.runAgent;
59
+
60
+ if (typeof runAgent !== 'function') {
61
+ return buildCursorSdkFailureOutput(
62
+ input,
63
+ 'Cursor SDK adapter is not configured in this runtime',
64
+ 'env_blocker',
65
+ );
66
+ }
67
+
68
+ try {
69
+ const agentResult = await runAgent(request, options);
70
+ return normalizeCursorSdkWorkerOutput(agentResult, input);
71
+ } catch (error) {
72
+ const message = error instanceof Error ? error.message : String(error);
73
+ return buildCursorSdkFailureOutput(input, `Cursor SDK worker failed: ${message}`, 'model_failure');
74
+ }
75
+ }
76
+
77
+ export function normalizeCursorSdkWorkerOutput(raw, input) {
78
+ if (raw && raw.schema === OUTPUT_SCHEMA) {
79
+ return normalizeWorkerOutput(raw, input);
80
+ }
81
+
82
+ const normalized = normalizeWorkerOutput({
83
+ schema: OUTPUT_SCHEMA,
84
+ runId: raw?.runId ?? input.runId,
85
+ taskId: raw?.taskId ?? input.task.id,
86
+ status: raw?.status ?? 'succeeded',
87
+ patchSummary: raw?.patchSummary ?? {
88
+ changedFiles: raw?.changedFiles ?? [],
89
+ summary: raw?.summary ?? 'Cursor SDK worker completed',
90
+ },
91
+ evidence: raw?.evidence,
92
+ transitionRequest: raw?.transitionRequest,
93
+ logs: raw?.logs,
94
+ failureReason: raw?.failureReason ?? '',
95
+ retryAdvice: raw?.retryAdvice ?? '',
96
+ }, input);
97
+
98
+ if (Array.isArray(normalized.evidence) && normalized.evidence.length > 0) {
99
+ normalized.evidence = normalized.evidence.map((entry) => ({
100
+ ...entry,
101
+ source: entry.source === 'openai-compatible' ? 'cursor-sdk' : (entry.source ?? 'cursor-sdk'),
102
+ }));
103
+ }
104
+
105
+ return normalized;
106
+ }
107
+
108
+ function validateCursorSdkWorkerInput(input) {
109
+ if (!input || typeof input !== 'object') {
110
+ return 'input must be an object';
111
+ }
112
+
113
+ if (input.schema !== INPUT_SCHEMA) {
114
+ return `unsupported input schema: ${String(input.schema)}`;
115
+ }
116
+
117
+ if (!input.task || typeof input.task.id !== 'string' || input.task.id.trim() === '') {
118
+ return 'task.id must be a non-empty string';
119
+ }
120
+
121
+ return null;
122
+ }
123
+
124
+ function buildCursorSdkFailureOutput(input, failureReason, failureClass) {
125
+ const runId = typeof input?.runId === 'string' && input.runId.trim() !== '' ? input.runId : 'cursor-sdk-invalid-input';
126
+ const taskId = typeof input?.task?.id === 'string' && input.task.id.trim() !== '' ? input.task.id : '';
127
+
128
+ return {
129
+ schema: OUTPUT_SCHEMA,
130
+ runId,
131
+ taskId,
132
+ status: 'failed',
133
+ patchSummary: {
134
+ changedFiles: [],
135
+ summary: failureClass === 'skipped'
136
+ ? 'Cursor SDK provider skipped (env-gated mode).'
137
+ : 'Cursor SDK provider failed before producing a patch summary.',
138
+ },
139
+ evidence: [{
140
+ kind: 'worker_run',
141
+ source: 'cursor-sdk',
142
+ result: 'failed',
143
+ summary: failureReason,
144
+ failureClass,
145
+ }],
146
+ transitionRequest: {
147
+ status: 'blocked',
148
+ reason: failureReason,
149
+ },
150
+ logs: [{ level: failureClass === 'skipped' ? 'info' : 'error', message: failureReason }],
151
+ failureReason,
152
+ retryAdvice: failureClass === 'skipped'
153
+ ? 'Set IOHASC_CURSOR_SDK_WORKER=1 and inject a Cursor SDK runAgent adapter.'
154
+ : 'Verify Cursor SDK adapter availability and structured output mapping, then retry.',
155
+ };
156
+ }