onto-mcp 0.4.6 → 0.4.7

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 (146) hide show
  1. package/.onto/authority/core-lens-registry.yaml +5 -14
  2. package/.onto/authority/core-lexicon.yaml +269 -392
  3. package/.onto/domains/commerce-performance-marketing-kr/competency_qs.md +249 -0
  4. package/.onto/domains/commerce-performance-marketing-kr/concepts.md +256 -0
  5. package/.onto/domains/commerce-performance-marketing-kr/conciseness_rules.md +164 -0
  6. package/.onto/domains/commerce-performance-marketing-kr/dependency_rules.md +227 -0
  7. package/.onto/domains/commerce-performance-marketing-kr/domain_scope.md +262 -0
  8. package/.onto/domains/commerce-performance-marketing-kr/domain_structure.svg +253 -0
  9. package/.onto/domains/commerce-performance-marketing-kr/extension_cases.md +370 -0
  10. package/.onto/domains/commerce-performance-marketing-kr/logic_rules.md +207 -0
  11. package/.onto/domains/commerce-performance-marketing-kr/structure_spec.md +412 -0
  12. package/.onto/domains/software-engineering/conciseness_rules.md +1 -1
  13. package/.onto/domains/software-engineering/domain_scope.md +3 -3
  14. package/.onto/principles/llm-native-development-guideline.md +136 -370
  15. package/.onto/principles/llm-runtime-interface-principles.md +184 -552
  16. package/.onto/principles/non-specialist-communication-guideline.md +159 -39
  17. package/.onto/principles/ontology-as-code-guideline.md +96 -134
  18. package/.onto/principles/ontology-as-code-naming-charter.md +163 -72
  19. package/.onto/principles/product-locality-principle.md +5 -7
  20. package/.onto/principles/productization-charter.md +159 -475
  21. package/.onto/processes/evolve/material-kind-adapter-contract.md +3 -3
  22. package/.onto/processes/reconstruct/ontology-seeding-and-maturation-design.md +1516 -181
  23. package/.onto/processes/reconstruct/operational-ontology-seed-contract.md +6 -2
  24. package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +36 -30
  25. package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +903 -690
  26. package/.onto/processes/reconstruct/source-profiles/code.md +25 -0
  27. package/.onto/processes/reconstruct/source-profiles/document.md +25 -0
  28. package/.onto/processes/review/binding-contract.md +1 -1
  29. package/.onto/processes/review/external-oauth-worker-contract.md +142 -0
  30. package/.onto/processes/review/host-orchestration-contract.md +114 -0
  31. package/.onto/processes/review/interpretation-contract.md +2 -2
  32. package/.onto/processes/review/issue-stance-deliberation-contract.md +221 -78
  33. package/.onto/processes/review/lens-registry.md +4 -4
  34. package/.onto/processes/review/live-deliberation-experiment-contract.md +64 -0
  35. package/.onto/processes/review/material-issue-contract.md +141 -0
  36. package/.onto/processes/review/nesting-batch-worker-contract.md +68 -0
  37. package/.onto/processes/review/pre-dispatch-contracts.md +25 -22
  38. package/.onto/processes/review/productized-live-path.md +65 -64
  39. package/.onto/processes/review/prompt-execution-runner-contract.md +74 -38
  40. package/.onto/processes/review/record-contract.md +66 -43
  41. package/.onto/processes/review/record-field-mapping.md +70 -52
  42. package/.onto/processes/review/review-context-manifest-contract.md +1 -1
  43. package/.onto/processes/review/review-execution-ux-contract.md +42 -37
  44. package/.onto/processes/review/review-target-profile-contract.md +1 -1
  45. package/.onto/processes/review/shared-phenomenon-contract.md +1 -1
  46. package/.onto/processes/review/synthesize-prompt-contract.md +226 -250
  47. package/.onto/processes/shared/target-material-kind-contract.md +4 -12
  48. package/.onto/roles/axiology.md +1 -1
  49. package/.onto/roles/conciseness.md +1 -1
  50. package/.onto/roles/coverage.md +8 -4
  51. package/.onto/roles/dependency.md +1 -1
  52. package/.onto/roles/evolution.md +1 -1
  53. package/.onto/roles/logic.md +5 -4
  54. package/.onto/roles/pragmatics.md +1 -1
  55. package/.onto/roles/semantics.md +4 -3
  56. package/.onto/roles/structure.md +1 -1
  57. package/AGENTS.md +193 -59
  58. package/README.md +252 -66
  59. package/dist/core-api/reconstruct-api.js +25 -13
  60. package/dist/core-api/review-api.js +1328 -225
  61. package/dist/core-runtime/cli/assemble-review-record.js +60 -22
  62. package/dist/core-runtime/cli/claude-code-review-unit-executor.js +631 -0
  63. package/dist/core-runtime/cli/claude-nesting-batch-worker.js +187 -0
  64. package/dist/core-runtime/cli/codex-nesting-batch-worker.js +194 -0
  65. package/dist/core-runtime/cli/codex-review-unit-executor.js +253 -40
  66. package/dist/core-runtime/cli/host-orchestration-reference-driver.js +33 -0
  67. package/dist/core-runtime/cli/inline-http-review-unit-executor.js +676 -89
  68. package/dist/core-runtime/cli/lens-sidecar-tools.js +436 -0
  69. package/dist/core-runtime/cli/materialize-review-prompt-packets.js +178 -133
  70. package/dist/core-runtime/cli/nested-batch-dispatch.js +237 -0
  71. package/dist/core-runtime/cli/onto-tools.js +177 -28
  72. package/dist/core-runtime/cli/render-review-final-output.js +503 -94
  73. package/dist/core-runtime/cli/review-invoke.js +173 -107
  74. package/dist/core-runtime/cli/run-review-prompt-execution.js +3680 -460
  75. package/dist/core-runtime/cli/runtime-submit-context.js +337 -0
  76. package/dist/core-runtime/cli/structured-output-tools.js +1027 -0
  77. package/dist/core-runtime/cli/submit-salvage.js +115 -0
  78. package/dist/core-runtime/cli/worker-structured-output.js +266 -0
  79. package/dist/core-runtime/discovery/host-detection.js +37 -0
  80. package/dist/core-runtime/discovery/settings-chain.js +841 -85
  81. package/dist/core-runtime/llm/llm-caller.js +86 -180
  82. package/dist/core-runtime/llm/llm-tool-loop.js +95 -109
  83. package/dist/core-runtime/llm/mock-llm-realization.js +573 -0
  84. package/dist/core-runtime/llm/model-switcher.js +55 -9
  85. package/dist/core-runtime/path-boundary.js +16 -7
  86. package/dist/core-runtime/pipeline-execution-ledger.js +9 -0
  87. package/dist/core-runtime/reconstruct/artifact-types.js +61 -0
  88. package/dist/core-runtime/reconstruct/claim-projection-validation.js +862 -0
  89. package/dist/core-runtime/reconstruct/material-admission-validation.js +518 -0
  90. package/dist/core-runtime/reconstruct/materialize-preparation.js +4 -1
  91. package/dist/core-runtime/reconstruct/maturation-validation.js +3575 -0
  92. package/dist/core-runtime/reconstruct/ontology-seed-validation.js +4 -1
  93. package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +657 -16
  94. package/dist/core-runtime/reconstruct/post-seed-validation.js +9 -1
  95. package/dist/core-runtime/reconstruct/proof-authority-validation.js +160 -0
  96. package/dist/core-runtime/reconstruct/purpose-authority-validation.js +421 -0
  97. package/dist/core-runtime/reconstruct/record.js +176 -0
  98. package/dist/core-runtime/reconstruct/registry-verification-validation.js +371 -0
  99. package/dist/core-runtime/reconstruct/run-control-validation.js +724 -0
  100. package/dist/core-runtime/reconstruct/run.js +5670 -1786
  101. package/dist/core-runtime/reconstruct/seed-authoring-readiness-validation.js +758 -0
  102. package/dist/core-runtime/reconstruct/seed-claim-projections.js +23 -23
  103. package/dist/core-runtime/reconstruct/source-observation-delta-validation.js +750 -0
  104. package/dist/core-runtime/reconstruct/source-observations.js +10 -0
  105. package/dist/core-runtime/reconstruct/source-profiles.js +2 -2
  106. package/dist/core-runtime/reconstruct/source-safety-validation.js +614 -0
  107. package/dist/core-runtime/reconstruct/source-scout-pack-validation.js +707 -0
  108. package/dist/core-runtime/reconstruct/terminal-validation.js +314 -1
  109. package/dist/core-runtime/release-channel/release-channel.js +2 -2
  110. package/dist/core-runtime/review/artifact-generation-realization.js +34 -0
  111. package/dist/core-runtime/review/boundary-prompt-sections.js +44 -0
  112. package/dist/core-runtime/review/citation-audit.js +3 -1
  113. package/dist/core-runtime/review/continuation-plan.js +3 -15
  114. package/dist/core-runtime/review/controlled-lens-deliberation.js +584 -90
  115. package/dist/core-runtime/review/execution-plan-boundary.js +8 -11
  116. package/dist/core-runtime/review/issue-artifact-runtime.js +2500 -91
  117. package/dist/core-runtime/review/lens-completion-policy.js +36 -0
  118. package/dist/core-runtime/review/lens-sidecar-artifact.js +344 -0
  119. package/dist/core-runtime/review/lens-sidecar-ledger.js +139 -0
  120. package/dist/core-runtime/review/materializers.js +166 -61
  121. package/dist/core-runtime/review/nesting-batch.js +294 -0
  122. package/dist/core-runtime/review/orchestration-owner.js +35 -0
  123. package/dist/core-runtime/review/packet-boundary-policy.js +204 -5
  124. package/dist/core-runtime/review/participating-lens-paths.js +33 -14
  125. package/dist/core-runtime/review/pipeline-execution-ledger.js +293 -36
  126. package/dist/core-runtime/review/problem-framing-spine.js +67 -0
  127. package/dist/core-runtime/review/review-artifact-utils.js +6 -6
  128. package/dist/core-runtime/review/review-execution-profile.js +240 -38
  129. package/dist/core-runtime/review/review-execution-route.js +87 -18
  130. package/dist/core-runtime/review/review-execution-steps.js +989 -0
  131. package/dist/core-runtime/review/review-invocation-runner.js +42 -19
  132. package/dist/core-runtime/review/review-progress-contract.js +1 -1
  133. package/dist/core-runtime/review/review-record-validation.js +42 -4
  134. package/dist/core-runtime/review/review-result-classification.js +178 -47
  135. package/dist/core-runtime/review/route-visibility.js +349 -21
  136. package/dist/core-runtime/review/semantic-quality-gate.js +515 -0
  137. package/dist/core-runtime/review/synthesis-map-reduce.js +901 -0
  138. package/dist/core-runtime/review/unit-boundary-details.js +56 -0
  139. package/dist/mcp/server.js +182 -40
  140. package/dist/mcp/tool-schemas.js +16 -5
  141. package/package.json +12 -6
  142. package/scripts/check-retired-root-paths.sh +36 -0
  143. package/settings.example.json +227 -25
  144. package/dist/core-runtime/cli/codex-nested-dispatch.js +0 -226
  145. package/dist/core-runtime/cli/codex-nested-teamlead-executor.js +0 -464
  146. package/dist/core-runtime/cli/mock-review-unit-executor.js +0 -302
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Submit salvage recovery — pure decision/merge logic (no I/O, no LLM calls).
3
+ *
4
+ * After a structured-submit unit exhausts its regular retries with
5
+ * `output_contract`, the executor can be re-invoked in salvage mode to
6
+ * recover the already-produced semantics without re-engaging the violating
7
+ * model. This module owns the parts that must be deterministic and
8
+ * unit-testable: failure-mode classification, prompt construction, the
9
+ * invention guard sentinel, and the missing-rows merge. The LLM calls and
10
+ * file I/O stay in the executor; validation/serialization stay in
11
+ * worker-structured-output (same validator as self-submitted payloads).
12
+ *
13
+ * Design: development-records/design/submit-salvage-recovery-design.md.
14
+ */
15
+ /** Invention guard: the transcription model must answer this when the frozen
16
+ * text lacks required content instead of inventing it. */
17
+ export const SALVAGE_INCOMPLETE_SENTINEL = "SALVAGE_INCOMPLETE";
18
+ /** Frozen-input sidecar path for a unit seat (runtime-owned scratch, not the seat). */
19
+ export function salvageInputPathFor(outputPath) {
20
+ return `${outputPath}.salvage-input.json`;
21
+ }
22
+ const MISSING_STANCE_ROWS_PATTERN = /submit_issue_stance_response is missing issue_id\(s\): (.+)$/m;
23
+ /**
24
+ * Classify the recovery path from the frozen failure.
25
+ *
26
+ * - S2 (partial submit, measured case): the payload exists and the validator
27
+ * named the missing stance rows -> bounded delta completion by a fresh
28
+ * same-tier instance (`delta_rows`). v1 covers issue-stance-response only —
29
+ * the other formats are single-object submissions without a row dimension.
30
+ * - S1-prose / S3 (no payload, or field-level violations) -> transcription by
31
+ * the cheap model (`transcription`), guarded by the incompleteness sentinel.
32
+ * - No payload AND no usable text -> unsalvageable (the regular failure
33
+ * stands; salvage never invents content).
34
+ */
35
+ export function classifySalvageMode(args) {
36
+ if (args.payload !== null) {
37
+ const missing = MISSING_STANCE_ROWS_PATTERN.exec(args.error);
38
+ if (missing?.[1] && args.outputFormat === "issue-stance-response") {
39
+ const missingIssueIds = missing[1]
40
+ .split(",")
41
+ .map((id) => id.trim())
42
+ .filter((id) => id.length > 0);
43
+ if (missingIssueIds.length > 0)
44
+ return { mode: "delta_rows", missingIssueIds };
45
+ }
46
+ return { mode: "transcription" };
47
+ }
48
+ if (args.resultText !== null && args.resultText.trim().length > 0) {
49
+ return { mode: "transcription" };
50
+ }
51
+ return {
52
+ mode: "unsalvageable",
53
+ reason: "frozen attempt has neither a structured payload nor result text",
54
+ };
55
+ }
56
+ /**
57
+ * Merge delta stance rows into the partial payload. The partial payload's
58
+ * rows win on duplicate issue_id (first-wins — the original model's accepted
59
+ * semantics stay authoritative; the delta only fills the named gaps).
60
+ */
61
+ export function mergeMissingStanceRows(partial, delta) {
62
+ const partialRows = Array.isArray(partial.stances) ? partial.stances : [];
63
+ const deltaRows = Array.isArray(delta.stances) ? delta.stances : [];
64
+ const seen = new Set(partialRows
65
+ .map((row) => typeof row?.issue_id === "string"
66
+ ? row.issue_id
67
+ : null)
68
+ .filter((id) => id !== null));
69
+ const merged = [
70
+ ...partialRows,
71
+ ...deltaRows.filter((row) => {
72
+ const issueId = row?.issue_id;
73
+ return typeof issueId === "string" && !seen.has(issueId);
74
+ }),
75
+ ];
76
+ return { ...partial, stances: merged };
77
+ }
78
+ /**
79
+ * Path A prompt — transcription only. The salvage model gets the frozen text
80
+ * (and the validator error when one exists) and must transcribe, never
81
+ * author: missing required content aborts via the sentinel.
82
+ */
83
+ export function buildTranscriptionSalvagePrompt(args) {
84
+ return [
85
+ "You are a transcription-only recovery worker. A previous worker produced",
86
+ "the review content below but failed the structured submission contract.",
87
+ "Transcribe that content into the required submission EXACTLY as written —",
88
+ "do NOT add, infer, or repair any semantic content that is not present in",
89
+ "the text. If any REQUIRED field's content is absent from the text, reply",
90
+ `with exactly ${SALVAGE_INCOMPLETE_SENTINEL} and nothing else.`,
91
+ "",
92
+ `Original submission error: ${args.error}`,
93
+ "",
94
+ "--- FROZEN WORKER OUTPUT (transcribe from this only) ---",
95
+ args.resultText,
96
+ "--- END FROZEN WORKER OUTPUT ---",
97
+ ].join("\n");
98
+ }
99
+ /**
100
+ * Path B prompt — bounded delta completion. A fresh same-tier instance gets
101
+ * the original unit packet (full semantic grounding) and must produce ONLY
102
+ * the named missing rows; the runtime merges and re-validates.
103
+ */
104
+ export function buildDeltaRowsSalvagePrompt(args) {
105
+ return [
106
+ args.boundedPrompt,
107
+ "",
108
+ "--- SALVAGE ADDENDUM (bounded delta completion) ---",
109
+ "A previous submission for this unit was accepted except that it is",
110
+ `missing the row(s) for: ${args.missingIssueIds.join(", ")}.`,
111
+ "Submit a payload whose `stances` contains ONLY the missing row(s) listed",
112
+ "above — do not restate rows for any other issue. Every other contract in",
113
+ "the packet (schema, evidence boundaries, lens identity) applies unchanged.",
114
+ ].join("\n");
115
+ }
@@ -0,0 +1,266 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { createLensSidecarSubmissionTools, } from "./lens-sidecar-tools.js";
4
+ import { createRuntimeSubmitTools, isRuntimeSubmitOutputFormat, } from "./structured-output-tools.js";
5
+ import { parseRuntimeSubmitContextForOutputFormat } from "./runtime-submit-context.js";
6
+ import { writeYamlDocument } from "../review/review-artifact-utils.js";
7
+ import { writeValidatedLensSidecarArtifact } from "../review/lens-sidecar-artifact.js";
8
+ export function requireString(value, optionName) {
9
+ if (typeof value !== "string" || value.length === 0) {
10
+ throw new Error(`Missing required option --${optionName}`);
11
+ }
12
+ return value;
13
+ }
14
+ export function parseOutputFormat(raw) {
15
+ if (raw === undefined || raw === "" || raw === "markdown")
16
+ return "markdown";
17
+ if (typeof raw === "string" && isRuntimeSubmitOutputFormat(raw))
18
+ return raw;
19
+ if (raw === "lens-sidecar")
20
+ return raw;
21
+ throw new Error(`Invalid --output-format value for review worker: ${String(raw)} (expected markdown | lens-sidecar | issue-artifact | issue-stance-response | issue-deliberation-response | deliberation-resolution | issue-synthesis-response)`);
22
+ }
23
+ export function submitToolNameForOutputFormat(outputFormat) {
24
+ if (outputFormat === "lens-sidecar")
25
+ return "submit_lens_findings";
26
+ switch (outputFormat) {
27
+ case "issue-artifact":
28
+ return "submit_issue_artifact";
29
+ case "issue-stance-response":
30
+ return "submit_issue_stance_response";
31
+ case "issue-deliberation-response":
32
+ return "submit_issue_deliberation_response";
33
+ case "deliberation-resolution":
34
+ return "submit_deliberation_resolution";
35
+ case "issue-synthesis-response":
36
+ return "submit_issue_synthesis_response";
37
+ }
38
+ }
39
+ export function buildStructuredOutputPrompt(args) {
40
+ const submitToolName = submitToolNameForOutputFormat(args.outputFormat);
41
+ return `You are executing one bounded review structured-output unit as a ContextIsolatedReasoningUnit.
42
+
43
+ Unit id: ${args.unitId}
44
+ Unit kind: ${args.unitKind}
45
+ Output format: ${args.outputFormat}
46
+ Authoritative prompt packet path: ${args.packetPath}
47
+ Canonical YAML output path: ${args.outputPath}
48
+
49
+ Rules:
50
+ - Treat the prompt packet below as the authoritative contract.
51
+ - Treat the Boundary Policy and Effective Boundary State in the packet as hard constraints.
52
+ - Read the files referenced by the prompt packet when needed.
53
+ - Stay within the smallest sufficient file set implied by the packet.
54
+ - Do not recursively follow reference chains beyond the files explicitly listed in the packet unless the packet requires it.
55
+ - Do not use web research when the packet says web research is denied.
56
+ - Do not read outside the allowed filesystem scope described in the packet.
57
+ - Do not modify repository files yourself.
58
+ - Produce only one JSON object matching the provided output schema.
59
+ - The JSON object is the argument payload for ${submitToolName}.
60
+ - Do not wrap the JSON object in markdown or code fences.
61
+ - Do not include runtime-owned envelope fields such as schema_version, session_id, lens_id, issue_id, or validation unless the output schema explicitly requires them.
62
+ - The runtime will validate the JSON object through the submit contract and write the canonical YAML artifact.
63
+ - If the packet asks you to preserve disagreement or uncertainty, preserve it explicitly in the structured fields.
64
+ - If you cannot complete the task within the declared boundary, encode the limitation as insufficient access or insufficient evidence within boundary instead of broadening the search.
65
+
66
+ Authoritative prompt packet follows:
67
+
68
+ ${args.packetText}
69
+ `;
70
+ }
71
+ export function buildBoundedPrompt(packetPath, packetText, outputPath, unitId, unitKind, outputFormat) {
72
+ if (outputFormat !== "markdown") {
73
+ return buildStructuredOutputPrompt({
74
+ packetPath,
75
+ packetText,
76
+ outputPath,
77
+ unitId,
78
+ unitKind,
79
+ outputFormat,
80
+ });
81
+ }
82
+ return `You are executing a single bounded review unit as a ContextIsolatedReasoningUnit.
83
+
84
+ Unit id: ${unitId}
85
+ Unit kind: ${unitKind}
86
+ Authoritative prompt packet path: ${packetPath}
87
+ Canonical output path: ${outputPath}
88
+
89
+ Rules:
90
+ - Treat the prompt packet below as the authoritative contract.
91
+ - Treat the Boundary Policy and Effective Boundary State in the packet as hard constraints.
92
+ - Read the files referenced by the prompt packet when needed.
93
+ - Stay within the smallest sufficient file set implied by the packet.
94
+ - Do not recursively follow reference chains beyond the files explicitly listed in the packet unless the packet requires it.
95
+ - Do not use web research when the packet says web research is denied.
96
+ - Do not read outside the allowed filesystem scope described in the packet.
97
+ - Produce only the final markdown content for the canonical output path.
98
+ - Do not wrap the answer in code fences.
99
+ - Do not add commentary before or after the markdown.
100
+ - Do not modify repository files yourself.
101
+ - Do not change the required output structure from the packet.
102
+ - If the packet asks you to preserve disagreement or uncertainty, preserve it explicitly.
103
+ - If you cannot complete the task within the declared boundary, preserve that limitation explicitly as insufficient access or insufficient evidence within boundary instead of broadening the search.
104
+
105
+ Authoritative prompt packet follows:
106
+
107
+ ${packetText}
108
+ `;
109
+ }
110
+ function requireRecord(value, label) {
111
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
112
+ throw new Error(`${label} must be an object.`);
113
+ }
114
+ return value;
115
+ }
116
+ /**
117
+ * Normalize a JSON Schema into the strict shape external workers require: every
118
+ * object's properties become `required`. Mirrors what the Codex `--output-schema`
119
+ * and Claude `--json-schema` flags expect for structured output.
120
+ */
121
+ export function toWorkerStructuredOutputSchema(schema) {
122
+ if (Array.isArray(schema)) {
123
+ return schema.map((item) => toWorkerStructuredOutputSchema(item));
124
+ }
125
+ if (!schema || typeof schema !== "object") {
126
+ return schema;
127
+ }
128
+ const normalized = {};
129
+ for (const [key, value] of Object.entries(schema)) {
130
+ normalized[key] = toWorkerStructuredOutputSchema(value);
131
+ }
132
+ const properties = normalized.properties;
133
+ if (properties && typeof properties === "object" && !Array.isArray(properties)) {
134
+ normalized.required = Object.keys(properties);
135
+ }
136
+ return normalized;
137
+ }
138
+ /**
139
+ * Build the submit-tool JSON Schema and the submission state for an output
140
+ * format, without writing any file. Codex writes this to disk for its
141
+ * `--output-schema` flag; Claude Code embeds it in the prompt instead.
142
+ */
143
+ export function buildWorkerSubmitSchema(args) {
144
+ return args.outputFormat === "lens-sidecar"
145
+ ? (() => {
146
+ const lensSidecarState = {
147
+ sessionId: args.sessionId,
148
+ lensId: args.unitId,
149
+ humanOutputRef: args.humanOutputRef ?? null,
150
+ };
151
+ const [submitTool] = createLensSidecarSubmissionTools(lensSidecarState);
152
+ if (!submitTool) {
153
+ throw new Error("No lens sidecar submit tool for worker structured output.");
154
+ }
155
+ return {
156
+ state: {
157
+ outputFormat: "lens-sidecar",
158
+ submitToolName: "submit_lens_findings",
159
+ lensSidecarState,
160
+ },
161
+ schema: toWorkerStructuredOutputSchema(submitTool.input_schema),
162
+ };
163
+ })()
164
+ : (() => {
165
+ const runtimeSubmitState = {
166
+ sessionId: args.sessionId,
167
+ unitId: args.unitId,
168
+ outputFormat: args.outputFormat,
169
+ ...parseRuntimeSubmitContextForOutputFormat({
170
+ rawPacketText: args.rawPacketText,
171
+ unitId: args.unitId,
172
+ outputFormat: args.outputFormat,
173
+ }),
174
+ };
175
+ const [submitTool] = createRuntimeSubmitTools(runtimeSubmitState);
176
+ if (!submitTool) {
177
+ throw new Error(`No runtime submit tool for output format ${args.outputFormat}.`);
178
+ }
179
+ return {
180
+ state: {
181
+ outputFormat: args.outputFormat,
182
+ submitToolName: submitTool.name,
183
+ runtimeSubmitState,
184
+ },
185
+ schema: toWorkerStructuredOutputSchema(submitTool.input_schema),
186
+ };
187
+ })();
188
+ }
189
+ /**
190
+ * Build the submit schema and write it to `<rawOutputPath>.schema.json` for
191
+ * workers that consume a schema file on disk (Codex `--output-schema`).
192
+ */
193
+ export async function writeOutputSchemaFile(args) {
194
+ const { schema, state } = buildWorkerSubmitSchema({
195
+ outputFormat: args.outputFormat,
196
+ unitId: args.unitId,
197
+ sessionId: args.sessionId,
198
+ rawPacketText: args.rawPacketText,
199
+ humanOutputRef: args.humanOutputRef ?? null,
200
+ });
201
+ const schemaPath = `${args.rawOutputPath}.schema.json`;
202
+ await fs.mkdir(path.dirname(args.rawOutputPath), { recursive: true });
203
+ await fs.writeFile(schemaPath, `${JSON.stringify(schema, null, 2)}\n`, "utf8");
204
+ return { schemaPath, state };
205
+ }
206
+ export function stripWrappingCodeFence(text) {
207
+ const trimmed = text.trim();
208
+ const match = trimmed.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/);
209
+ return match ? match[1].trim() : trimmed;
210
+ }
211
+ /**
212
+ * Parse and validate a worker's raw structured output text into a submit-tool
213
+ * payload object. Rejects the legacy `payload_json` wrapper. The raw text may be
214
+ * fenced; it is unwrapped first.
215
+ */
216
+ export function coerceStructuredPayload(rawText, label) {
217
+ const raw = stripWrappingCodeFence(rawText);
218
+ try {
219
+ const payload = requireRecord(JSON.parse(raw), label);
220
+ if (Object.prototype.hasOwnProperty.call(payload, "payload_json")) {
221
+ throw new Error("payload_json wrapper is no longer accepted; structured output must be the submit payload object.");
222
+ }
223
+ return payload;
224
+ }
225
+ catch (error) {
226
+ throw new Error(`Failed to parse worker structured output JSON: ${label}: ${error instanceof Error ? error.message : String(error)}`);
227
+ }
228
+ }
229
+ export async function writeRuntimeSubmitArtifactFromPayload(args) {
230
+ const [submitTool] = createRuntimeSubmitTools(args.state);
231
+ if (!submitTool) {
232
+ throw new Error(`No runtime submit tool for output format ${args.state.outputFormat}.`);
233
+ }
234
+ await submitTool.execute(args.payload, {
235
+ projectRoot: "",
236
+ ontoHome: "",
237
+ });
238
+ if (args.state.artifact === undefined) {
239
+ throw new Error(`${args.state.outputFormat} mode completed without ${submitTool.name} for unit ${args.state.unitId}.`);
240
+ }
241
+ await writeYamlDocument(args.outputPath, args.state.artifact);
242
+ return Object.keys(args.payload).length;
243
+ }
244
+ export async function writeLensSidecarArtifactFromPayload(args) {
245
+ const [submitTool] = createLensSidecarSubmissionTools(args.state);
246
+ if (!submitTool) {
247
+ throw new Error("No lens sidecar submit tool for worker structured output.");
248
+ }
249
+ await submitTool.execute(args.payload, {
250
+ projectRoot: "",
251
+ ontoHome: "",
252
+ });
253
+ if (args.state.artifact === undefined) {
254
+ throw new Error(`lens-sidecar mode completed without ${submitTool.name} for unit ${args.state.lensId}.`);
255
+ }
256
+ await writeValidatedLensSidecarArtifact({
257
+ sidecarPath: args.outputPath,
258
+ artifact: args.state.artifact,
259
+ sessionId: args.state.sessionId,
260
+ lensId: args.state.lensId,
261
+ ...(args.state.humanOutputRef !== undefined
262
+ ? { expectedHumanOutputRef: args.state.humanOutputRef }
263
+ : {}),
264
+ });
265
+ return Object.keys(args.payload).length;
266
+ }
@@ -31,3 +31,40 @@ export function detectCodexBinaryAvailable() {
31
31
  return false;
32
32
  return fsSync.existsSync(path.join(os.homedir(), ".codex", "auth.json"));
33
33
  }
34
+ /** OAuth credential filenames Claude Code may write under its config dir. */
35
+ const CLAUDE_OAUTH_CREDENTIAL_FILENAMES = [
36
+ ".credentials.json",
37
+ ".oauth-token",
38
+ ];
39
+ function claudeConfigDir() {
40
+ const configured = process.env.CLAUDE_CONFIG_DIR;
41
+ if (typeof configured === "string" && configured.trim().length > 0) {
42
+ return configured.trim();
43
+ }
44
+ return path.join(os.homedir(), ".claude");
45
+ }
46
+ /**
47
+ * True when the Claude Code worker path can be used from this process.
48
+ *
49
+ * Mirrors {@link detectCodexBinaryAvailable}: both the executable and an OAuth
50
+ * credential are required so the external OAuth worker (`claude_code` adapter)
51
+ * route stays fail-loud when the host-bound worker is unavailable. The config
52
+ * dir honors CLAUDE_CONFIG_DIR; the credential filename is tolerant of the
53
+ * known Claude Code variants.
54
+ */
55
+ export function detectClaudeBinaryAvailable() {
56
+ const pathEnv = process.env.PATH ?? "";
57
+ let claudeOnPath = false;
58
+ for (const dir of pathEnv.split(path.delimiter)) {
59
+ if (!dir)
60
+ continue;
61
+ if (fsSync.existsSync(path.join(dir, "claude"))) {
62
+ claudeOnPath = true;
63
+ break;
64
+ }
65
+ }
66
+ if (!claudeOnPath)
67
+ return false;
68
+ const configDir = claudeConfigDir();
69
+ return CLAUDE_OAUTH_CREDENTIAL_FILENAMES.some((name) => fsSync.existsSync(path.join(configDir, name)));
70
+ }