pi-background-tasks 2.4.2 → 2.6.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.
- package/BACKGROUND-TASKS-INSTRUCTIONS.md +1 -1
- package/README.md +70 -25
- package/TESTING.md +42 -2
- package/TEST_PLAN.md +7 -4
- package/dist/extensions/anthropic-attribution-child.js +4 -0
- package/dist/extensions/anthropic-attribution-child.js.map +1 -0
- package/dist/extensions/anthropic-attribution.js +107 -0
- package/dist/extensions/anthropic-attribution.js.map +1 -0
- package/dist/extensions/background-tasks.js +2 -0
- package/dist/extensions/background-tasks.js.map +1 -0
- package/dist/extensions/delegate-child.js +2 -0
- package/dist/extensions/delegate-child.js.map +1 -0
- package/dist/extensions/fusion-child.js +2 -0
- package/dist/extensions/fusion-child.js.map +1 -0
- package/dist/package.json +5 -0
- package/dist/src/core/anthropic-attribution-path.js +24 -0
- package/dist/src/core/anthropic-attribution-path.js.map +1 -0
- package/dist/src/core/anthropic-attribution.js +2247 -0
- package/dist/src/core/anthropic-attribution.js.map +1 -0
- package/dist/src/core/attested-pi-contract.js +5 -0
- package/dist/src/core/attested-pi-contract.js.map +1 -0
- package/dist/src/core/attested-pi-run.js +749 -0
- package/dist/src/core/attested-pi-run.js.map +1 -0
- package/dist/src/core/canonical-json.js +19 -0
- package/dist/src/core/canonical-json.js.map +1 -0
- package/dist/src/core/common.js +787 -0
- package/dist/src/core/common.js.map +1 -0
- package/dist/src/core/config.js +78 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/context/parent-snapshot.js +75 -0
- package/dist/src/core/context/parent-snapshot.js.map +1 -0
- package/dist/src/core/context/token-budget.js +631 -0
- package/dist/src/core/context/token-budget.js.map +1 -0
- package/dist/src/core/context/visible-conversation-v2.js +390 -0
- package/dist/src/core/context/visible-conversation-v2.js.map +1 -0
- package/dist/src/core/delegate/artifacts.js +357 -0
- package/dist/src/core/delegate/artifacts.js.map +1 -0
- package/dist/src/core/delegate/budget.js +266 -0
- package/dist/src/core/delegate/budget.js.map +1 -0
- package/dist/src/core/delegate/facade-contract.js +7 -0
- package/dist/src/core/delegate/facade-contract.js.map +1 -0
- package/dist/src/core/delegate/hook-contract-evidence.json +18 -0
- package/dist/src/core/delegate/hook-contract.js +124 -0
- package/dist/src/core/delegate/hook-contract.js.map +1 -0
- package/dist/src/core/delegate/launch.js +366 -0
- package/dist/src/core/delegate/launch.js.map +1 -0
- package/dist/src/core/delegate/result-package.js +293 -0
- package/dist/src/core/delegate/result-package.js.map +1 -0
- package/dist/src/core/delegate/runner.js +398 -0
- package/dist/src/core/delegate/runner.js.map +1 -0
- package/dist/src/core/delegate/seed.js +334 -0
- package/dist/src/core/delegate/seed.js.map +1 -0
- package/dist/src/core/delegate/types.js +103 -0
- package/dist/src/core/delegate/types.js.map +1 -0
- package/dist/src/core/durable-fs.js +372 -0
- package/dist/src/core/durable-fs.js.map +1 -0
- package/dist/src/core/extension-api.js +382 -0
- package/dist/src/core/extension-api.js.map +1 -0
- package/dist/src/core/fusion/artifacts.js +654 -0
- package/dist/src/core/fusion/artifacts.js.map +1 -0
- package/dist/src/core/fusion/budget.js +949 -0
- package/dist/src/core/fusion/budget.js.map +1 -0
- package/dist/src/core/fusion/child-protocol.js +176 -0
- package/dist/src/core/fusion/child-protocol.js.map +1 -0
- package/dist/src/core/fusion/claude-cache.js +156 -0
- package/dist/src/core/fusion/claude-cache.js.map +1 -0
- package/dist/src/core/fusion/clean-context.js +64 -0
- package/dist/src/core/fusion/clean-context.js.map +1 -0
- package/dist/src/core/fusion/config.js +349 -0
- package/dist/src/core/fusion/config.js.map +1 -0
- package/dist/src/core/fusion/context.js +184 -0
- package/dist/src/core/fusion/context.js.map +1 -0
- package/dist/src/core/fusion/evaluation.js +696 -0
- package/dist/src/core/fusion/evaluation.js.map +1 -0
- package/dist/src/core/fusion/facade-contract.js +3 -0
- package/dist/src/core/fusion/facade-contract.js.map +1 -0
- package/dist/src/core/fusion/orchestrator.js +867 -0
- package/dist/src/core/fusion/orchestrator.js.map +1 -0
- package/dist/src/core/fusion/output-contract.js +27 -0
- package/dist/src/core/fusion/output-contract.js.map +1 -0
- package/dist/src/core/fusion/pi-child.js +1741 -0
- package/dist/src/core/fusion/pi-child.js.map +1 -0
- package/dist/src/core/fusion/prompts.js +260 -0
- package/dist/src/core/fusion/prompts.js.map +1 -0
- package/dist/src/core/fusion/result-package.js +857 -0
- package/dist/src/core/fusion/result-package.js.map +1 -0
- package/dist/src/core/fusion/source-policy.js +259 -0
- package/dist/src/core/fusion/source-policy.js.map +1 -0
- package/dist/src/core/fusion/types.js +207 -0
- package/dist/src/core/fusion/types.js.map +1 -0
- package/dist/src/core/fusion/web-fetch.js +777 -0
- package/dist/src/core/fusion/web-fetch.js.map +1 -0
- package/dist/src/core/fusion/workflows.js +126 -0
- package/dist/src/core/fusion/workflows.js.map +1 -0
- package/dist/src/core/lazy-module.js +181 -0
- package/dist/src/core/lazy-module.js.map +1 -0
- package/dist/src/core/pi-launch.js +431 -0
- package/dist/src/core/pi-launch.js.map +1 -0
- package/dist/src/core/registry.js +3331 -0
- package/dist/src/core/registry.js.map +1 -0
- package/dist/src/core/reload-shell-owner.js +1396 -0
- package/dist/src/core/reload-shell-owner.js.map +1 -0
- package/dist/src/core/shell-policy.js +80 -0
- package/dist/src/core/shell-policy.js.map +1 -0
- package/dist/src/core/task-durable.js +51 -0
- package/dist/src/core/task-durable.js.map +1 -0
- package/dist/src/core/update-check.js +92 -0
- package/dist/src/core/update-check.js.map +1 -0
- package/dist/src/core/windows-taskkill.js +185 -0
- package/dist/src/core/windows-taskkill.js.map +1 -0
- package/dist/src/delegate-child-extension.js +776 -0
- package/dist/src/delegate-child-extension.js.map +1 -0
- package/dist/src/delegate-extension.js +746 -0
- package/dist/src/delegate-extension.js.map +1 -0
- package/dist/src/extension.js +953 -0
- package/dist/src/extension.js.map +1 -0
- package/dist/src/fusion-child-extension.js +760 -0
- package/dist/src/fusion-child-extension.js.map +1 -0
- package/dist/src/fusion-extension.js +1030 -0
- package/dist/src/fusion-extension.js.map +1 -0
- package/dist/src/ui/background-tasks-manager.js +689 -0
- package/dist/src/ui/background-tasks-manager.js.map +1 -0
- package/dist/src/ui/fusion-model-selector.js +277 -0
- package/dist/src/ui/fusion-model-selector.js.map +1 -0
- package/docs/INDEX.md +35 -33
- package/docs/api/eventbus-v1.md +21 -5
- package/docs/choose-a-workflow.md +2 -0
- package/docs/commands/bg-clear.md +3 -3
- package/docs/commands/bg-update.md +3 -3
- package/docs/commands/bg.md +18 -6
- package/docs/commands/claude-cache.md +6 -6
- package/docs/commands/fusion-models.md +49 -4
- package/docs/commands/fusion.md +3 -3
- package/docs/commands/jobs.md +3 -3
- package/docs/commands/kill.md +3 -3
- package/docs/commands/logs.md +3 -3
- package/docs/commands/task-manager.md +5 -5
- package/docs/concepts/completion-delivery.md +6 -2
- package/docs/getting-started.md +7 -1
- package/docs/manifest.json +228 -42
- package/docs/operations/configuration.md +58 -5
- package/docs/operations/releasing.md +4 -2
- package/docs/operations/testing.md +22 -0
- package/docs/operations/troubleshooting.md +6 -2
- package/docs/read-before-edit.md +44 -31
- package/docs/reference/runtime-contracts.md +87 -51
- package/docs/reference/shortcuts-and-dock.md +28 -14
- package/docs/subsystems/anthropic-attribution.md +35 -13
- package/docs/subsystems/attested-pi-runs.md +12 -7
- package/docs/subsystems/background-task-runtime.md +53 -11
- package/docs/subsystems/child-launch-durability-and-safety.md +28 -9
- package/docs/subsystems/delegation.md +16 -3
- package/docs/subsystems/docs-freshness-gate.md +14 -7
- package/docs/subsystems/fusion.md +36 -11
- package/docs/subsystems/host-ui-and-telemetry.md +22 -9
- package/docs/tools/bg_delegate.md +3 -1
- package/docs/tools/bg_kill.md +3 -1
- package/docs/tools/bg_logs.md +3 -1
- package/docs/tools/bg_result.md +5 -3
- package/docs/tools/bg_run.md +31 -5
- package/docs/tools/bg_run_pi_attested.md +3 -1
- package/docs/tools/bg_status.md +3 -1
- package/docs/tools/fusion_investigate.md +3 -1
- package/docs/tools/fusion_reason.md +3 -1
- package/docs/tools/fusion_research.md +3 -1
- package/docs/tools/fusion_validate.md +3 -1
- package/extensions/anthropic-attribution-child.ts +3 -0
- package/extensions/anthropic-attribution.ts +166 -1
- package/package.json +12 -10
- package/src/core/anthropic-attribution-path.ts +5 -4
- package/src/core/anthropic-attribution.ts +1505 -237
- package/src/core/attested-pi-contract.ts +4 -0
- package/src/core/attested-pi-run.ts +468 -81
- package/src/core/canonical-json.ts +21 -0
- package/src/core/common.ts +450 -40
- package/src/core/config.ts +121 -0
- package/src/core/context/visible-conversation-v2.ts +3 -6
- package/src/core/delegate/artifacts.ts +13 -9
- package/src/core/delegate/budget.ts +13 -6
- package/src/core/delegate/facade-contract.ts +6 -0
- package/src/core/delegate/result-package.ts +32 -14
- package/src/core/delegate/runner.ts +129 -58
- package/src/core/delegate/seed.ts +5 -7
- package/src/core/durable-fs.ts +178 -30
- package/src/core/extension-api.ts +36 -8
- package/src/core/fusion/artifacts.ts +17 -16
- package/src/core/fusion/clean-context.ts +8 -5
- package/src/core/fusion/config.ts +2 -1
- package/src/core/fusion/context.ts +2 -6
- package/src/core/fusion/facade-contract.ts +2 -0
- package/src/core/fusion/orchestrator.ts +3 -3
- package/src/core/fusion/prompts.ts +1 -1
- package/src/core/fusion/result-package.ts +259 -72
- package/src/core/fusion/source-policy.ts +43 -17
- package/src/core/lazy-module.ts +215 -0
- package/src/core/pi-launch.ts +390 -65
- package/src/core/registry.ts +2010 -381
- package/src/core/reload-shell-owner.ts +1662 -0
- package/src/core/shell-policy.ts +134 -0
- package/src/core/task-durable.ts +67 -0
- package/src/delegate-extension.ts +404 -144
- package/src/extension.ts +387 -114
- package/src/fusion-extension.ts +202 -96
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-package.js","sourceRoot":"","sources":["../../../../src/core/fusion/result-package.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstat, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { canonicalJson, sha256Buffer } from '../canonical-json.js';\nimport { parseJsonText, type JsonObject } from '../common.js';\nimport {\n FUSION_FAILURE_SUMMARY_ATTEMPT_CAP,\n FUSION_FAILURE_SUMMARY_EVIDENCE_CAP,\n FUSION_FAILURE_SUMMARY_INLINE_MESSAGE_BYTES,\n FUSION_FAILURE_SUMMARY_MAX_BYTES,\n assertFusionArtifactBasename,\n buildFusionRunProgress,\n} from './artifacts.js';\nimport {\n FUSION_COMMITTED_RESULT_SCHEMA_VERSION,\n FUSION_FAILURE_SUMMARY_SCHEMA_VERSION,\n FUSION_LEGACY_MANIFEST_SCHEMA_VERSION,\n FUSION_MANIFEST_SCHEMA_VERSION,\n FUSION_RESULT_SCHEMA_VERSION,\n FusionError,\n type FusionArtifactRef,\n type FusionFailureAttemptMetadata,\n type FusionFailureEvidenceArtifact,\n type FusionFailureList,\n type FusionFailureResultView,\n type FusionFailureSummaryV1,\n type FusionResultDetails,\n type FusionRunResult,\n type FusionUsage,\n type FusionWorkflowId,\n type FusionRunProgress,\n type FusionSource,\n type FusionStage,\n} from './types.js';\n\nconst SHA256_PATTERN = /^sha256:[0-9a-f]{64}$/u;\n\nfunction isRecord(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction fail(message: string, artifactDir: string): never {\n throw new FusionError(`fusion committed result invalid: ${message}`, {\n code: 'artifact_error',\n childCreated: true,\n artifactDir,\n });\n}\n\nfunction assertOnlyKeys(\n value: JsonObject,\n allowed: readonly string[],\n label: string,\n artifactDir: string,\n): void {\n const unexpected = Object.keys(value).filter((key) => !allowed.includes(key));\n if (unexpected.length > 0)\n fail(`${label} contains unexpected keys: ${unexpected.join(', ')}`, artifactDir);\n}\n\nfunction artifactRef(value: unknown, label: string, artifactDir: string): FusionArtifactRef {\n if (!isRecord(value)) fail(`${label} must be an object`, artifactDir);\n assertOnlyKeys(value, ['path', 'byte_length', 'sha256'], label, artifactDir);\n const path = value['path'];\n const byteLength = value['byte_length'];\n const sha256 = value['sha256'];\n if (typeof path !== 'string') fail(`${label}.path is invalid`, artifactDir);\n try {\n assertFusionArtifactBasename(path);\n } catch {\n fail(`${label}.path is invalid`, artifactDir);\n }\n if (!Number.isSafeInteger(byteLength) || Number(byteLength) < 0) {\n fail(`${label}.byte_length is invalid`, artifactDir);\n }\n if (typeof sha256 !== 'string' || !SHA256_PATTERN.test(sha256)) {\n fail(`${label}.sha256 is invalid`, artifactDir);\n }\n return { path, byte_length: Number(byteLength), sha256 };\n}\n\nfunction usage(value: unknown, artifactDir: string): FusionUsage {\n if (!isRecord(value)) fail('details.usage must be an object', artifactDir);\n assertOnlyKeys(\n value,\n [\n 'input',\n 'output',\n 'cacheRead',\n 'cacheWrite',\n 'cacheWrite1h',\n 'reasoning',\n 'totalTokens',\n 'cost',\n ],\n 'details.usage',\n artifactDir,\n );\n const cost = value['cost'];\n if (!isRecord(cost)) fail('details.usage.cost must be an object', artifactDir);\n assertOnlyKeys(\n cost,\n ['input', 'output', 'cacheRead', 'cacheWrite', 'total'],\n 'details.usage.cost',\n artifactDir,\n );\n const finiteNonnegative = (entry: unknown, label: string): number => {\n if (typeof entry !== 'number' || !Number.isFinite(entry) || entry < 0)\n fail(`${label} is invalid`, artifactDir);\n return entry;\n };\n const output = finiteNonnegative(value['output'], 'details.usage.output');\n const cacheWrite = finiteNonnegative(value['cacheWrite'], 'details.usage.cacheWrite');\n const cacheWrite1h =\n value['cacheWrite1h'] === undefined\n ? undefined\n : finiteNonnegative(value['cacheWrite1h'], 'details.usage.cacheWrite1h');\n const reasoning =\n value['reasoning'] === undefined\n ? undefined\n : finiteNonnegative(value['reasoning'], 'details.usage.reasoning');\n if (cacheWrite1h !== undefined && cacheWrite1h > cacheWrite) {\n fail('details.usage.cacheWrite1h must not exceed cacheWrite', artifactDir);\n }\n if (reasoning !== undefined && reasoning > output) {\n fail('details.usage.reasoning must not exceed output', artifactDir);\n }\n return {\n input: finiteNonnegative(value['input'], 'details.usage.input'),\n output,\n cacheRead: finiteNonnegative(value['cacheRead'], 'details.usage.cacheRead'),\n cacheWrite,\n ...(cacheWrite1h === undefined ? {} : { cacheWrite1h }),\n ...(reasoning === undefined ? {} : { reasoning }),\n totalTokens: finiteNonnegative(value['totalTokens'], 'details.usage.totalTokens'),\n cost: {\n input: finiteNonnegative(cost['input'], 'details.usage.cost.input'),\n output: finiteNonnegative(cost['output'], 'details.usage.cost.output'),\n cacheRead: finiteNonnegative(cost['cacheRead'], 'details.usage.cost.cacheRead'),\n cacheWrite: finiteNonnegative(cost['cacheWrite'], 'details.usage.cost.cacheWrite'),\n total: finiteNonnegative(cost['total'], 'details.usage.cost.total'),\n },\n };\n}\n\nfunction resultDetails(\n value: unknown,\n expected: { runId: string; workflow: FusionWorkflowId; artifactDir: string },\n): FusionResultDetails {\n if (!isRecord(value)) fail('details must be an object', expected.artifactDir);\n assertOnlyKeys(\n value,\n [\n 'schema_version',\n 'run_id',\n 'workflow',\n 'source',\n 'status',\n 'context',\n 'tool_policy',\n 'artifact_dir',\n 'models',\n 'evaluator_attempts',\n 'usage',\n 'budget',\n ],\n 'details',\n expected.artifactDir,\n );\n if (value['schema_version'] !== FUSION_RESULT_SCHEMA_VERSION)\n fail('details schema version mismatch', expected.artifactDir);\n if (value['run_id'] !== expected.runId) fail('details run id mismatch', expected.artifactDir);\n if (value['workflow'] !== expected.workflow)\n fail('details workflow mismatch', expected.artifactDir);\n if (value['source'] !== 'command' && value['source'] !== 'tool')\n fail('details source is invalid', expected.artifactDir);\n if (value['status'] !== 'completed')\n fail('details status is not completed', expected.artifactDir);\n if (value['artifact_dir'] !== expected.artifactDir)\n fail('details artifact directory mismatch', expected.artifactDir);\n const context = value['context'];\n const toolPolicy = value['tool_policy'];\n const models = value['models'];\n const budget = value['budget'];\n if (!isRecord(context) || !isRecord(toolPolicy) || !isRecord(models) || !isRecord(budget)) {\n fail('details nested contract is malformed', expected.artifactDir);\n }\n assertOnlyKeys(context, ['kind', 'policy_id'], 'details.context', expected.artifactDir);\n if (\n (context['kind'] !== 'session_projection' && context['kind'] !== 'clean_task') ||\n typeof context['policy_id'] !== 'string'\n ) {\n fail('details.context is invalid', expected.artifactDir);\n }\n assertOnlyKeys(\n toolPolicy,\n ['candidate_tools', 'evaluation_tools', 'merge_tools'],\n 'details.tool_policy',\n expected.artifactDir,\n );\n const stringArray = (entry: unknown): entry is string[] =>\n Array.isArray(entry) && entry.every((item) => typeof item === 'string');\n if (\n !stringArray(toolPolicy['candidate_tools']) ||\n !Array.isArray(toolPolicy['evaluation_tools']) ||\n toolPolicy['evaluation_tools'].length !== 0 ||\n !Array.isArray(toolPolicy['merge_tools']) ||\n toolPolicy['merge_tools'].length !== 0\n ) {\n fail('details.tool_policy is invalid', expected.artifactDir);\n }\n assertOnlyKeys(\n models,\n ['candidates', 'evaluator', 'merger', 'thinking_level'],\n 'details.models',\n expected.artifactDir,\n );\n if (\n !stringArray(models['candidates']) ||\n models['candidates'].length !== 3 ||\n typeof models['evaluator'] !== 'string' ||\n typeof models['merger'] !== 'string' ||\n typeof models['thinking_level'] !== 'string'\n ) {\n fail('details.models is invalid', expected.artifactDir);\n }\n assertOnlyKeys(\n budget,\n [\n 'policy_id',\n 'calibration_version',\n 'route_table',\n 'rate_sources',\n 'unknown_provider_warnings',\n 'calibration_warnings',\n ],\n 'details.budget',\n expected.artifactDir,\n );\n if (\n typeof budget['policy_id'] !== 'string' ||\n typeof budget['calibration_version'] !== 'string' ||\n !Array.isArray(budget['route_table']) ||\n !Array.isArray(budget['rate_sources']) ||\n !stringArray(budget['unknown_provider_warnings']) ||\n !Array.isArray(budget['calibration_warnings'])\n ) {\n fail('details.budget is invalid', expected.artifactDir);\n }\n if (\n !Number.isSafeInteger(value['evaluator_attempts']) ||\n ![1, 2].includes(Number(value['evaluator_attempts']))\n ) {\n fail('details evaluator_attempts is invalid', expected.artifactDir);\n }\n const checkedUsage = usage(value['usage'], expected.artifactDir);\n const candidates = models['candidates'];\n if (!stringArray(candidates) || candidates.length !== 3)\n fail('details.models candidates are invalid', expected.artifactDir);\n const candidate1 = candidates[0];\n const candidate2 = candidates[1];\n const candidate3 = candidates[2];\n if (candidate1 === undefined || candidate2 === undefined || candidate3 === undefined) {\n fail('details.models candidates are incomplete', expected.artifactDir);\n }\n const source = value['source'];\n const contextKind = context['kind'];\n return {\n schema_version: FUSION_RESULT_SCHEMA_VERSION,\n run_id: expected.runId,\n workflow: expected.workflow,\n source,\n status: 'completed',\n context: { kind: contextKind, policy_id: context['policy_id'] },\n tool_policy: {\n candidate_tools: [...toolPolicy['candidate_tools']],\n evaluation_tools: [],\n merge_tools: [],\n },\n artifact_dir: expected.artifactDir,\n models: {\n candidates: [candidate1, candidate2, candidate3],\n evaluator: models['evaluator'],\n merger: models['merger'],\n thinking_level: models['thinking_level'],\n },\n evaluator_attempts: Number(value['evaluator_attempts']),\n usage: checkedUsage,\n budget: {\n policy_id: budget['policy_id'],\n calibration_version: budget['calibration_version'],\n route_table: budget['route_table'] as FusionResultDetails['budget']['route_table'],\n rate_sources: budget['rate_sources'] as FusionResultDetails['budget']['rate_sources'],\n unknown_provider_warnings: [...budget['unknown_provider_warnings']],\n calibration_warnings: budget[\n 'calibration_warnings'\n ] as FusionResultDetails['budget']['calibration_warnings'],\n },\n };\n}\n\nfunction sameRef(left: FusionArtifactRef, right: FusionArtifactRef): boolean {\n return (\n left.path === right.path &&\n left.byte_length === right.byte_length &&\n left.sha256 === right.sha256\n );\n}\n\nasync function readUtf8(\n path: string,\n label: string,\n artifactDir: string,\n): Promise<{ bytes: Buffer; text: string }> {\n let bytes: Buffer;\n try {\n bytes = await readFile(path);\n } catch (error) {\n fail(\n `${label} is unreadable: ${error instanceof Error ? error.message : String(error)}`,\n artifactDir,\n );\n }\n let text: string;\n try {\n text = new TextDecoder('utf-8', { fatal: true }).decode(bytes);\n } catch {\n fail(`${label} is not well-formed UTF-8`, artifactDir);\n }\n return { bytes, text };\n}\n\n/** Failure retrieval has an additional bounded, no-symlink evidence-file policy. */\nasync function readFailureUtf8(\n path: string,\n label: string,\n artifactDir: string,\n maxBytes: number,\n): Promise<{ bytes: Buffer; text: string }> {\n try {\n const metadata = await lstat(path);\n if (!metadata.isFile() || metadata.isSymbolicLink()) {\n fail(`${label} is not a regular artifact file`, artifactDir);\n }\n if (metadata.size > maxBytes) fail(`${label} exceeds its bounded artifact size`, artifactDir);\n } catch (error) {\n if (error instanceof FusionError) throw error;\n fail(\n `${label} is unreadable: ${error instanceof Error ? error.message : String(error)}`,\n artifactDir,\n );\n }\n const file = await readUtf8(path, label, artifactDir);\n if (file.bytes.length > maxBytes) fail(`${label} exceeds its bounded artifact size`, artifactDir);\n return file;\n}\n\nexport interface ReadFusionCommittedResultOptions {\n artifactDirAbs: string;\n artifactDir: string;\n runId: string;\n workflow: FusionWorkflowId;\n}\n\n/** Verify the manifest-bound Fusion commit before returning merged bytes. */\nexport async function readFusionCommittedResult(\n options: ReadFusionCommittedResultOptions,\n): Promise<FusionRunResult> {\n const manifestFile = await readUtf8(\n join(options.artifactDirAbs, 'manifest.json'),\n 'manifest.json',\n options.artifactDir,\n );\n let manifestValue: unknown;\n try {\n manifestValue = parseJsonText(manifestFile.text);\n } catch (error) {\n fail(\n `manifest.json is invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n options.artifactDir,\n );\n }\n if (!isRecord(manifestValue)) fail('manifest.json must be an object', options.artifactDir);\n if (manifestValue['schema_version'] !== FUSION_MANIFEST_SCHEMA_VERSION)\n fail('manifest schema version mismatch', options.artifactDir);\n if (manifestValue['run_id'] !== options.runId || manifestValue['workflow'] !== options.workflow)\n fail('manifest identity mismatch', options.artifactDir);\n if (manifestValue['state'] !== 'completed')\n fail('manifest is not committed', options.artifactDir);\n const artifacts = manifestValue['artifacts'];\n if (!isRecord(artifacts)) fail('manifest artifacts map is invalid', options.artifactDir);\n const manifestMerged = artifactRef(\n artifacts['merged.md'],\n 'manifest artifacts merged.md',\n options.artifactDir,\n );\n const manifestResult = artifactRef(\n artifacts['result.json'],\n 'manifest artifacts result.json',\n options.artifactDir,\n );\n if (manifestMerged.path !== 'merged.md' || manifestResult.path !== 'result.json')\n fail('manifest fixed artifact paths are invalid', options.artifactDir);\n\n const resultFile = await readUtf8(\n join(options.artifactDirAbs, 'result.json'),\n 'result.json',\n options.artifactDir,\n );\n if (\n resultFile.bytes.length !== manifestResult.byte_length ||\n sha256Buffer(resultFile.bytes) !== manifestResult.sha256\n ) {\n fail('result.json does not match its manifest hash and length', options.artifactDir);\n }\n let resultValue: unknown;\n try {\n resultValue = parseJsonText(resultFile.text);\n } catch (error) {\n fail(\n `result.json is invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n options.artifactDir,\n );\n }\n if (!isRecord(resultValue)) fail('result.json must be an object', options.artifactDir);\n assertOnlyKeys(\n resultValue,\n ['schema_version', 'run_id', 'merged', 'details'],\n 'result.json',\n options.artifactDir,\n );\n if (\n resultValue['schema_version'] !== FUSION_COMMITTED_RESULT_SCHEMA_VERSION ||\n resultValue['run_id'] !== options.runId\n ) {\n fail('result.json identity mismatch', options.artifactDir);\n }\n const committedMerged = artifactRef(\n resultValue['merged'],\n 'result.json merged',\n options.artifactDir,\n );\n if (!sameRef(committedMerged, manifestMerged))\n fail('result.json merged reference does not match manifest', options.artifactDir);\n const details = resultDetails(resultValue['details'], options);\n\n const mergedFile = await readUtf8(\n join(options.artifactDirAbs, 'merged.md'),\n 'merged.md',\n options.artifactDir,\n );\n if (\n mergedFile.bytes.length !== committedMerged.byte_length ||\n sha256Buffer(mergedFile.bytes) !== committedMerged.sha256\n ) {\n fail('merged.md does not match its committed hash and length', options.artifactDir);\n }\n return { mergedText: mergedFile.text, details };\n}\n\n// The public tool adds a small task envelope and text receipt around this view.\n// Keep the verified details below 8 KiB even after that model-visible envelope.\nconst FAILURE_VIEW_MAX_BYTES = 6 * 1024;\nconst FAILURE_CODES = new Set([\n 'config_invalid',\n 'config_conflict',\n 'model_unavailable',\n 'context_capture_failed',\n 'context_policy_unsupported_block',\n 'prompt_budget_exceeded_forecast',\n 'prompt_budget_exceeded_measured',\n 'model_capacity_unknown',\n 'child_spawn_failed',\n 'child_stdin_failed',\n 'child_event_invalid',\n 'child_exit_failed',\n 'child_runtime_limit_exceeded',\n 'child_runtime_payload_invalid',\n 'child_cache_policy_invalid',\n 'child_timeout',\n 'child_output_cap',\n 'child_cancelled',\n 'evaluation_invalid',\n 'artifact_error',\n 'state_transition_invalid',\n 'orchestration_failed',\n]);\nconst FAILURE_REMEDIATION_IDS = new Set([\n 'inspect_manifest_bound_evidence',\n 'inspect_terminal_error',\n 'split_or_reduce_work',\n 'retry_same_route_after_operator_review',\n]);\nconst FAILURE_CLASSIFICATIONS = new Set([\n 'complete_stage_output',\n 'partial_stage_output',\n 'oversized_original',\n 'empty_rejected_output',\n 'evidence_only',\n]);\n\ninterface TrustedFailureManifest {\n schemaVersion: string;\n source: FusionSource;\n state: 'failed' | 'cancelled';\n usage: FusionUsage;\n artifacts: Readonly<Record<string, FusionArtifactRef>>;\n attempts: readonly FusionFailureAttemptMetadata[];\n classifications: Readonly<Record<string, FusionFailureEvidenceArtifact['classification']>>;\n error?: string | undefined;\n}\n\nfunction failureUnavailable(\n state: 'failed' | 'cancelled',\n status: 'unavailable' | 'integrity_failed',\n): FusionFailureResultView {\n return {\n schema_version: FUSION_FAILURE_SUMMARY_SCHEMA_VERSION,\n summary_status: status,\n terminal_state: state,\n answer: { present: false, reason: 'run_did_not_commit' },\n summary_unavailable_reason:\n status === 'unavailable' ? 'manifest_untrusted' : 'summary_integrity_failed',\n };\n}\n\nfunction failureString(value: unknown, label: string): string {\n if (typeof value !== 'string') throw new Error(`${label} must be a string`);\n return value;\n}\n\nfunction failureInteger(value: unknown, label: string): number {\n if (!Number.isSafeInteger(value) || Number(value) < 0)\n throw new Error(`${label} must be a nonnegative integer`);\n return Number(value);\n}\n\nfunction compareFailureText(left: string, right: string): number {\n return left < right ? -1 : left > right ? 1 : 0;\n}\n\nfunction failureStage(value: unknown, label: string): FusionStage {\n if (value === 'candidate' || value === 'evaluation' || value === 'merge') return value;\n throw new Error(`${label} is invalid`);\n}\n\nfunction failureUsage(value: unknown, artifactDir: string): FusionUsage {\n return usage(value, artifactDir);\n}\n\nfunction failureRef(value: unknown, label: string, artifactDir: string): FusionArtifactRef {\n return artifactRef(value, label, artifactDir);\n}\n\nfunction sameFailureRef(left: FusionArtifactRef, right: FusionArtifactRef): boolean {\n return (\n left.path === right.path &&\n left.byte_length === right.byte_length &&\n left.sha256 === right.sha256\n );\n}\n\nfunction trustedFailureManifest(\n value: unknown,\n options: ReadFusionCommittedResultOptions,\n): TrustedFailureManifest {\n if (!isRecord(value)) throw new Error('manifest must be an object');\n const schemaVersion = value['schema_version'];\n if (\n schemaVersion !== FUSION_MANIFEST_SCHEMA_VERSION &&\n schemaVersion !== FUSION_LEGACY_MANIFEST_SCHEMA_VERSION\n )\n throw new Error('manifest schema version mismatch');\n if (value['run_id'] !== options.runId || value['workflow'] !== options.workflow)\n throw new Error('manifest identity mismatch');\n const state = value['state'];\n if (state !== 'failed' && state !== 'cancelled')\n throw new Error('manifest is not failed or cancelled');\n const source = value['source'];\n if (source !== 'command' && source !== 'tool') throw new Error('manifest source is invalid');\n const artifactsValue = value['artifacts'];\n if (!isRecord(artifactsValue)) throw new Error('manifest artifacts are invalid');\n const artifacts: Record<string, FusionArtifactRef> = {};\n for (const [name, ref] of Object.entries(artifactsValue)) {\n assertFusionArtifactBasename(name);\n const checked = failureRef(ref, `manifest artifact ${name}`, options.artifactDir);\n if (checked.path !== name) throw new Error('manifest artifact key/ref divergence');\n artifacts[name] = checked;\n }\n const attemptsValue = value['attempts'];\n if (!Array.isArray(attemptsValue)) throw new Error('manifest attempts are invalid');\n const attempts: FusionFailureAttemptMetadata[] = [];\n const classifications: Record<string, FusionFailureEvidenceArtifact['classification']> = {};\n const attemptArtifact = (entry: unknown, label: string): string | undefined => {\n if (entry === undefined) return undefined;\n const name = failureString(entry, label);\n assertFusionArtifactBasename(name);\n if (artifacts[name] === undefined) throw new Error(`${label} is not manifest-bound`);\n return name;\n };\n for (const attemptValue of attemptsValue) {\n if (!isRecord(attemptValue)) throw new Error('manifest attempt is invalid');\n const metadata = failureAttempt({\n stage: attemptValue['stage'],\n slot: attemptValue['slot'],\n attempt: attemptValue['attempt'],\n status: attemptValue['status'],\n child_created: attemptValue['child_created'],\n });\n attempts.push(metadata);\n const response = attemptArtifact(attemptValue['response_path'], 'manifest response_path');\n if (response !== undefined) {\n const responseRef = artifacts[response];\n if (responseRef === undefined)\n throw new Error('manifest response_path is not manifest-bound');\n classifications[response] =\n responseRef.byte_length === 0 && metadata.status !== 'completed'\n ? 'empty_rejected_output'\n : 'complete_stage_output';\n }\n const partial = attemptArtifact(\n attemptValue['partial_response_path'],\n 'manifest partial_response_path',\n );\n if (partial !== undefined) classifications[partial] = 'partial_stage_output';\n const recovery = attemptValue['output_recovery'];\n if (recovery !== undefined) {\n if (!isRecord(recovery)) throw new Error('manifest output_recovery is invalid');\n const original = attemptArtifact(\n recovery['original_response_path'],\n 'manifest output_recovery.original_response_path',\n );\n if (original === undefined)\n throw new Error('manifest output recovery has no original response');\n classifications[original] = 'oversized_original';\n }\n }\n attempts.sort(\n (left, right) =>\n compareFailureText(left.stage, right.stage) ||\n (left.slot ?? 0) - (right.slot ?? 0) ||\n left.attempt - right.attempt,\n );\n const manifestUsage = failureUsage(value['usage'], options.artifactDir);\n const error = value['error'];\n if (error !== undefined && typeof error !== 'string')\n throw new Error('manifest error is invalid');\n return {\n schemaVersion,\n source,\n state,\n usage: manifestUsage,\n artifacts,\n attempts,\n classifications,\n ...(error === undefined ? {} : { error }),\n };\n}\n\nfunction failureMessage(value: unknown): FusionFailureSummaryV1['failure']['message'] {\n if (!isRecord(value)) throw new Error('failure message is invalid');\n assertOnlyKeys(\n value,\n ['byte_length', 'sha256', 'inline_message', 'omission_reason'],\n 'failure message',\n 'failure-summary.json',\n );\n const byteLength = failureInteger(value['byte_length'], 'failure message byte_length');\n const sha256 = failureString(value['sha256'], 'failure message sha256');\n if (!SHA256_PATTERN.test(sha256)) throw new Error('failure message sha256 is invalid');\n const inline = value['inline_message'];\n const omission = value['omission_reason'];\n if ((inline === undefined) === (omission === undefined))\n throw new Error('failure message must have exactly one representation');\n if (inline !== undefined) {\n if (\n typeof inline !== 'string' ||\n byteLength > FUSION_FAILURE_SUMMARY_INLINE_MESSAGE_BYTES ||\n Buffer.byteLength(inline, 'utf8') !== byteLength ||\n sha256Buffer(Buffer.from(inline, 'utf8')) !== sha256\n ) {\n throw new Error('failure inline message does not match its metadata');\n }\n return { byte_length: byteLength, sha256, inline_message: inline };\n }\n if (omission !== 'exceeds_inline_message_bytes_cap')\n throw new Error('failure message omission reason is invalid');\n return { byte_length: byteLength, sha256, omission_reason: omission };\n}\n\nfunction failureList<T>(\n value: unknown,\n label: string,\n cap: number,\n parseEntry: (entry: unknown) => T,\n): FusionFailureList<T> {\n if (!isRecord(value)) throw new Error(`${label} is invalid`);\n assertOnlyKeys(value, ['listed', 'omitted_count'], label, 'failure-summary.json');\n if (!Array.isArray(value['listed']) || value['listed'].length > cap)\n throw new Error(`${label}.listed is invalid`);\n return {\n listed: value['listed'].map(parseEntry),\n omitted_count: failureInteger(value['omitted_count'], `${label}.omitted_count`),\n };\n}\n\nfunction failureAttempt(value: unknown): FusionFailureAttemptMetadata {\n if (!isRecord(value)) throw new Error('failure attempt is invalid');\n assertOnlyKeys(\n value,\n ['stage', 'slot', 'attempt', 'status', 'child_created'],\n 'failure attempt',\n 'failure-summary.json',\n );\n const stage = failureStage(value['stage'], 'failure attempt stage');\n const slot = value['slot'];\n if (slot !== undefined && slot !== 1 && slot !== 2 && slot !== 3)\n throw new Error('failure attempt slot is invalid');\n if ((stage === 'candidate') !== (slot !== undefined))\n throw new Error('failure attempt stage/slot is inconsistent');\n const status = value['status'];\n if (status !== 'completed' && status !== 'failed' && status !== 'cancelled')\n throw new Error('failure attempt status is invalid');\n if (typeof value['child_created'] !== 'boolean')\n throw new Error('failure attempt child_created is invalid');\n const attempt = failureInteger(value['attempt'], 'failure attempt number');\n if (attempt === 0) throw new Error('failure attempt number must be positive');\n return {\n stage,\n ...(slot === undefined ? {} : { slot }),\n attempt,\n status,\n child_created: value['child_created'],\n };\n}\n\nfunction failureEvidence(\n value: unknown,\n manifest: TrustedFailureManifest,\n artifactDir: string,\n): FusionFailureEvidenceArtifact {\n if (!isRecord(value)) throw new Error('failure evidence row is invalid');\n assertOnlyKeys(value, ['name', 'classification', 'ref'], 'failure evidence row', artifactDir);\n const name = failureString(value['name'], 'failure evidence name');\n assertFusionArtifactBasename(name);\n const classification = value['classification'];\n if (typeof classification !== 'string' || !FAILURE_CLASSIFICATIONS.has(classification))\n throw new Error('failure evidence classification is invalid');\n const ref = failureRef(value['ref'], 'failure evidence ref', artifactDir);\n const manifestRef = manifest.artifacts[name];\n if (manifestRef === undefined || !sameFailureRef(ref, manifestRef))\n throw new Error('failure evidence ref diverges from manifest');\n const expectedClassification = manifest.classifications[name] ?? 'evidence_only';\n if (classification !== expectedClassification)\n throw new Error('failure evidence classification diverges from manifest');\n return { name, classification: expectedClassification, ref };\n}\n\nfunction failureProgress(\n value: unknown,\n manifest: TrustedFailureManifest,\n artifactDir: string,\n): FusionRunProgress {\n if (!isRecord(value)) throw new Error('failure progress is invalid');\n assertOnlyKeys(\n value,\n ['manifest_state', 'candidates', 'evaluation', 'merge', 'usage_so_far'],\n 'failure progress',\n artifactDir,\n );\n if (value['manifest_state'] !== manifest.state)\n throw new Error('failure progress state diverges from manifest');\n const stage = (\n entry: unknown,\n label: string,\n candidates: boolean,\n ): FusionRunProgress['candidates'] => {\n if (!isRecord(entry)) throw new Error(`${label} is invalid`);\n assertOnlyKeys(\n entry,\n [\n 'status',\n 'attempts_recorded',\n 'children_created',\n 'children_completed',\n 'children_failed',\n 'children_cancelled',\n 'not_started_slots',\n ],\n label,\n artifactDir,\n );\n const status = entry['status'];\n if (status !== 'not_started' && status !== 'incomplete' && status !== 'completed')\n throw new Error(`${label}.status is invalid`);\n const notStarted = entry['not_started_slots'];\n if (\n candidates\n ? !Number.isSafeInteger(notStarted) || Number(notStarted) < 0 || Number(notStarted) > 3\n : notStarted !== undefined\n )\n throw new Error(`${label}.not_started_slots is invalid`);\n return {\n status,\n attempts_recorded: failureInteger(entry['attempts_recorded'], `${label}.attempts_recorded`),\n children_created: failureInteger(entry['children_created'], `${label}.children_created`),\n children_completed: failureInteger(\n entry['children_completed'],\n `${label}.children_completed`,\n ),\n children_failed: failureInteger(entry['children_failed'], `${label}.children_failed`),\n children_cancelled: failureInteger(\n entry['children_cancelled'],\n `${label}.children_cancelled`,\n ),\n ...(candidates ? { not_started_slots: Number(notStarted) } : {}),\n };\n };\n const usageSoFar = failureUsage(value['usage_so_far'], artifactDir);\n if (canonicalJson(usageSoFar) !== canonicalJson(manifest.usage))\n throw new Error('failure progress usage diverges from manifest');\n return {\n manifest_state: manifest.state,\n candidates: stage(value['candidates'], 'failure candidates', true),\n evaluation: stage(value['evaluation'], 'failure evaluation', false),\n merge: stage(value['merge'], 'failure merge', false),\n usage_so_far: usageSoFar,\n };\n}\n\nfunction parseFailureSummary(\n value: unknown,\n manifest: TrustedFailureManifest,\n options: ReadFusionCommittedResultOptions,\n): FusionFailureSummaryV1 {\n if (!isRecord(value)) throw new Error('failure summary must be an object');\n assertOnlyKeys(\n value,\n [\n 'schema_version',\n 'run_id',\n 'workflow',\n 'source',\n 'terminal_state',\n 'created_at',\n 'answer',\n 'failure',\n 'progress',\n 'usage_so_far',\n 'attempts',\n 'evidence_artifacts',\n 'remediation_ids',\n ],\n 'failure summary',\n options.artifactDir,\n );\n if (\n value['schema_version'] !== FUSION_FAILURE_SUMMARY_SCHEMA_VERSION ||\n value['run_id'] !== options.runId ||\n value['workflow'] !== options.workflow ||\n value['source'] !== manifest.source ||\n value['terminal_state'] !== manifest.state ||\n typeof value['created_at'] !== 'string'\n )\n throw new Error('failure summary identity is invalid');\n const answer = value['answer'];\n if (!isRecord(answer) || answer['present'] !== false || answer['reason'] !== 'run_did_not_commit')\n throw new Error('failure summary answer assertion is invalid');\n const failure = value['failure'];\n if (!isRecord(failure)) throw new Error('failure summary failure metadata is invalid');\n assertOnlyKeys(\n failure,\n ['code', 'stage', 'slot', 'attempt', 'child_created', 'message'],\n 'failure metadata',\n options.artifactDir,\n );\n const code = failure['code'];\n if (code !== null && (typeof code !== 'string' || !FAILURE_CODES.has(code)))\n throw new Error('failure code is invalid');\n const stageValue = failure['stage'];\n const stage = stageValue === undefined ? undefined : failureStage(stageValue, 'failure stage');\n const slot = failure['slot'];\n if (slot !== undefined && slot !== 1 && slot !== 2 && slot !== 3)\n throw new Error('failure slot is invalid');\n if (failure['attempt'] !== undefined) failureInteger(failure['attempt'], 'failure attempt');\n if (typeof failure['child_created'] !== 'boolean')\n throw new Error('failure child_created is invalid');\n const progress = failureProgress(value['progress'], manifest, options.artifactDir);\n const expectedProgress = buildFusionRunProgress(manifest);\n if (canonicalJson(progress) !== canonicalJson(expectedProgress))\n throw new Error('failure progress diverges from durable attempts');\n const usageSoFar = failureUsage(value['usage_so_far'], options.artifactDir);\n if (canonicalJson(usageSoFar) !== canonicalJson(manifest.usage))\n throw new Error('summary usage diverges from manifest');\n const attempts = failureList(\n value['attempts'],\n 'failure attempts',\n FUSION_FAILURE_SUMMARY_ATTEMPT_CAP,\n failureAttempt,\n );\n const expectedAttempts = manifest.attempts;\n const expectedAttemptListedCount = Math.min(\n expectedAttempts.length,\n FUSION_FAILURE_SUMMARY_ATTEMPT_CAP,\n );\n if (\n attempts.listed.length !== expectedAttemptListedCount ||\n attempts.omitted_count !== expectedAttempts.length - expectedAttemptListedCount ||\n canonicalJson(attempts.listed) !==\n canonicalJson(\n expectedAttempts.filter((_attempt, index) => index < expectedAttemptListedCount),\n )\n ) {\n throw new Error('failure attempt metadata diverges from manifest');\n }\n const evidence = failureList(\n value['evidence_artifacts'],\n 'failure evidence artifacts',\n FUSION_FAILURE_SUMMARY_EVIDENCE_CAP,\n (entry) => failureEvidence(entry, manifest, options.artifactDir),\n );\n const expectedEvidence = Object.entries(manifest.artifacts)\n .filter(([name]) => name !== 'failure-summary.json')\n .map(([name, ref]) => ({\n name,\n classification: manifest.classifications[name] ?? 'evidence_only',\n ref,\n }))\n .sort((left, right) => compareFailureText(left.name, right.name));\n const expectedEvidenceListedCount = Math.min(\n expectedEvidence.length,\n FUSION_FAILURE_SUMMARY_EVIDENCE_CAP,\n );\n if (\n evidence.listed.length !== expectedEvidenceListedCount ||\n evidence.omitted_count !== expectedEvidence.length - expectedEvidenceListedCount ||\n canonicalJson(evidence.listed) !==\n canonicalJson(\n expectedEvidence.filter((_evidence, index) => index < expectedEvidenceListedCount),\n )\n ) {\n throw new Error('failure evidence metadata diverges from manifest');\n }\n const remediationIds = value['remediation_ids'];\n const expectedRemediationIds = [\n 'inspect_manifest_bound_evidence',\n 'inspect_terminal_error',\n 'split_or_reduce_work',\n 'retry_same_route_after_operator_review',\n ];\n if (\n !Array.isArray(remediationIds) ||\n !remediationIds.every((id) => typeof id === 'string' && FAILURE_REMEDIATION_IDS.has(id)) ||\n canonicalJson(remediationIds) !== canonicalJson(expectedRemediationIds)\n ) {\n throw new Error('failure remediation ids are invalid');\n }\n const terminalMessage = failureMessage(failure['message']);\n if (manifest.error === undefined) throw new Error('manifest terminal error is unavailable');\n const manifestErrorBytes = Buffer.from(manifest.error, 'utf8');\n const expectedMessage = {\n byte_length: manifestErrorBytes.length,\n sha256: sha256Buffer(manifestErrorBytes),\n ...(manifestErrorBytes.length <= FUSION_FAILURE_SUMMARY_INLINE_MESSAGE_BYTES\n ? { inline_message: manifest.error }\n : { omission_reason: 'exceeds_inline_message_bytes_cap' as const }),\n };\n if (canonicalJson(terminalMessage) !== canonicalJson(expectedMessage))\n throw new Error('failure message diverges from manifest terminal error');\n return {\n schema_version: FUSION_FAILURE_SUMMARY_SCHEMA_VERSION,\n run_id: options.runId,\n workflow: options.workflow,\n source: manifest.source,\n terminal_state: manifest.state,\n created_at: value['created_at'],\n answer: { present: false, reason: 'run_did_not_commit' },\n failure: {\n code: code as FusionFailureSummaryV1['failure']['code'],\n ...(stage === undefined ? {} : { stage }),\n ...(slot === undefined ? {} : { slot }),\n ...(failure['attempt'] === undefined ? {} : { attempt: Number(failure['attempt']) }),\n child_created: failure['child_created'],\n message: terminalMessage,\n },\n progress,\n usage_so_far: usageSoFar,\n attempts,\n evidence_artifacts: evidence,\n remediation_ids: [...remediationIds] as FusionFailureSummaryV1['remediation_ids'],\n };\n}\n\ninterface FailureViewSource {\n terminal_state: Exclude<FusionFailureResultView['terminal_state'], 'completed'>;\n failure?: FusionFailureResultView['failure'] | undefined;\n progress: FusionRunProgress;\n usage_so_far: FusionUsage;\n attempts: FusionFailureList<FusionFailureAttemptMetadata>;\n evidence_artifacts: FusionFailureList<FusionFailureEvidenceArtifact>;\n remediation_ids: FusionFailureSummaryV1['remediation_ids'];\n}\n\nfunction boundedFailureView(\n source: FailureViewSource,\n status: FusionFailureResultView['summary_status'],\n summaryRef?: FusionArtifactRef,\n): FusionFailureResultView {\n const attempts = {\n listed: [...source.attempts.listed],\n omitted_count: source.attempts.omitted_count,\n };\n const evidence = {\n listed: [...source.evidence_artifacts.listed],\n omitted_count: source.evidence_artifacts.omitted_count,\n };\n const failure = source.failure;\n const view: FusionFailureResultView = {\n schema_version: FUSION_FAILURE_SUMMARY_SCHEMA_VERSION,\n summary_status: status,\n terminal_state: source.terminal_state,\n answer: { present: false, reason: 'run_did_not_commit' },\n ...(failure === undefined ? {} : { failure: { ...failure, message: { ...failure.message } } }),\n progress: source.progress,\n usage_so_far: source.usage_so_far,\n attempts,\n evidence_artifacts: evidence,\n remediation_ids: source.remediation_ids,\n ...(summaryRef === undefined ? {} : { failure_summary_ref: summaryRef }),\n };\n const fits = (): boolean =>\n Buffer.byteLength(canonicalJson(view), 'utf8') <= FAILURE_VIEW_MAX_BYTES;\n if (!fits() && view.failure?.message.inline_message !== undefined) {\n const message = view.failure.message;\n view.failure = {\n ...view.failure,\n message: {\n byte_length: message.byte_length,\n sha256: message.sha256,\n omission_reason: 'result_view_byte_budget',\n },\n };\n }\n while (!fits() && evidence.listed.length > 0) {\n evidence.listed.pop();\n evidence.omitted_count += 1;\n }\n while (!fits() && attempts.listed.length > 0) {\n attempts.listed.pop();\n attempts.omitted_count += 1;\n }\n if (!fits())\n throw new Error(\n 'failure result view exceeds its byte budget without a safe whole-section omission',\n );\n return view;\n}\n\nfunction legacyFailureSource(manifest: TrustedFailureManifest): FailureViewSource {\n const message =\n manifest.error === undefined\n ? undefined\n : (() => {\n const bytes = Buffer.from(manifest.error, 'utf8');\n return bytes.length <= FUSION_FAILURE_SUMMARY_INLINE_MESSAGE_BYTES\n ? {\n byte_length: bytes.length,\n sha256: sha256Buffer(bytes),\n inline_message: manifest.error,\n }\n : {\n byte_length: bytes.length,\n sha256: sha256Buffer(bytes),\n omission_reason: 'exceeds_inline_message_bytes_cap' as const,\n };\n })();\n const evidence = Object.entries(manifest.artifacts)\n .map(([name, ref]) => ({\n name,\n classification: manifest.classifications[name] ?? 'evidence_only',\n ref: { ...ref },\n }))\n .sort((left, right) => compareFailureText(left.name, right.name));\n const attempts = manifest.attempts;\n return {\n terminal_state: manifest.state,\n ...(message === undefined ? {} : { failure: { message } }),\n progress: buildFusionRunProgress(manifest),\n usage_so_far: manifest.usage,\n attempts: {\n listed: attempts.filter((_attempt, index) => index < FUSION_FAILURE_SUMMARY_ATTEMPT_CAP),\n omitted_count:\n attempts.length - Math.min(attempts.length, FUSION_FAILURE_SUMMARY_ATTEMPT_CAP),\n },\n evidence_artifacts: {\n listed: evidence.filter((_evidence, index) => index < FUSION_FAILURE_SUMMARY_EVIDENCE_CAP),\n omitted_count:\n evidence.length - Math.min(evidence.length, FUSION_FAILURE_SUMMARY_EVIDENCE_CAP),\n },\n remediation_ids: ['inspect_manifest_bound_evidence', 'inspect_terminal_error'],\n };\n}\n\n/** Read only terminal failure metadata; it never reads stage-output bodies. */\nexport async function readFusionFailureResult(\n options: ReadFusionCommittedResultOptions,\n): Promise<FusionFailureResultView> {\n let manifest: TrustedFailureManifest;\n try {\n const file = await readUtf8(\n join(options.artifactDirAbs, 'manifest.json'),\n 'manifest.json',\n options.artifactDir,\n );\n manifest = trustedFailureManifest(parseJsonText(file.text), options);\n } catch {\n return failureUnavailable('failed', 'unavailable');\n }\n const summaryRef = manifest.artifacts['failure-summary.json'];\n if (summaryRef === undefined) {\n return boundedFailureView(legacyFailureSource(manifest), 'legacy_manifest_only');\n }\n if (\n manifest.schemaVersion !== FUSION_MANIFEST_SCHEMA_VERSION ||\n summaryRef.path !== 'failure-summary.json'\n )\n return failureUnavailable(manifest.state, 'integrity_failed');\n try {\n if (summaryRef.byte_length > FUSION_FAILURE_SUMMARY_MAX_BYTES)\n throw new Error('failure summary exceeds its bounded artifact size');\n const file = await readFailureUtf8(\n join(options.artifactDirAbs, summaryRef.path),\n 'failure-summary.json',\n options.artifactDir,\n FUSION_FAILURE_SUMMARY_MAX_BYTES,\n );\n if (\n file.bytes.length !== summaryRef.byte_length ||\n sha256Buffer(file.bytes) !== summaryRef.sha256\n )\n throw new Error('failure summary hash/length mismatch');\n const summary = parseFailureSummary(parseJsonText(file.text), manifest, options);\n return boundedFailureView(summary, 'verified', summaryRef);\n } catch {\n return failureUnavailable(manifest.state, 'integrity_failed');\n }\n}\n"]}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { constants } from 'node:fs';
|
|
3
|
+
import { open } from 'node:fs/promises';
|
|
4
|
+
import { isIP } from 'node:net';
|
|
5
|
+
import { canonicalJson } from '../canonical-json.js';
|
|
6
|
+
import { isJsonObject, parseJsonText } from '../common.js';
|
|
7
|
+
import { FUSION_SOURCE_POLICY_SCHEMA_VERSION, FusionError, } from './types.js';
|
|
8
|
+
const SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
9
|
+
const O_NOFOLLOW = typeof constants.O_NOFOLLOW === 'number' ? constants.O_NOFOLLOW : 0;
|
|
10
|
+
function sha256Text(value) {
|
|
11
|
+
return createHash('sha256').update(value, 'utf8').digest('hex');
|
|
12
|
+
}
|
|
13
|
+
function stripIpv6Brackets(hostname) {
|
|
14
|
+
return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;
|
|
15
|
+
}
|
|
16
|
+
function isBlockedHostname(hostname) {
|
|
17
|
+
const lower = hostname.toLowerCase();
|
|
18
|
+
return (lower === 'localhost' ||
|
|
19
|
+
lower.endsWith('.localhost') ||
|
|
20
|
+
lower === 'metadata' ||
|
|
21
|
+
lower === 'metadata.local' ||
|
|
22
|
+
lower === 'metadata.google.internal' ||
|
|
23
|
+
lower === 'metadata.goog' ||
|
|
24
|
+
lower === 'instance-data' ||
|
|
25
|
+
lower === 'instance-data.ec2.internal');
|
|
26
|
+
}
|
|
27
|
+
function isBlockedIpv4(host) {
|
|
28
|
+
const parts = host.split('.').map((part) => Number.parseInt(part, 10));
|
|
29
|
+
if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255))
|
|
30
|
+
return true;
|
|
31
|
+
const [a = 0, b = 0, c = 0] = parts;
|
|
32
|
+
if (a === 0 || a === 10 || a === 127)
|
|
33
|
+
return true;
|
|
34
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
35
|
+
return true;
|
|
36
|
+
if (a === 169 && b === 254)
|
|
37
|
+
return true;
|
|
38
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
39
|
+
return true;
|
|
40
|
+
if (a === 192 && b === 168)
|
|
41
|
+
return true;
|
|
42
|
+
if (a === 192 && b === 0 && c === 0)
|
|
43
|
+
return true;
|
|
44
|
+
if (a === 192 && b === 0 && c === 2)
|
|
45
|
+
return true;
|
|
46
|
+
if (a === 198 && (b === 18 || b === 19))
|
|
47
|
+
return true;
|
|
48
|
+
if (a === 198 && b === 51 && c === 100)
|
|
49
|
+
return true;
|
|
50
|
+
if (a === 203 && b === 0 && c === 113)
|
|
51
|
+
return true;
|
|
52
|
+
if (a >= 224)
|
|
53
|
+
return true;
|
|
54
|
+
return host === '255.255.255.255' || host === '168.63.129.16';
|
|
55
|
+
}
|
|
56
|
+
function isBlockedIpv6(host) {
|
|
57
|
+
const lower = host.toLowerCase();
|
|
58
|
+
return (lower === '::' ||
|
|
59
|
+
lower === '::1' ||
|
|
60
|
+
lower.startsWith('::ffff:') ||
|
|
61
|
+
lower.startsWith('64:ff9b::') ||
|
|
62
|
+
lower.startsWith('64:ff9b:1:') ||
|
|
63
|
+
lower.startsWith('100:') ||
|
|
64
|
+
lower.startsWith('2001:2:') ||
|
|
65
|
+
lower.startsWith('2001:db8:') ||
|
|
66
|
+
lower.startsWith('2002:') ||
|
|
67
|
+
lower.startsWith('fc') ||
|
|
68
|
+
lower.startsWith('fd') ||
|
|
69
|
+
lower.startsWith('fe8') ||
|
|
70
|
+
lower.startsWith('fe9') ||
|
|
71
|
+
lower.startsWith('fea') ||
|
|
72
|
+
lower.startsWith('feb') ||
|
|
73
|
+
lower.startsWith('ff'));
|
|
74
|
+
}
|
|
75
|
+
export function canonicalizeFusionPublicUrl(value) {
|
|
76
|
+
let url;
|
|
77
|
+
try {
|
|
78
|
+
url = new URL(value);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
throw new FusionError(`fusion research declared source URL is malformed: ${error instanceof Error ? error.message : String(error)}`, { code: 'orchestration_failed', childCreated: false });
|
|
82
|
+
}
|
|
83
|
+
if (url.username !== '' || url.password !== '') {
|
|
84
|
+
throw new FusionError('fusion research source URL must not contain credentials', {
|
|
85
|
+
code: 'orchestration_failed',
|
|
86
|
+
childCreated: false,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
90
|
+
throw new FusionError('fusion research source URL must use http or https', {
|
|
91
|
+
code: 'orchestration_failed',
|
|
92
|
+
childCreated: false,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
url.username = '';
|
|
96
|
+
url.password = '';
|
|
97
|
+
url.hash = '';
|
|
98
|
+
const normalizedHost = stripIpv6Brackets(url.hostname.toLowerCase().replace(/\.+$/u, ''));
|
|
99
|
+
url.hostname = normalizedHost;
|
|
100
|
+
if (isBlockedHostname(normalizedHost)) {
|
|
101
|
+
throw new FusionError('fusion research source URL must be public, not localhost/metadata', {
|
|
102
|
+
code: 'orchestration_failed',
|
|
103
|
+
childCreated: false,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const ipKind = isIP(normalizedHost);
|
|
107
|
+
if ((ipKind === 4 && isBlockedIpv4(normalizedHost)) ||
|
|
108
|
+
(ipKind === 6 && isBlockedIpv6(normalizedHost))) {
|
|
109
|
+
throw new FusionError('fusion research source URL must be public, not private/reserved', {
|
|
110
|
+
code: 'orchestration_failed',
|
|
111
|
+
childCreated: false,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if ((url.protocol === 'http:' && url.port === '80') ||
|
|
115
|
+
(url.protocol === 'https:' && url.port === '443')) {
|
|
116
|
+
url.port = '';
|
|
117
|
+
}
|
|
118
|
+
return url.toString();
|
|
119
|
+
}
|
|
120
|
+
export function normalizeFusionDeclaredSources(sources = []) {
|
|
121
|
+
const seen = new Map();
|
|
122
|
+
return sources.map((source, index) => {
|
|
123
|
+
if (typeof source.url !== 'string' || source.url.trim().length === 0) {
|
|
124
|
+
throw new FusionError(`fusion research source ${String(index)} requires non-blank URL`, {
|
|
125
|
+
code: 'orchestration_failed',
|
|
126
|
+
childCreated: false,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (typeof source.purpose !== 'string' || source.purpose.trim().length === 0) {
|
|
130
|
+
throw new FusionError(`fusion research source ${String(index)} requires non-blank purpose`, {
|
|
131
|
+
code: 'orchestration_failed',
|
|
132
|
+
childCreated: false,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
const canonicalUrl = canonicalizeFusionPublicUrl(source.url.trim());
|
|
136
|
+
const previous = seen.get(canonicalUrl);
|
|
137
|
+
if (previous !== undefined) {
|
|
138
|
+
throw new FusionError(`fusion research source ${String(index)} duplicates canonical URL from source ${String(previous)}: ${canonicalUrl}`, { code: 'orchestration_failed', childCreated: false });
|
|
139
|
+
}
|
|
140
|
+
seen.set(canonicalUrl, index);
|
|
141
|
+
const purpose = source.purpose.trim();
|
|
142
|
+
return {
|
|
143
|
+
url: canonicalUrl,
|
|
144
|
+
canonical_url: canonicalUrl,
|
|
145
|
+
purpose,
|
|
146
|
+
sha256: sha256Text(`${canonicalUrl}\u0000${purpose}`),
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
export function buildFusionSourcePolicy(cwd, sources) {
|
|
151
|
+
const body = {
|
|
152
|
+
schema_version: FUSION_SOURCE_POLICY_SCHEMA_VERSION,
|
|
153
|
+
workflow: 'research',
|
|
154
|
+
cwd,
|
|
155
|
+
sources,
|
|
156
|
+
};
|
|
157
|
+
return { ...body, root_sha256: sha256Text(canonicalJson(body)) };
|
|
158
|
+
}
|
|
159
|
+
export function sourcePolicyCanonicalBytes(policy) {
|
|
160
|
+
return canonicalJson(policy);
|
|
161
|
+
}
|
|
162
|
+
function requireString(record, key, label) {
|
|
163
|
+
const value = record[key];
|
|
164
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
165
|
+
throw new Error(`${label}.${key} must be non-blank string`);
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
export function parseFusionSourcePolicy(value) {
|
|
169
|
+
if (!isJsonObject(value) || Array.isArray(value))
|
|
170
|
+
throw new Error('fusion source policy must be object');
|
|
171
|
+
const keys = Object.keys(value).sort();
|
|
172
|
+
const expected = ['cwd', 'root_sha256', 'schema_version', 'sources', 'workflow'];
|
|
173
|
+
if (keys.join('\0') !== expected.join('\0'))
|
|
174
|
+
throw new Error('fusion source policy keys mismatch');
|
|
175
|
+
if (value['schema_version'] !== FUSION_SOURCE_POLICY_SCHEMA_VERSION)
|
|
176
|
+
throw new Error('fusion source policy schema_version mismatch');
|
|
177
|
+
if (value['workflow'] !== 'research')
|
|
178
|
+
throw new Error('fusion source policy workflow must be research');
|
|
179
|
+
const cwd = requireString(value, 'cwd', 'fusion source policy');
|
|
180
|
+
const rootSha256 = requireString(value, 'root_sha256', 'fusion source policy');
|
|
181
|
+
if (!SHA256_HEX.test(rootSha256))
|
|
182
|
+
throw new Error('fusion source policy.root_sha256 must be sha256');
|
|
183
|
+
if (!Array.isArray(value['sources']))
|
|
184
|
+
throw new Error('fusion source policy.sources must be array');
|
|
185
|
+
const sources = value['sources'].map((item, index) => {
|
|
186
|
+
const label = `fusion source policy.sources[${String(index)}]`;
|
|
187
|
+
if (!isJsonObject(item) || Array.isArray(item))
|
|
188
|
+
throw new Error(`${label} must be object`);
|
|
189
|
+
const itemKeys = Object.keys(item).sort();
|
|
190
|
+
const itemExpected = ['canonical_url', 'purpose', 'sha256', 'url'];
|
|
191
|
+
if (itemKeys.join('\0') !== itemExpected.join('\0'))
|
|
192
|
+
throw new Error(`${label} keys mismatch`);
|
|
193
|
+
const url = requireString(item, 'url', label);
|
|
194
|
+
const purpose = requireString(item, 'purpose', label);
|
|
195
|
+
const canonical_url = requireString(item, 'canonical_url', label);
|
|
196
|
+
const sha256 = requireString(item, 'sha256', label);
|
|
197
|
+
if (!SHA256_HEX.test(sha256))
|
|
198
|
+
throw new Error(`${label}.sha256 must be sha256`);
|
|
199
|
+
if (canonicalizeFusionPublicUrl(url) !== canonical_url)
|
|
200
|
+
throw new Error(`${label}.canonical_url mismatch`);
|
|
201
|
+
if (url !== canonical_url)
|
|
202
|
+
throw new Error(`${label}.url must equal canonical_url`);
|
|
203
|
+
if (purpose.trim() !== purpose)
|
|
204
|
+
throw new Error(`${label}.purpose must be trimmed`);
|
|
205
|
+
if (sha256Text(`${canonical_url}\u0000${purpose}`) !== sha256)
|
|
206
|
+
throw new Error(`${label}.sha256 mismatch`);
|
|
207
|
+
return { url, canonical_url, purpose, sha256 };
|
|
208
|
+
});
|
|
209
|
+
const seen = new Set();
|
|
210
|
+
for (const [index, source] of sources.entries()) {
|
|
211
|
+
if (seen.has(source.canonical_url)) {
|
|
212
|
+
throw new Error(`fusion source policy.sources[${String(index)}].canonical_url duplicate`);
|
|
213
|
+
}
|
|
214
|
+
seen.add(source.canonical_url);
|
|
215
|
+
}
|
|
216
|
+
const body = {
|
|
217
|
+
schema_version: FUSION_SOURCE_POLICY_SCHEMA_VERSION,
|
|
218
|
+
workflow: 'research',
|
|
219
|
+
cwd,
|
|
220
|
+
sources,
|
|
221
|
+
};
|
|
222
|
+
if (sha256Text(canonicalJson(body)) !== rootSha256)
|
|
223
|
+
throw new Error('fusion source policy root_sha256 mismatch');
|
|
224
|
+
return { ...body, root_sha256: rootSha256 };
|
|
225
|
+
}
|
|
226
|
+
async function readRegularFileNoSymlink(path, label) {
|
|
227
|
+
let handle;
|
|
228
|
+
try {
|
|
229
|
+
handle = await open(path, constants.O_RDONLY | O_NOFOLLOW);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
if (isJsonObject(error) && error['code'] === 'ELOOP') {
|
|
233
|
+
throw new Error(`${label} at ${path} is a symlink; refusing to follow it`);
|
|
234
|
+
}
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
const stats = await handle.stat();
|
|
239
|
+
if (!stats.isFile())
|
|
240
|
+
throw new Error(`${label} at ${path} is not a regular file`);
|
|
241
|
+
return await handle.readFile();
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
await handle.close();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
export async function readFusionSourcePolicyFile(path, expectedSha256) {
|
|
248
|
+
if (!SHA256_HEX.test(expectedSha256))
|
|
249
|
+
throw new Error('fusion source policy expected hash is malformed');
|
|
250
|
+
const bytes = await readRegularFileNoSymlink(path, 'fusion source policy');
|
|
251
|
+
const actual = createHash('sha256').update(bytes).digest('hex');
|
|
252
|
+
if (actual !== expectedSha256)
|
|
253
|
+
throw new Error('fusion source policy artifact hash mismatch');
|
|
254
|
+
const text = bytes.toString('utf8');
|
|
255
|
+
if (!Buffer.from(text, 'utf8').equals(bytes))
|
|
256
|
+
throw new Error('fusion source policy is not UTF-8');
|
|
257
|
+
return parseFusionSourcePolicy(parseJsonText(text));
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=source-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-policy.js","sourceRoot":"","sources":["../../../../src/core/fusion/source-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EACL,mCAAmC,EACnC,WAAW,GAGZ,MAAM,YAAY,CAAC;AAEpB,MAAM,UAAU,GAAG,gBAAgB,CAAC;AACpC,MAAM,UAAU,GAAG,OAAO,SAAS,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAEvF,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/F,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO,CACL,KAAK,KAAK,WAAW;QACrB,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC5B,KAAK,KAAK,UAAU;QACpB,KAAK,KAAK,gBAAgB;QAC1B,KAAK,KAAK,0BAA0B;QACpC,KAAK,KAAK,eAAe;QACzB,KAAK,KAAK,eAAe;QACzB,KAAK,KAAK,4BAA4B,CACvC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,GAAG,CAAC;QAC/F,OAAO,IAAI,CAAC;IACd,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IACpC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACpD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,IAAI,KAAK,iBAAiB,IAAI,IAAI,KAAK,eAAe,CAAC;AAChE,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,CACL,KAAK,KAAK,IAAI;QACd,KAAK,KAAK,KAAK;QACf,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;QAC3B,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC;QAC7B,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC;QAC9B,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QACxB,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;QAC3B,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC;QAC7B,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;QACzB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QACtB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QACtB,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CACvB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,KAAa;IACvD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,WAAW,CACnB,qDAAqD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAC7G,EAAE,IAAI,EAAE,sBAAsB,EAAE,YAAY,EAAE,KAAK,EAAE,CACtD,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,WAAW,CAAC,yDAAyD,EAAE;YAC/E,IAAI,EAAE,sBAAsB;YAC5B,YAAY,EAAE,KAAK;SACpB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,WAAW,CAAC,mDAAmD,EAAE;YACzE,IAAI,EAAE,sBAAsB;YAC5B,YAAY,EAAE,KAAK;SACpB,CAAC,CAAC;IACL,CAAC;IACD,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,MAAM,cAAc,GAAG,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1F,GAAG,CAAC,QAAQ,GAAG,cAAc,CAAC;IAC9B,IAAI,iBAAiB,CAAC,cAAc,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,WAAW,CAAC,mEAAmE,EAAE;YACzF,IAAI,EAAE,sBAAsB;YAC5B,YAAY,EAAE,KAAK;SACpB,CAAC,CAAC;IACL,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;IACpC,IACE,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa,CAAC,cAAc,CAAC,CAAC;QAC/C,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa,CAAC,cAAc,CAAC,CAAC,EAC/C,CAAC;QACD,MAAM,IAAI,WAAW,CAAC,iEAAiE,EAAE;YACvF,IAAI,EAAE,sBAAsB;YAC5B,YAAY,EAAE,KAAK;SACpB,CAAC,CAAC;IACL,CAAC;IACD,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC;QAC/C,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,EACjD,CAAC;QACD,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IAChB,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAOD,MAAM,UAAU,8BAA8B,CAC5C,UAAgD,EAAE;IAElD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QACnC,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,WAAW,CAAC,0BAA0B,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE;gBACtF,IAAI,EAAE,sBAAsB;gBAC5B,YAAY,EAAE,KAAK;aACpB,CAAC,CAAC;QACL,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,WAAW,CAAC,0BAA0B,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE;gBAC1F,IAAI,EAAE,sBAAsB;gBAC5B,YAAY,EAAE,KAAK;aACpB,CAAC,CAAC;QACL,CAAC;QACD,MAAM,YAAY,GAAG,2BAA2B,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACxC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,WAAW,CACnB,0BAA0B,MAAM,CAAC,KAAK,CAAC,yCAAyC,MAAM,CAAC,QAAQ,CAAC,KAAK,YAAY,EAAE,EACnH,EAAE,IAAI,EAAE,sBAAsB,EAAE,YAAY,EAAE,KAAK,EAAE,CACtD,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACtC,OAAO;YACL,GAAG,EAAE,YAAY;YACjB,aAAa,EAAE,YAAY;YAC3B,OAAO;YACP,MAAM,EAAE,UAAU,CAAC,GAAG,YAAY,SAAS,OAAO,EAAE,CAAC;SACtD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,GAAW,EACX,OAA0C;IAE1C,MAAM,IAAI,GAAG;QACX,cAAc,EAAE,mCAAmC;QACnD,QAAQ,EAAE,UAAmB;QAC7B,GAAG;QACH,OAAO;KACC,CAAC;IACX,OAAO,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAA4B;IACrE,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,aAAa,CAAC,MAAoC,EAAE,GAAW,EAAE,KAAa;IACrF,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,GAAG,2BAA2B,CAAC,CAAC;IAC9D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACjF,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,IAAI,KAAK,CAAC,gBAAgB,CAAC,KAAK,mCAAmC;QACjE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,UAAU;QAClC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,sBAAsB,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,sBAAsB,CAAC,CAAC;IAC/E,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAA0B,EAAE;QAC3E,MAAM,KAAK,GAAG,gCAAgC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,iBAAiB,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,YAAY,GAAG,CAAC,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACnE,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gBAAgB,CAAC,CAAC;QAC/F,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QACtD,MAAM,aAAa,GAAG,aAAa,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;QAClE,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,wBAAwB,CAAC,CAAC;QAChF,IAAI,2BAA2B,CAAC,GAAG,CAAC,KAAK,aAAa;YACpD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,yBAAyB,CAAC,CAAC;QACrD,IAAI,GAAG,KAAK,aAAa;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,+BAA+B,CAAC,CAAC;QACpF,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,0BAA0B,CAAC,CAAC;QACpF,IAAI,UAAU,CAAC,GAAG,aAAa,SAAS,OAAO,EAAE,CAAC,KAAK,MAAM;YAC3D,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kBAAkB,CAAC,CAAC;QAC9C,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QAChD,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC5F,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IACD,MAAM,IAAI,GAAG;QACX,cAAc,EAAE,mCAAmC;QACnD,QAAQ,EAAE,UAAmB;QAC7B,GAAG;QACH,OAAO;KACC,CAAC;IACX,IAAI,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,UAAU;QAChD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,OAAO,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;AAC9C,CAAC;AAED,KAAK,UAAU,wBAAwB,CAAC,IAAY,EAAE,KAAa;IACjE,IAAI,MAAwC,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,GAAG,UAAU,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,sCAAsC,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,wBAAwB,CAAC,CAAC;QAClF,OAAO,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,IAAY,EACZ,cAAsB;IAEtB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,MAAM,wBAAwB,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChE,IAAI,MAAM,KAAK,cAAc;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC9F,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,OAAO,uBAAuB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AACtD,CAAC","sourcesContent":["import { createHash } from 'node:crypto';\nimport { constants } from 'node:fs';\nimport { open } from 'node:fs/promises';\nimport { isIP } from 'node:net';\nimport { canonicalJson } from '../canonical-json.js';\nimport { isJsonObject, parseJsonText } from '../common.js';\nimport {\n FUSION_SOURCE_POLICY_SCHEMA_VERSION,\n FusionError,\n type FusionDeclaredSourceV1,\n type FusionSourcePolicyV1,\n} from './types.js';\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/;\nconst O_NOFOLLOW = typeof constants.O_NOFOLLOW === 'number' ? constants.O_NOFOLLOW : 0;\n\nfunction sha256Text(value: string): string {\n return createHash('sha256').update(value, 'utf8').digest('hex');\n}\n\nfunction stripIpv6Brackets(hostname: string): string {\n return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n}\n\nfunction isBlockedHostname(hostname: string): boolean {\n const lower = hostname.toLowerCase();\n return (\n lower === 'localhost' ||\n lower.endsWith('.localhost') ||\n lower === 'metadata' ||\n lower === 'metadata.local' ||\n lower === 'metadata.google.internal' ||\n lower === 'metadata.goog' ||\n lower === 'instance-data' ||\n lower === 'instance-data.ec2.internal'\n );\n}\n\nfunction isBlockedIpv4(host: string): boolean {\n const parts = host.split('.').map((part) => Number.parseInt(part, 10));\n if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255))\n return true;\n const [a = 0, b = 0, c = 0] = parts;\n if (a === 0 || a === 10 || a === 127) return true;\n if (a === 100 && b >= 64 && b <= 127) return true;\n if (a === 169 && b === 254) return true;\n if (a === 172 && b >= 16 && b <= 31) return true;\n if (a === 192 && b === 168) return true;\n if (a === 192 && b === 0 && c === 0) return true;\n if (a === 192 && b === 0 && c === 2) return true;\n if (a === 198 && (b === 18 || b === 19)) return true;\n if (a === 198 && b === 51 && c === 100) return true;\n if (a === 203 && b === 0 && c === 113) return true;\n if (a >= 224) return true;\n return host === '255.255.255.255' || host === '168.63.129.16';\n}\n\nfunction isBlockedIpv6(host: string): boolean {\n const lower = host.toLowerCase();\n return (\n lower === '::' ||\n lower === '::1' ||\n lower.startsWith('::ffff:') ||\n lower.startsWith('64:ff9b::') ||\n lower.startsWith('64:ff9b:1:') ||\n lower.startsWith('100:') ||\n lower.startsWith('2001:2:') ||\n lower.startsWith('2001:db8:') ||\n lower.startsWith('2002:') ||\n lower.startsWith('fc') ||\n lower.startsWith('fd') ||\n lower.startsWith('fe8') ||\n lower.startsWith('fe9') ||\n lower.startsWith('fea') ||\n lower.startsWith('feb') ||\n lower.startsWith('ff')\n );\n}\n\nexport function canonicalizeFusionPublicUrl(value: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch (error) {\n throw new FusionError(\n `fusion research declared source URL is malformed: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'orchestration_failed', childCreated: false },\n );\n }\n if (url.username !== '' || url.password !== '') {\n throw new FusionError('fusion research source URL must not contain credentials', {\n code: 'orchestration_failed',\n childCreated: false,\n });\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new FusionError('fusion research source URL must use http or https', {\n code: 'orchestration_failed',\n childCreated: false,\n });\n }\n url.username = '';\n url.password = '';\n url.hash = '';\n const normalizedHost = stripIpv6Brackets(url.hostname.toLowerCase().replace(/\\.+$/u, ''));\n url.hostname = normalizedHost;\n if (isBlockedHostname(normalizedHost)) {\n throw new FusionError('fusion research source URL must be public, not localhost/metadata', {\n code: 'orchestration_failed',\n childCreated: false,\n });\n }\n const ipKind = isIP(normalizedHost);\n if (\n (ipKind === 4 && isBlockedIpv4(normalizedHost)) ||\n (ipKind === 6 && isBlockedIpv6(normalizedHost))\n ) {\n throw new FusionError('fusion research source URL must be public, not private/reserved', {\n code: 'orchestration_failed',\n childCreated: false,\n });\n }\n if (\n (url.protocol === 'http:' && url.port === '80') ||\n (url.protocol === 'https:' && url.port === '443')\n ) {\n url.port = '';\n }\n return url.toString();\n}\n\nexport interface DeclaredFusionSourceInput {\n url: string;\n purpose: string;\n}\n\nexport function normalizeFusionDeclaredSources(\n sources: readonly DeclaredFusionSourceInput[] = [],\n): readonly FusionDeclaredSourceV1[] {\n const seen = new Map<string, number>();\n return sources.map((source, index) => {\n if (typeof source.url !== 'string' || source.url.trim().length === 0) {\n throw new FusionError(`fusion research source ${String(index)} requires non-blank URL`, {\n code: 'orchestration_failed',\n childCreated: false,\n });\n }\n if (typeof source.purpose !== 'string' || source.purpose.trim().length === 0) {\n throw new FusionError(`fusion research source ${String(index)} requires non-blank purpose`, {\n code: 'orchestration_failed',\n childCreated: false,\n });\n }\n const canonicalUrl = canonicalizeFusionPublicUrl(source.url.trim());\n const previous = seen.get(canonicalUrl);\n if (previous !== undefined) {\n throw new FusionError(\n `fusion research source ${String(index)} duplicates canonical URL from source ${String(previous)}: ${canonicalUrl}`,\n { code: 'orchestration_failed', childCreated: false },\n );\n }\n seen.set(canonicalUrl, index);\n const purpose = source.purpose.trim();\n return {\n url: canonicalUrl,\n canonical_url: canonicalUrl,\n purpose,\n sha256: sha256Text(`${canonicalUrl}\\u0000${purpose}`),\n };\n });\n}\n\nexport function buildFusionSourcePolicy(\n cwd: string,\n sources: readonly FusionDeclaredSourceV1[],\n): FusionSourcePolicyV1 {\n const body = {\n schema_version: FUSION_SOURCE_POLICY_SCHEMA_VERSION,\n workflow: 'research' as const,\n cwd,\n sources,\n } as const;\n return { ...body, root_sha256: sha256Text(canonicalJson(body)) };\n}\n\nexport function sourcePolicyCanonicalBytes(policy: FusionSourcePolicyV1): string {\n return canonicalJson(policy);\n}\n\nfunction requireString(record: Record<PropertyKey, unknown>, key: string, label: string): string {\n const value = record[key];\n if (typeof value !== 'string' || value.length === 0)\n throw new Error(`${label}.${key} must be non-blank string`);\n return value;\n}\n\nexport function parseFusionSourcePolicy(value: unknown): FusionSourcePolicyV1 {\n if (!isJsonObject(value) || Array.isArray(value))\n throw new Error('fusion source policy must be object');\n const keys = Object.keys(value).sort();\n const expected = ['cwd', 'root_sha256', 'schema_version', 'sources', 'workflow'];\n if (keys.join('\\0') !== expected.join('\\0'))\n throw new Error('fusion source policy keys mismatch');\n if (value['schema_version'] !== FUSION_SOURCE_POLICY_SCHEMA_VERSION)\n throw new Error('fusion source policy schema_version mismatch');\n if (value['workflow'] !== 'research')\n throw new Error('fusion source policy workflow must be research');\n const cwd = requireString(value, 'cwd', 'fusion source policy');\n const rootSha256 = requireString(value, 'root_sha256', 'fusion source policy');\n if (!SHA256_HEX.test(rootSha256))\n throw new Error('fusion source policy.root_sha256 must be sha256');\n if (!Array.isArray(value['sources']))\n throw new Error('fusion source policy.sources must be array');\n const sources = value['sources'].map((item, index): FusionDeclaredSourceV1 => {\n const label = `fusion source policy.sources[${String(index)}]`;\n if (!isJsonObject(item) || Array.isArray(item)) throw new Error(`${label} must be object`);\n const itemKeys = Object.keys(item).sort();\n const itemExpected = ['canonical_url', 'purpose', 'sha256', 'url'];\n if (itemKeys.join('\\0') !== itemExpected.join('\\0')) throw new Error(`${label} keys mismatch`);\n const url = requireString(item, 'url', label);\n const purpose = requireString(item, 'purpose', label);\n const canonical_url = requireString(item, 'canonical_url', label);\n const sha256 = requireString(item, 'sha256', label);\n if (!SHA256_HEX.test(sha256)) throw new Error(`${label}.sha256 must be sha256`);\n if (canonicalizeFusionPublicUrl(url) !== canonical_url)\n throw new Error(`${label}.canonical_url mismatch`);\n if (url !== canonical_url) throw new Error(`${label}.url must equal canonical_url`);\n if (purpose.trim() !== purpose) throw new Error(`${label}.purpose must be trimmed`);\n if (sha256Text(`${canonical_url}\\u0000${purpose}`) !== sha256)\n throw new Error(`${label}.sha256 mismatch`);\n return { url, canonical_url, purpose, sha256 };\n });\n const seen = new Set<string>();\n for (const [index, source] of sources.entries()) {\n if (seen.has(source.canonical_url)) {\n throw new Error(`fusion source policy.sources[${String(index)}].canonical_url duplicate`);\n }\n seen.add(source.canonical_url);\n }\n const body = {\n schema_version: FUSION_SOURCE_POLICY_SCHEMA_VERSION,\n workflow: 'research' as const,\n cwd,\n sources,\n } as const;\n if (sha256Text(canonicalJson(body)) !== rootSha256)\n throw new Error('fusion source policy root_sha256 mismatch');\n return { ...body, root_sha256: rootSha256 };\n}\n\nasync function readRegularFileNoSymlink(path: string, label: string): Promise<Buffer> {\n let handle: Awaited<ReturnType<typeof open>>;\n try {\n handle = await open(path, constants.O_RDONLY | O_NOFOLLOW);\n } catch (error) {\n if (isJsonObject(error) && error['code'] === 'ELOOP') {\n throw new Error(`${label} at ${path} is a symlink; refusing to follow it`);\n }\n throw error;\n }\n try {\n const stats = await handle.stat();\n if (!stats.isFile()) throw new Error(`${label} at ${path} is not a regular file`);\n return await handle.readFile();\n } finally {\n await handle.close();\n }\n}\n\nexport async function readFusionSourcePolicyFile(\n path: string,\n expectedSha256: string,\n): Promise<FusionSourcePolicyV1> {\n if (!SHA256_HEX.test(expectedSha256))\n throw new Error('fusion source policy expected hash is malformed');\n const bytes = await readRegularFileNoSymlink(path, 'fusion source policy');\n const actual = createHash('sha256').update(bytes).digest('hex');\n if (actual !== expectedSha256) throw new Error('fusion source policy artifact hash mismatch');\n const text = bytes.toString('utf8');\n if (!Buffer.from(text, 'utf8').equals(bytes))\n throw new Error('fusion source policy is not UTF-8');\n return parseFusionSourcePolicy(parseJsonText(text));\n}\n"]}
|