@elie-laloum/outpost 2.0.0 → 3.0.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/CHANGELOG.md +24 -0
- package/dist/adapters/agents/claude-diagnostics.d.ts +1 -0
- package/dist/adapters/agents/claude-diagnostics.js +7 -0
- package/dist/adapters/agents/claude-diagnostics.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.constants.d.ts +12 -0
- package/dist/adapters/agents/cli-diagnostics.constants.js +24 -0
- package/dist/adapters/agents/cli-diagnostics.constants.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.d.ts +4 -0
- package/dist/adapters/agents/cli-diagnostics.js +14 -0
- package/dist/adapters/agents/cli-diagnostics.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.types.d.ts +13 -0
- package/dist/adapters/agents/cli-diagnostics.types.js +2 -0
- package/dist/adapters/agents/cli-diagnostics.types.js.map +1 -0
- package/dist/adapters/agents/codex-diagnostics.d.ts +1 -0
- package/dist/adapters/agents/codex-diagnostics.js +7 -0
- package/dist/adapters/agents/codex-diagnostics.js.map +1 -0
- package/dist/adapters/agents/protocol-fixtures.constants.d.ts +2 -0
- package/dist/adapters/agents/protocol-fixtures.constants.js +68 -0
- package/dist/adapters/agents/protocol-fixtures.constants.js.map +1 -0
- package/dist/adapters/agents/protocol-fixtures.types.d.ts +6 -0
- package/dist/adapters/agents/protocol-fixtures.types.js +2 -0
- package/dist/adapters/agents/protocol-fixtures.types.js.map +1 -0
- package/dist/application/diagnostic-probe.d.ts +3 -0
- package/dist/application/diagnostic-probe.js +55 -0
- package/dist/application/diagnostic-probe.js.map +1 -0
- package/dist/application/doctor-agent.constants.d.ts +9 -0
- package/dist/application/doctor-agent.constants.js +8 -0
- package/dist/application/doctor-agent.constants.js.map +1 -0
- package/dist/application/doctor-agent.d.ts +3 -0
- package/dist/application/doctor-agent.js +53 -0
- package/dist/application/doctor-agent.js.map +1 -0
- package/dist/application/doctor-image.d.ts +3 -0
- package/dist/application/doctor-image.js +133 -0
- package/dist/application/doctor-image.js.map +1 -0
- package/dist/application/doctor-protocol.d.ts +3 -0
- package/dist/application/doctor-protocol.js +29 -0
- package/dist/application/doctor-protocol.js.map +1 -0
- package/dist/application/doctor-protocol.types.d.ts +10 -0
- package/dist/application/doctor-protocol.types.js +2 -0
- package/dist/application/doctor-protocol.types.js.map +1 -0
- package/dist/application/doctor-sandbox.constants.d.ts +5 -0
- package/dist/application/doctor-sandbox.constants.js +6 -0
- package/dist/application/doctor-sandbox.constants.js.map +1 -0
- package/dist/application/doctor-sandbox.d.ts +4 -0
- package/dist/application/doctor-sandbox.js +133 -0
- package/dist/application/doctor-sandbox.js.map +1 -0
- package/dist/application/doctor-sandbox.types.d.ts +23 -0
- package/dist/application/doctor-sandbox.types.js +2 -0
- package/dist/application/doctor-sandbox.types.js.map +1 -0
- package/dist/application/doctor-transfers.constants.d.ts +6 -0
- package/dist/application/doctor-transfers.constants.js +7 -0
- package/dist/application/doctor-transfers.constants.js.map +1 -0
- package/dist/application/doctor-transfers.d.ts +4 -0
- package/dist/application/doctor-transfers.js +88 -0
- package/dist/application/doctor-transfers.js.map +1 -0
- package/dist/application/doctor.constants.d.ts +9 -0
- package/dist/application/doctor.constants.js +15 -0
- package/dist/application/doctor.constants.js.map +1 -0
- package/dist/application/doctor.d.ts +3 -0
- package/dist/application/doctor.js +106 -0
- package/dist/application/doctor.js.map +1 -0
- package/dist/application/doctor.types.d.ts +39 -0
- package/dist/application/doctor.types.js +2 -0
- package/dist/application/doctor.types.js.map +1 -0
- package/dist/application/execution.js +1 -0
- package/dist/application/execution.js.map +1 -1
- package/dist/application/outpost.types.d.ts +2 -0
- package/dist/application/outpost.types.js.map +1 -1
- package/dist/application/recovery-checksum-capture.d.ts +2 -0
- package/dist/application/recovery-checksum-capture.js +32 -0
- package/dist/application/recovery-checksum-capture.js.map +1 -0
- package/dist/application/recovery-checksum-paths.d.ts +2 -0
- package/dist/application/recovery-checksum-paths.js +11 -0
- package/dist/application/recovery-checksum-paths.js.map +1 -0
- package/dist/application/recovery-checksums.constants.d.ts +5 -0
- package/dist/application/recovery-checksums.constants.js +6 -0
- package/dist/application/recovery-checksums.constants.js.map +1 -0
- package/dist/application/recovery-checksums.d.ts +3 -0
- package/dist/application/recovery-checksums.js +94 -0
- package/dist/application/recovery-checksums.js.map +1 -0
- package/dist/application/recovery-checksums.types.d.ts +17 -0
- package/dist/application/recovery-checksums.types.js +2 -0
- package/dist/application/recovery-checksums.types.js.map +1 -0
- package/dist/application/recovery-inspection.d.ts +2 -0
- package/dist/application/recovery-inspection.js +27 -0
- package/dist/application/recovery-inspection.js.map +1 -0
- package/dist/application/recovery-inspection.types.d.ts +15 -0
- package/dist/application/recovery-inspection.types.js +2 -0
- package/dist/application/recovery-inspection.types.js.map +1 -0
- package/dist/application/recovery-restorability.d.ts +2 -0
- package/dist/application/recovery-restorability.js +137 -0
- package/dist/application/recovery-restorability.js.map +1 -0
- package/dist/application/recovery-retention-policy.d.ts +2 -0
- package/dist/application/recovery-retention-policy.js +21 -0
- package/dist/application/recovery-retention-policy.js.map +1 -0
- package/dist/application/recovery-retention.constants.d.ts +3 -0
- package/dist/application/recovery-retention.constants.js +2 -0
- package/dist/application/recovery-retention.constants.js.map +1 -0
- package/dist/application/recovery-retention.d.ts +4 -0
- package/dist/application/recovery-retention.js +202 -0
- package/dist/application/recovery-retention.js.map +1 -0
- package/dist/application/recovery-retention.types.d.ts +52 -0
- package/dist/application/recovery-retention.types.js +2 -0
- package/dist/application/recovery-retention.types.js.map +1 -0
- package/dist/application/recovery-verification.constants.d.ts +5 -0
- package/dist/application/recovery-verification.constants.js +10 -0
- package/dist/application/recovery-verification.constants.js.map +1 -0
- package/dist/application/recovery-verification.d.ts +2 -0
- package/dist/application/recovery-verification.js +107 -0
- package/dist/application/recovery-verification.js.map +1 -0
- package/dist/application/recovery-verification.types.d.ts +26 -0
- package/dist/application/recovery-verification.types.js +2 -0
- package/dist/application/recovery-verification.types.js.map +1 -0
- package/dist/application/remote-apply.js +24 -6
- package/dist/application/remote-apply.js.map +1 -1
- package/dist/application/remote-backup.js +6 -2
- package/dist/application/remote-backup.js.map +1 -1
- package/dist/application/remote-download.js +36 -4
- package/dist/application/remote-download.js.map +1 -1
- package/dist/application/remote-validation.js +19 -0
- package/dist/application/remote-validation.js.map +1 -1
- package/dist/application/remote-workspace.constants.d.ts +3 -0
- package/dist/application/remote-workspace.constants.js +2 -0
- package/dist/application/remote-workspace.constants.js.map +1 -0
- package/dist/application/remote-workspace.js +6 -0
- package/dist/application/remote-workspace.js.map +1 -1
- package/dist/application/remote-workspace.types.d.ts +3 -1
- package/dist/application/remote-workspace.types.js.map +1 -1
- package/dist/application/sandbox.js +11 -0
- package/dist/application/sandbox.js.map +1 -1
- package/dist/application/task-usage.d.ts +4 -0
- package/dist/application/task-usage.js +41 -0
- package/dist/application/task-usage.js.map +1 -0
- package/dist/application/task-usage.types.d.ts +5 -0
- package/dist/application/task-usage.types.js +2 -0
- package/dist/application/task-usage.types.js.map +1 -0
- package/dist/application/tasks.js +23 -2
- package/dist/application/tasks.js.map +1 -1
- package/dist/cli/commands.js +4 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/doctor-command.d.ts +3 -0
- package/dist/cli/doctor-command.js +38 -0
- package/dist/cli/doctor-command.js.map +1 -0
- package/dist/cli/main.constants.d.ts +28 -1
- package/dist/cli/main.constants.js +15 -0
- package/dist/cli/main.constants.js.map +1 -1
- package/dist/cli/recovery-command.d.ts +2 -0
- package/dist/cli/recovery-command.js +69 -0
- package/dist/cli/recovery-command.js.map +1 -0
- package/dist/cli/recovery-prune-command.d.ts +2 -0
- package/dist/cli/recovery-prune-command.js +34 -0
- package/dist/cli/recovery-prune-command.js.map +1 -0
- package/dist/cli/recovery-verify-command.d.ts +2 -0
- package/dist/cli/recovery-verify-command.js +43 -0
- package/dist/cli/recovery-verify-command.js.map +1 -0
- package/dist/domain/ports.d.ts +1 -1
- package/dist/domain/ports.js.map +1 -1
- package/dist/domain/sandbox.types.d.ts +12 -0
- package/dist/domain/sandbox.types.js.map +1 -1
- package/dist/domain/workflow/budget.constants.d.ts +1 -0
- package/dist/domain/workflow/budget.constants.js +7 -0
- package/dist/domain/workflow/budget.constants.js.map +1 -0
- package/dist/domain/workflow/budget.d.ts +9 -0
- package/dist/domain/workflow/budget.js +67 -0
- package/dist/domain/workflow/budget.js.map +1 -0
- package/dist/domain/workflow/budget.types.d.ts +15 -0
- package/dist/domain/workflow/budget.types.js +2 -0
- package/dist/domain/workflow/budget.types.js.map +1 -0
- package/dist/domain/workflow/task-runner.js +8 -1
- package/dist/domain/workflow/task-runner.js.map +1 -1
- package/dist/domain/workflow/workflow-scheduler.js +4 -2
- package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
- package/dist/domain/workflow/workflow-state.js +29 -0
- package/dist/domain/workflow/workflow-state.js.map +1 -1
- package/dist/domain/workflow.d.ts +2 -0
- package/dist/domain/workflow.js +1 -0
- package/dist/domain/workflow.js.map +1 -1
- package/dist/domain/workflow.types.d.ts +10 -1
- package/dist/domain/workflow.types.js.map +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/file-manifest.d.ts +6 -0
- package/dist/infrastructure/file-manifest.js +91 -0
- package/dist/infrastructure/file-manifest.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.constants.d.ts +4 -0
- package/dist/infrastructure/git/lock-inspection.constants.js +5 -0
- package/dist/infrastructure/git/lock-inspection.constants.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.d.ts +3 -0
- package/dist/infrastructure/git/lock-inspection.js +64 -0
- package/dist/infrastructure/git/lock-inspection.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.types.d.ts +27 -0
- package/dist/infrastructure/git/lock-inspection.types.js +2 -0
- package/dist/infrastructure/git/lock-inspection.types.js.map +1 -0
- package/dist/infrastructure/git/lock.d.ts +1 -0
- package/dist/infrastructure/git/lock.js +70 -29
- package/dist/infrastructure/git/lock.js.map +1 -1
- package/dist/infrastructure/git/process-identity.d.ts +3 -0
- package/dist/infrastructure/git/process-identity.js +73 -0
- package/dist/infrastructure/git/process-identity.js.map +1 -0
- package/dist/infrastructure/git/process-identity.types.d.ts +10 -0
- package/dist/infrastructure/git/process-identity.types.js +2 -0
- package/dist/infrastructure/git/process-identity.types.js.map +1 -0
- package/dist/infrastructure/git/verification-command.d.ts +1 -0
- package/dist/infrastructure/git/verification-command.js +36 -0
- package/dist/infrastructure/git/verification-command.js.map +1 -0
- package/dist/infrastructure/git/workspace-lease.js +1 -0
- package/dist/infrastructure/git/workspace-lease.js.map +1 -1
- package/dist/infrastructure/git/workspace.js +5 -1
- package/dist/infrastructure/git/workspace.js.map +1 -1
- package/dist/infrastructure/git/worktree-inspection.constants.d.ts +5 -0
- package/dist/infrastructure/git/worktree-inspection.constants.js +16 -0
- package/dist/infrastructure/git/worktree-inspection.constants.js.map +1 -0
- package/dist/infrastructure/git/worktree-inspection.d.ts +3 -0
- package/dist/infrastructure/git/worktree-inspection.js +120 -0
- package/dist/infrastructure/git/worktree-inspection.js.map +1 -0
- package/dist/infrastructure/git/worktree-inspection.types.d.ts +19 -0
- package/dist/infrastructure/git/worktree-inspection.types.js +2 -0
- package/dist/infrastructure/git/worktree-inspection.types.js.map +1 -0
- package/dist/infrastructure/inspection-file.constants.d.ts +1 -0
- package/dist/infrastructure/inspection-file.constants.js +5 -0
- package/dist/infrastructure/inspection-file.constants.js.map +1 -0
- package/dist/infrastructure/inspection-file.d.ts +1 -0
- package/dist/infrastructure/inspection-file.js +43 -0
- package/dist/infrastructure/inspection-file.js.map +1 -0
- package/dist/infrastructure/inspection-hash.constants.d.ts +1 -0
- package/dist/infrastructure/inspection-hash.constants.js +2 -0
- package/dist/infrastructure/inspection-hash.constants.js.map +1 -0
- package/dist/infrastructure/inspection-hash.d.ts +2 -0
- package/dist/infrastructure/inspection-hash.js +62 -0
- package/dist/infrastructure/inspection-hash.js.map +1 -0
- package/dist/infrastructure/inspection-hash.types.d.ts +5 -0
- package/dist/infrastructure/inspection-hash.types.js +2 -0
- package/dist/infrastructure/inspection-hash.types.js.map +1 -0
- package/dist/infrastructure/journal-retention.constants.d.ts +4 -0
- package/dist/infrastructure/journal-retention.constants.js +5 -0
- package/dist/infrastructure/journal-retention.constants.js.map +1 -0
- package/dist/infrastructure/journal-retention.d.ts +2 -0
- package/dist/infrastructure/journal-retention.js +51 -0
- package/dist/infrastructure/journal-retention.js.map +1 -0
- package/dist/infrastructure/journal.js +37 -13
- package/dist/infrastructure/journal.js.map +1 -1
- package/dist/infrastructure/opentelemetry.constants.d.ts +10 -0
- package/dist/infrastructure/opentelemetry.constants.js +11 -0
- package/dist/infrastructure/opentelemetry.constants.js.map +1 -0
- package/dist/infrastructure/opentelemetry.d.ts +3 -0
- package/dist/infrastructure/opentelemetry.js +131 -0
- package/dist/infrastructure/opentelemetry.js.map +1 -0
- package/dist/infrastructure/opentelemetry.types.d.ts +21 -0
- package/dist/infrastructure/opentelemetry.types.js +2 -0
- package/dist/infrastructure/opentelemetry.types.js.map +1 -0
- package/dist/infrastructure/storage-inventory.constants.d.ts +6 -0
- package/dist/infrastructure/storage-inventory.constants.js +11 -0
- package/dist/infrastructure/storage-inventory.constants.js.map +1 -0
- package/dist/infrastructure/storage-inventory.d.ts +2 -0
- package/dist/infrastructure/storage-inventory.js +123 -0
- package/dist/infrastructure/storage-inventory.js.map +1 -0
- package/dist/infrastructure/storage-inventory.types.d.ts +38 -0
- package/dist/infrastructure/storage-inventory.types.js +2 -0
- package/dist/infrastructure/storage-inventory.types.js.map +1 -0
- package/dist/infrastructure/transfer.js +12 -0
- package/dist/infrastructure/transfer.js.map +1 -1
- package/dist/providers/cloud.constants.d.ts +1 -0
- package/dist/providers/cloud.constants.js +1 -0
- package/dist/providers/cloud.constants.js.map +1 -1
- package/dist/providers/container-cache.constants.d.ts +11 -0
- package/dist/providers/container-cache.constants.js +9 -0
- package/dist/providers/container-cache.constants.js.map +1 -0
- package/dist/providers/container-cache.d.ts +4 -0
- package/dist/providers/container-cache.js +48 -0
- package/dist/providers/container-cache.js.map +1 -0
- package/dist/providers/container-cache.types.d.ts +8 -0
- package/dist/providers/container-cache.types.js +2 -0
- package/dist/providers/container-cache.types.js.map +1 -0
- package/dist/providers/container-plan.js +3 -1
- package/dist/providers/container-plan.js.map +1 -1
- package/dist/providers/container.js +31 -1
- package/dist/providers/container.js.map +1 -1
- package/dist/providers/container.types.d.ts +2 -0
- package/dist/providers/container.types.js.map +1 -1
- package/dist/providers/daytona-command.js +7 -4
- package/dist/providers/daytona-command.js.map +1 -1
- package/dist/providers/daytona.js +13 -4
- package/dist/providers/daytona.js.map +1 -1
- package/dist/providers/diagnostic-container.d.ts +4 -0
- package/dist/providers/diagnostic-container.js +15 -0
- package/dist/providers/diagnostic-container.js.map +1 -0
- package/dist/providers/docker.d.ts +1 -0
- package/dist/providers/docker.js.map +1 -1
- package/dist/providers/file-batches.constants.d.ts +10 -0
- package/dist/providers/file-batches.constants.js +57 -0
- package/dist/providers/file-batches.constants.js.map +1 -0
- package/dist/providers/file-batches.d.ts +2 -0
- package/dist/providers/file-batches.js +151 -0
- package/dist/providers/file-batches.js.map +1 -0
- package/dist/providers/podman.d.ts +1 -0
- package/dist/providers/podman.js.map +1 -1
- package/dist/providers/vercel.js +3 -1
- package/dist/providers/vercel.js.map +1 -1
- package/package.json +12 -1
|
@@ -23,6 +23,7 @@ export async function execute(workspace, lease, agent, host, options, afterTurn)
|
|
|
23
23
|
? 1 + options.response.repairs
|
|
24
24
|
: (options.passes ?? executionDefaults.passes);
|
|
25
25
|
for (let index = 0; index < attempts; index++) {
|
|
26
|
+
options.signal?.throwIfAborted();
|
|
26
27
|
notify(options.observe, {
|
|
27
28
|
kind: "phase",
|
|
28
29
|
name: "preparing prompt",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/application/execution.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentAdapter, Usage } from \"../domain/agent.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { ResponseError } from \"../domain/response.ts\";\nimport type { SandboxLease } from \"../domain/sandbox.types.ts\";\nimport { addUsage } from \"../domain/usage.ts\";\nimport type { WorkspaceRecord } from \"../domain/workspace.types.ts\";\nimport { turn } from \"./agent-turn.ts\";\nimport { renderBrief } from \"./brief-renderer.ts\";\nimport { validateDispatch } from \"./dispatch-validation.ts\";\nimport { executionDefaults } from \"./execution.constants.ts\";\nimport type { DispatchOptions, Execution, Turn } from \"./execution.types.ts\";\nimport { notify } from \"./observation.ts\";\n\nexport { renderBrief } from \"./brief-renderer.ts\";\nexport { preflightDispatch, validateDispatch } from \"./dispatch-validation.ts\";\nexport type { DispatchOptions, Execution, Turn } from \"./execution.types.ts\";\nexport { notify } from \"./observation.ts\";\n\nexport async function execute<T>(\n workspace: WorkspaceRecord,\n lease: SandboxLease,\n agent: AgentAdapter,\n host: boolean,\n options: DispatchOptions<T>,\n afterTurn?: (turn: Turn) => Promise<Turn>,\n): Promise<Execution<T>> {\n validateDispatch(options);\n const markers =\n options.until === undefined\n ? [executionDefaults.completion]\n : typeof options.until === \"string\"\n ? [options.until]\n : options.until;\n const turns: Turn[] = [];\n let value: T = undefined as T,\n completed = false,\n continuation = options.continuation;\n let repair: string | undefined;\n const attempts = options.response\n ? 1 + options.response.repairs\n : (options.passes ?? executionDefaults.passes);\n for (let index = 0; index < attempts; index++) {\n notify(options.observe, {\n kind: \"phase\",\n name: \"preparing prompt\",\n agent: agent.name,\n branch: workspace.branch,\n directory: workspace.directory,\n pass: index + 1,\n at: new Date().toISOString(),\n });\n const prompt =\n repair ??\n (await renderBrief(options.brief, workspace, lease, host, options));\n if (options.response && !repair)\n invariant(\n prompt.includes(`<${options.response.tag}>`),\n `Brief must request an opening <${options.response.tag}> tag`,\n );\n notify(options.observe, {\n kind: \"prompt\",\n text: prompt,\n pass: index + 1,\n at: new Date().toISOString(),\n });\n notify(options.observe, {\n kind: \"phase\",\n name: \"running\",\n agent: agent.name,\n branch: workspace.branch,\n pass: index + 1,\n at: new Date().toISOString(),\n });\n const finished = await turn(\n lease,\n agent,\n prompt,\n options,\n continuation,\n markers,\n index + 1,\n );\n const current = afterTurn ? await afterTurn(finished) : finished;\n turns.push(current);\n notify(options.observe, {\n kind: \"summary\",\n durationMs: current.durationMs,\n status: current.status,\n tokens: current.usage,\n pass: index + 1,\n at: new Date().toISOString(),\n });\n completed = markers.some((marker) => current.text.includes(marker));\n if (options.response) {\n try {\n value = await options.response.read(current.text);\n completed = true;\n break;\n } catch (error) {\n if (!(error instanceof ResponseError)) throw error;\n error.recovery = {\n conversation: current.conversation,\n branch: workspace.branch,\n directory: workspace.directory,\n turns,\n };\n if (index + 1 >= attempts || !current.conversation) throw error;\n continuation = { id: current.conversation };\n repair = [\n `Correct the response inside <${options.response.tag}> and </${options.response.tag}>.`,\n `Validation failure: ${error.message}`,\n `Previous content: ${error.raw ?? \"No complete tagged response was returned.\"}`,\n `Cause: ${error.cause instanceof Error ? error.cause.message : (JSON.stringify(error.cause) ?? \"unspecified\")}`,\n `Further repair attempts after this one: ${attempts - index - 2}.`,\n \"Do not edit files, run commands or continue implementation. Only return the corrected response.\",\n ].join(\"\\n\");\n }\n }\n if (!options.response && completed) break;\n }\n const conversation = turns.at(-1)?.conversation;\n const completion = markers.find((marker) =>\n turns.at(-1)?.text.includes(marker),\n );\n return {\n text: turns.map((item) => item.text).join(\"\\n\"),\n turns,\n value,\n completed,\n ...(completion ? { completion } : {}),\n ...(conversation ? { conversation } : {}),\n usage: turns.reduce((sum, item) => addUsage(sum, item.usage), {\n input: 0,\n cached: 0,\n output: 0,\n } as Usage),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/application/execution.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentAdapter, Usage } from \"../domain/agent.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { ResponseError } from \"../domain/response.ts\";\nimport type { SandboxLease } from \"../domain/sandbox.types.ts\";\nimport { addUsage } from \"../domain/usage.ts\";\nimport type { WorkspaceRecord } from \"../domain/workspace.types.ts\";\nimport { turn } from \"./agent-turn.ts\";\nimport { renderBrief } from \"./brief-renderer.ts\";\nimport { validateDispatch } from \"./dispatch-validation.ts\";\nimport { executionDefaults } from \"./execution.constants.ts\";\nimport type { DispatchOptions, Execution, Turn } from \"./execution.types.ts\";\nimport { notify } from \"./observation.ts\";\n\nexport { renderBrief } from \"./brief-renderer.ts\";\nexport { preflightDispatch, validateDispatch } from \"./dispatch-validation.ts\";\nexport type { DispatchOptions, Execution, Turn } from \"./execution.types.ts\";\nexport { notify } from \"./observation.ts\";\n\nexport async function execute<T>(\n workspace: WorkspaceRecord,\n lease: SandboxLease,\n agent: AgentAdapter,\n host: boolean,\n options: DispatchOptions<T>,\n afterTurn?: (turn: Turn) => Promise<Turn>,\n): Promise<Execution<T>> {\n validateDispatch(options);\n const markers =\n options.until === undefined\n ? [executionDefaults.completion]\n : typeof options.until === \"string\"\n ? [options.until]\n : options.until;\n const turns: Turn[] = [];\n let value: T = undefined as T,\n completed = false,\n continuation = options.continuation;\n let repair: string | undefined;\n const attempts = options.response\n ? 1 + options.response.repairs\n : (options.passes ?? executionDefaults.passes);\n for (let index = 0; index < attempts; index++) {\n options.signal?.throwIfAborted();\n notify(options.observe, {\n kind: \"phase\",\n name: \"preparing prompt\",\n agent: agent.name,\n branch: workspace.branch,\n directory: workspace.directory,\n pass: index + 1,\n at: new Date().toISOString(),\n });\n const prompt =\n repair ??\n (await renderBrief(options.brief, workspace, lease, host, options));\n if (options.response && !repair)\n invariant(\n prompt.includes(`<${options.response.tag}>`),\n `Brief must request an opening <${options.response.tag}> tag`,\n );\n notify(options.observe, {\n kind: \"prompt\",\n text: prompt,\n pass: index + 1,\n at: new Date().toISOString(),\n });\n notify(options.observe, {\n kind: \"phase\",\n name: \"running\",\n agent: agent.name,\n branch: workspace.branch,\n pass: index + 1,\n at: new Date().toISOString(),\n });\n const finished = await turn(\n lease,\n agent,\n prompt,\n options,\n continuation,\n markers,\n index + 1,\n );\n const current = afterTurn ? await afterTurn(finished) : finished;\n turns.push(current);\n notify(options.observe, {\n kind: \"summary\",\n durationMs: current.durationMs,\n status: current.status,\n tokens: current.usage,\n pass: index + 1,\n at: new Date().toISOString(),\n });\n completed = markers.some((marker) => current.text.includes(marker));\n if (options.response) {\n try {\n value = await options.response.read(current.text);\n completed = true;\n break;\n } catch (error) {\n if (!(error instanceof ResponseError)) throw error;\n error.recovery = {\n conversation: current.conversation,\n branch: workspace.branch,\n directory: workspace.directory,\n turns,\n };\n if (index + 1 >= attempts || !current.conversation) throw error;\n continuation = { id: current.conversation };\n repair = [\n `Correct the response inside <${options.response.tag}> and </${options.response.tag}>.`,\n `Validation failure: ${error.message}`,\n `Previous content: ${error.raw ?? \"No complete tagged response was returned.\"}`,\n `Cause: ${error.cause instanceof Error ? error.cause.message : (JSON.stringify(error.cause) ?? \"unspecified\")}`,\n `Further repair attempts after this one: ${attempts - index - 2}.`,\n \"Do not edit files, run commands or continue implementation. Only return the corrected response.\",\n ].join(\"\\n\");\n }\n }\n if (!options.response && completed) break;\n }\n const conversation = turns.at(-1)?.conversation;\n const completion = markers.find((marker) =>\n turns.at(-1)?.text.includes(marker),\n );\n return {\n text: turns.map((item) => item.text).join(\"\\n\"),\n turns,\n value,\n completed,\n ...(completion ? { completion } : {}),\n ...(conversation ? { conversation } : {}),\n usage: turns.reduce((sum, item) => addUsage(sum, item.usage), {\n input: 0,\n cached: 0,\n output: 0,\n } as Usage),\n };\n}\n"]}
|
|
@@ -4,6 +4,7 @@ import type { Brief } from "../domain/prompts.types.ts";
|
|
|
4
4
|
import type { SandboxProvider } from "../domain/sandbox.types.ts";
|
|
5
5
|
import type { BranchPolicy, Commit, Disposal, LifecycleHooks, StageLimits, WorkspaceRecord } from "../domain/workspace.types.ts";
|
|
6
6
|
import type { Logging } from "../infrastructure/journal.types.ts";
|
|
7
|
+
import type { SandboxDiagnosticOptions, SandboxDiagnosticReport } from "./doctor-sandbox.types.ts";
|
|
7
8
|
import type { DispatchOptions, Execution } from "./execution.types.ts";
|
|
8
9
|
import type { VariableQuestion } from "./interactive-brief.types.ts";
|
|
9
10
|
export interface WorkspaceOptions {
|
|
@@ -72,6 +73,7 @@ export interface WarmDispatchResult<T> extends Omit<DispatchResult<T>, "resume"
|
|
|
72
73
|
fork<U = undefined>(options: DispatchOptions<U>): Promise<WarmDispatchResult<U>>;
|
|
73
74
|
}
|
|
74
75
|
export interface Sandbox {
|
|
76
|
+
diagnose(options?: SandboxDiagnosticOptions): Promise<SandboxDiagnosticReport>;
|
|
75
77
|
readonly workspace: Workspace;
|
|
76
78
|
readonly root: string;
|
|
77
79
|
dispatch<T = undefined>(options: DispatchOptions<T>): Promise<WarmDispatchResult<T>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outpost.types.js","sourceRoot":"","sources":["../../src/application/outpost.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AgentAdapter } from \"../domain/agent.types.ts\";\nimport type { Command, CommandResult } from \"../domain/command.types.ts\";\nimport type { Brief } from \"../domain/prompts.types.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport type {\n BranchPolicy,\n Commit,\n Disposal,\n LifecycleHooks,\n StageLimits,\n WorkspaceRecord,\n} from \"../domain/workspace.types.ts\";\nimport type { Logging } from \"../infrastructure/journal.types.ts\";\nimport type { DispatchOptions, Execution } from \"./execution.types.ts\";\nimport type { VariableQuestion } from \"./interactive-brief.types.ts\";\n\nexport interface WorkspaceOptions {\n readonly signal?: AbortSignal;\n readonly repository?: string;\n readonly branch?: BranchPolicy;\n readonly copies?: readonly string[];\n readonly limits?: StageLimits;\n readonly label?: string;\n readonly hooks?: LifecycleHooks;\n}\n\nexport interface Workspace extends WorkspaceRecord {\n dispatch<T = undefined>(\n options: Omit<\n SandboxOptions,\n Exclude<keyof WorkspaceOptions, \"hooks\" | \"label\"> | \"workspace\"\n > &\n DispatchOptions<T> & { readonly agent: AgentAdapter },\n ): Promise<DispatchResult<T>>;\n sandbox(\n options?: Omit<\n SandboxOptions,\n Exclude<keyof WorkspaceOptions, \"hooks\" | \"label\"> | \"workspace\"\n >,\n ): Promise<Sandbox>;\n attach(\n options: Omit<\n SandboxOptions,\n Exclude<keyof WorkspaceOptions, \"hooks\" | \"label\"> | \"workspace\"\n > &\n AttachOptions & { readonly agent: AgentAdapter },\n ): Promise<AttachResult>;\n close(options?: { readonly preserve?: boolean }): Promise<Disposal>;\n integrate(): Promise<void>;\n [Symbol.asyncDispose](): Promise<void>;\n}\n\nexport interface SandboxOptions extends WorkspaceOptions {\n readonly includeUncommitted?: boolean;\n readonly agent?: AgentAdapter;\n readonly provider?: SandboxProvider;\n readonly workspace?: Workspace;\n readonly hooks?: LifecycleHooks;\n readonly signal?: AbortSignal;\n readonly logging?: Logging;\n readonly bootstrap?: boolean;\n readonly conversationHome?: string;\n}\n\nexport interface AttachOptions {\n readonly ask?: VariableQuestion;\n readonly agent?: AgentAdapter;\n readonly brief?: Brief;\n readonly continuation?: { readonly id: string; readonly fork?: boolean };\n readonly signal?: AbortSignal;\n readonly terminal?: Command[\"terminal\"];\n}\n\nexport interface AttachResult extends CommandResult, Disposal {\n readonly commits: readonly Commit[];\n readonly branch: string;\n readonly directory: string;\n}\n\nexport interface DispatchResult<T> extends Execution<T> {\n readonly branch: string;\n readonly directory: string;\n readonly commits: readonly Commit[];\n readonly transcript?: string;\n readonly log?: string;\n readonly retainedDirectory?: string;\n resume<U = undefined>(\n options: ContinuationOptions<U>,\n ): Promise<DispatchResult<U>>;\n fork<U = undefined>(\n options: ContinuationOptions<U>,\n ): Promise<DispatchResult<U>>;\n}\n\nexport type ContinuationOptions<T = undefined> = DispatchOptions<T> &\n Omit<SandboxOptions, \"agent\">;\n\nexport interface WarmDispatchResult<T> extends Omit<\n DispatchResult<T>,\n \"resume\" | \"fork\"\n> {\n resume<U = undefined>(\n options: DispatchOptions<U>,\n ): Promise<WarmDispatchResult<U>>;\n fork<U = undefined>(\n options: DispatchOptions<U>,\n ): Promise<WarmDispatchResult<U>>;\n}\n\nexport interface Sandbox {\n readonly workspace: Workspace;\n readonly root: string;\n dispatch<T = undefined>(\n options: DispatchOptions<T>,\n ): Promise<WarmDispatchResult<T>>;\n resume<T = undefined>(\n id: string,\n options: DispatchOptions<T>,\n ): Promise<WarmDispatchResult<T>>;\n fork<T = undefined>(\n id: string,\n options: DispatchOptions<T>,\n ): Promise<WarmDispatchResult<T>>;\n attach(options?: AttachOptions): Promise<AttachResult>;\n command(command: Command): Promise<CommandResult>;\n close(options?: { readonly preserve?: boolean }): Promise<Disposal>;\n [Symbol.asyncDispose](): Promise<void>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"outpost.types.js","sourceRoot":"","sources":["../../src/application/outpost.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AgentAdapter } from \"../domain/agent.types.ts\";\nimport type { Command, CommandResult } from \"../domain/command.types.ts\";\nimport type { Brief } from \"../domain/prompts.types.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport type {\n BranchPolicy,\n Commit,\n Disposal,\n LifecycleHooks,\n StageLimits,\n WorkspaceRecord,\n} from \"../domain/workspace.types.ts\";\nimport type { Logging } from \"../infrastructure/journal.types.ts\";\nimport type {\n SandboxDiagnosticOptions,\n SandboxDiagnosticReport,\n} from \"./doctor-sandbox.types.ts\";\nimport type { DispatchOptions, Execution } from \"./execution.types.ts\";\nimport type { VariableQuestion } from \"./interactive-brief.types.ts\";\n\nexport interface WorkspaceOptions {\n readonly signal?: AbortSignal;\n readonly repository?: string;\n readonly branch?: BranchPolicy;\n readonly copies?: readonly string[];\n readonly limits?: StageLimits;\n readonly label?: string;\n readonly hooks?: LifecycleHooks;\n}\n\nexport interface Workspace extends WorkspaceRecord {\n dispatch<T = undefined>(\n options: Omit<\n SandboxOptions,\n Exclude<keyof WorkspaceOptions, \"hooks\" | \"label\"> | \"workspace\"\n > &\n DispatchOptions<T> & { readonly agent: AgentAdapter },\n ): Promise<DispatchResult<T>>;\n sandbox(\n options?: Omit<\n SandboxOptions,\n Exclude<keyof WorkspaceOptions, \"hooks\" | \"label\"> | \"workspace\"\n >,\n ): Promise<Sandbox>;\n attach(\n options: Omit<\n SandboxOptions,\n Exclude<keyof WorkspaceOptions, \"hooks\" | \"label\"> | \"workspace\"\n > &\n AttachOptions & { readonly agent: AgentAdapter },\n ): Promise<AttachResult>;\n close(options?: { readonly preserve?: boolean }): Promise<Disposal>;\n integrate(): Promise<void>;\n [Symbol.asyncDispose](): Promise<void>;\n}\n\nexport interface SandboxOptions extends WorkspaceOptions {\n readonly includeUncommitted?: boolean;\n readonly agent?: AgentAdapter;\n readonly provider?: SandboxProvider;\n readonly workspace?: Workspace;\n readonly hooks?: LifecycleHooks;\n readonly signal?: AbortSignal;\n readonly logging?: Logging;\n readonly bootstrap?: boolean;\n readonly conversationHome?: string;\n}\n\nexport interface AttachOptions {\n readonly ask?: VariableQuestion;\n readonly agent?: AgentAdapter;\n readonly brief?: Brief;\n readonly continuation?: { readonly id: string; readonly fork?: boolean };\n readonly signal?: AbortSignal;\n readonly terminal?: Command[\"terminal\"];\n}\n\nexport interface AttachResult extends CommandResult, Disposal {\n readonly commits: readonly Commit[];\n readonly branch: string;\n readonly directory: string;\n}\n\nexport interface DispatchResult<T> extends Execution<T> {\n readonly branch: string;\n readonly directory: string;\n readonly commits: readonly Commit[];\n readonly transcript?: string;\n readonly log?: string;\n readonly retainedDirectory?: string;\n resume<U = undefined>(\n options: ContinuationOptions<U>,\n ): Promise<DispatchResult<U>>;\n fork<U = undefined>(\n options: ContinuationOptions<U>,\n ): Promise<DispatchResult<U>>;\n}\n\nexport type ContinuationOptions<T = undefined> = DispatchOptions<T> &\n Omit<SandboxOptions, \"agent\">;\n\nexport interface WarmDispatchResult<T> extends Omit<\n DispatchResult<T>,\n \"resume\" | \"fork\"\n> {\n resume<U = undefined>(\n options: DispatchOptions<U>,\n ): Promise<WarmDispatchResult<U>>;\n fork<U = undefined>(\n options: DispatchOptions<U>,\n ): Promise<WarmDispatchResult<U>>;\n}\n\nexport interface Sandbox {\n diagnose(\n options?: SandboxDiagnosticOptions,\n ): Promise<SandboxDiagnosticReport>;\n readonly workspace: Workspace;\n readonly root: string;\n dispatch<T = undefined>(\n options: DispatchOptions<T>,\n ): Promise<WarmDispatchResult<T>>;\n resume<T = undefined>(\n id: string,\n options: DispatchOptions<T>,\n ): Promise<WarmDispatchResult<T>>;\n fork<T = undefined>(\n id: string,\n options: DispatchOptions<T>,\n ): Promise<WarmDispatchResult<T>>;\n attach(options?: AttachOptions): Promise<AttachResult>;\n command(command: Command): Promise<CommandResult>;\n close(options?: { readonly preserve?: boolean }): Promise<Disposal>;\n [Symbol.asyncDispose](): Promise<void>;\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { safeDestination } from "../infrastructure/files.js";
|
|
5
|
+
import { hashInspectionEntry } from "../infrastructure/inspection-hash.js";
|
|
6
|
+
import { recoveryChecksumDefaults } from "./recovery-checksums.constants.js";
|
|
7
|
+
import { recoveryChecksumPaths } from "./recovery-checksum-paths.js";
|
|
8
|
+
export async function captureRecoveryChecksums(root, state) {
|
|
9
|
+
const entries = [];
|
|
10
|
+
for (const path of recoveryChecksumPaths(state))
|
|
11
|
+
entries.push({
|
|
12
|
+
path,
|
|
13
|
+
...(await hashInspectionEntry(await safeDestination(root, path))),
|
|
14
|
+
});
|
|
15
|
+
const manifest = {
|
|
16
|
+
version: 1,
|
|
17
|
+
algorithm: "sha256",
|
|
18
|
+
entries,
|
|
19
|
+
};
|
|
20
|
+
const temporary = join(root, `.checksums-${randomUUID()}.tmp`);
|
|
21
|
+
try {
|
|
22
|
+
await writeFile(temporary, JSON.stringify(manifest), {
|
|
23
|
+
flag: "wx",
|
|
24
|
+
mode: 0o600,
|
|
25
|
+
});
|
|
26
|
+
await rename(temporary, join(root, recoveryChecksumDefaults.filename));
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await rm(temporary, { force: true });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=recovery-checksum-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-checksum-capture.js","sourceRoot":"","sources":["../../src/application/recovery-checksum-capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAK7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,IAAY,EACZ,KAA4B;IAE5B,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,KAAK,MAAM,IAAI,IAAI,qBAAqB,CAAC,KAAK,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC;YACX,IAAI;YACJ,GAAG,CAAC,MAAM,mBAAmB,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;SAClE,CAAC,CAAC;IACL,MAAM,QAAQ,GAA6B;QACzC,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,QAAQ;QACnB,OAAO;KACR,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,cAAc,UAAU,EAAE,MAAM,CAAC,CAAC;IAC/D,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;YACnD,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACzE,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;AACH,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { rename, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { safeDestination } from \"../infrastructure/files.ts\";\nimport { hashInspectionEntry } from \"../infrastructure/inspection-hash.ts\";\nimport { recoveryChecksumDefaults } from \"./recovery-checksums.constants.ts\";\nimport type {\n RecoveryChecksumEntry,\n RecoveryChecksumManifest,\n} from \"./recovery-checksums.types.ts\";\nimport { recoveryChecksumPaths } from \"./recovery-checksum-paths.ts\";\nimport type { RecoveryTransferState } from \"./recovery-verification.types.ts\";\n\nexport async function captureRecoveryChecksums(\n root: string,\n state: RecoveryTransferState,\n): Promise<void> {\n const entries: RecoveryChecksumEntry[] = [];\n for (const path of recoveryChecksumPaths(state))\n entries.push({\n path,\n ...(await hashInspectionEntry(await safeDestination(root, path))),\n });\n const manifest: RecoveryChecksumManifest = {\n version: 1,\n algorithm: \"sha256\",\n entries,\n };\n const temporary = join(root, `.checksums-${randomUUID()}.tmp`);\n try {\n await writeFile(temporary, JSON.stringify(manifest), {\n flag: \"wx\",\n mode: 0o600,\n });\n await rename(temporary, join(root, recoveryChecksumDefaults.filename));\n } finally {\n await rm(temporary, { force: true });\n }\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { recoveryTransferPatches } from "./recovery-verification.constants.js";
|
|
2
|
+
export function recoveryChecksumPaths(state) {
|
|
3
|
+
return [
|
|
4
|
+
"state.json",
|
|
5
|
+
...recoveryTransferPatches,
|
|
6
|
+
...(state.previous !== state.next ? ["commits.bundle"] : []),
|
|
7
|
+
...state.previousExtras.map((path) => `previous-files/${path}`),
|
|
8
|
+
...state.incoming.map((path) => `incoming/${path}`),
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=recovery-checksum-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-checksum-paths.js","sourceRoot":"","sources":["../../src/application/recovery-checksum-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAG/E,MAAM,UAAU,qBAAqB,CAAC,KAA4B;IAChE,OAAO;QACL,YAAY;QACZ,GAAG,uBAAuB;QAC1B,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAC/D,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,IAAI,EAAE,CAAC;KACpD,CAAC;AACJ,CAAC","sourcesContent":["import { recoveryTransferPatches } from \"./recovery-verification.constants.ts\";\nimport type { RecoveryTransferState } from \"./recovery-verification.types.ts\";\n\nexport function recoveryChecksumPaths(state: RecoveryTransferState): string[] {\n return [\n \"state.json\",\n ...recoveryTransferPatches,\n ...(state.previous !== state.next ? [\"commits.bundle\"] : []),\n ...state.previousExtras.map((path) => `previous-files/${path}`),\n ...state.incoming.map((path) => `incoming/${path}`),\n ];\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-checksums.constants.js","sourceRoot":"","sources":["../../src/application/recovery-checksums.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,QAAQ,EAAE,gBAAgB;IAC1B,gBAAgB,EAAE,SAAS;IAC3B,QAAQ,EAAE,aAAa;CACf,CAAC","sourcesContent":["export const recoveryChecksumDefaults = {\n filename: \"checksums.json\",\n maxManifestBytes: 1_048_576,\n maxBytes: 1_073_741_824,\n} as const;\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { RecoveryChecksumResult } from "./recovery-checksums.types.ts";
|
|
2
|
+
import type { RecoveryTransferState } from "./recovery-verification.types.ts";
|
|
3
|
+
export declare function verifyRecoveryChecksums(root: string, state: RecoveryTransferState, maxBytes?: number): Promise<RecoveryChecksumResult>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { OutpostError, positive } from "../domain/errors.js";
|
|
3
|
+
import { safeDestination } from "../infrastructure/files.js";
|
|
4
|
+
import { hashInspectionEntry } from "../infrastructure/inspection-hash.js";
|
|
5
|
+
import { readInspectionFile } from "../infrastructure/inspection-file.js";
|
|
6
|
+
import { recoveryChecksumPaths } from "./recovery-checksum-paths.js";
|
|
7
|
+
import { recoveryChecksumDefaults } from "./recovery-checksums.constants.js";
|
|
8
|
+
function validManifest(value, expected) {
|
|
9
|
+
if (!value ||
|
|
10
|
+
typeof value !== "object" ||
|
|
11
|
+
!("version" in value) ||
|
|
12
|
+
value.version !== 1 ||
|
|
13
|
+
!("algorithm" in value) ||
|
|
14
|
+
value.algorithm !== "sha256" ||
|
|
15
|
+
!("entries" in value) ||
|
|
16
|
+
!Array.isArray(value.entries) ||
|
|
17
|
+
value.entries.length !== expected.length)
|
|
18
|
+
return false;
|
|
19
|
+
const remaining = new Set(expected);
|
|
20
|
+
if (remaining.size !== expected.length)
|
|
21
|
+
return false;
|
|
22
|
+
const entries = value.entries;
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
if (!entry ||
|
|
25
|
+
typeof entry !== "object" ||
|
|
26
|
+
!("path" in entry) ||
|
|
27
|
+
typeof entry.path !== "string" ||
|
|
28
|
+
!remaining.delete(entry.path) ||
|
|
29
|
+
!("kind" in entry) ||
|
|
30
|
+
(entry.kind !== "file" && entry.kind !== "symlink") ||
|
|
31
|
+
!("bytes" in entry) ||
|
|
32
|
+
typeof entry.bytes !== "number" ||
|
|
33
|
+
!Number.isSafeInteger(entry.bytes) ||
|
|
34
|
+
entry.bytes < 0 ||
|
|
35
|
+
!("sha256" in entry) ||
|
|
36
|
+
typeof entry.sha256 !== "string" ||
|
|
37
|
+
!/^[a-f0-9]{64}$/.test(entry.sha256))
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return remaining.size === 0;
|
|
41
|
+
}
|
|
42
|
+
export async function verifyRecoveryChecksums(root, state, maxBytes = recoveryChecksumDefaults.maxBytes) {
|
|
43
|
+
positive(maxBytes, "maxBytes");
|
|
44
|
+
const checks = [];
|
|
45
|
+
let bytesChecked = 0;
|
|
46
|
+
const manifestPath = join(root, recoveryChecksumDefaults.filename);
|
|
47
|
+
const unavailable = (code) => ({
|
|
48
|
+
integrity: "unverified",
|
|
49
|
+
bytesChecked,
|
|
50
|
+
maxBytes,
|
|
51
|
+
checks: [{ path: manifestPath, status: "fail", code }],
|
|
52
|
+
});
|
|
53
|
+
let manifest;
|
|
54
|
+
try {
|
|
55
|
+
manifest = JSON.parse((await readInspectionFile(manifestPath, recoveryChecksumDefaults.maxManifestBytes)).toString("utf8"));
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return unavailable("CHECKSUMS_UNAVAILABLE");
|
|
59
|
+
}
|
|
60
|
+
if (!validManifest(manifest, recoveryChecksumPaths(state)))
|
|
61
|
+
return unavailable("INVALID_CHECKSUM_MANIFEST");
|
|
62
|
+
for (const entry of manifest.entries) {
|
|
63
|
+
const path = join(root, entry.path);
|
|
64
|
+
try {
|
|
65
|
+
const actual = await hashInspectionEntry(await safeDestination(root, entry.path), maxBytes - bytesChecked);
|
|
66
|
+
bytesChecked += actual.bytes;
|
|
67
|
+
const matches = actual.kind === entry.kind &&
|
|
68
|
+
actual.bytes === entry.bytes &&
|
|
69
|
+
actual.sha256 === entry.sha256;
|
|
70
|
+
checks.push({
|
|
71
|
+
path,
|
|
72
|
+
status: matches ? "pass" : "fail",
|
|
73
|
+
code: matches ? "CHECKSUM_MATCH" : "CHECKSUM_MISMATCH",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const code = error instanceof OutpostError &&
|
|
78
|
+
error.details.reason === "CHECKSUM_LIMIT"
|
|
79
|
+
? "CHECKSUM_LIMIT"
|
|
80
|
+
: "CHECKSUM_UNAVAILABLE";
|
|
81
|
+
checks.push({ path, status: "fail", code });
|
|
82
|
+
return { integrity: "unverified", bytesChecked, maxBytes, checks };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
integrity: checks.every((check) => check.status === "pass")
|
|
87
|
+
? "checksums-match"
|
|
88
|
+
: "checksums-mismatch",
|
|
89
|
+
bytesChecked,
|
|
90
|
+
maxBytes,
|
|
91
|
+
checks,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=recovery-checksums.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-checksums.js","sourceRoot":"","sources":["../../src/application/recovery-checksums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAU7E,SAAS,aAAa,CACpB,KAAc,EACd,QAA2B;IAE3B,IACE,CAAC,KAAK;QACN,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC;QACrB,KAAK,CAAC,OAAO,KAAK,CAAC;QACnB,CAAC,CAAC,WAAW,IAAI,KAAK,CAAC;QACvB,KAAK,CAAC,SAAS,KAAK,QAAQ;QAC5B,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC;QACrB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;QAC7B,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAExC,OAAO,KAAK,CAAC;IACf,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACrD,MAAM,OAAO,GAAuB,KAAK,CAAC,OAAO,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IACE,CAAC,KAAK;YACN,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;YAClB,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAC9B,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YAC7B,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;YAClB,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;YACnD,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC;YACnB,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;YAC/B,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC;YAClC,KAAK,CAAC,KAAK,GAAG,CAAC;YACf,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC;YACpB,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;YAChC,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAEpC,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,SAAS,CAAC,IAAI,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,IAAY,EACZ,KAA4B,EAC5B,WAAmB,wBAAwB,CAAC,QAAQ;IAEpD,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC/B,MAAM,MAAM,GAA6B,EAAE,CAAC;IAC5C,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACnE,MAAM,WAAW,GAAG,CAAC,IAAY,EAA0B,EAAE,CAAC,CAAC;QAC7D,SAAS,EAAE,YAAY;QACvB,YAAY;QACZ,QAAQ;QACR,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KACvD,CAAC,CAAC;IACH,IAAI,QAAiB,CAAC;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CACnB,CACE,MAAM,kBAAkB,CACtB,YAAY,EACZ,wBAAwB,CAAC,gBAAgB,CAC1C,CACF,CAAC,QAAQ,CAAC,MAAM,CAAC,CACnB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,CAAC,uBAAuB,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC;QACxD,OAAO,WAAW,CAAC,2BAA2B,CAAC,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CACtC,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EACvC,QAAQ,GAAG,YAAY,CACxB,CAAC;YACF,YAAY,IAAI,MAAM,CAAC,KAAK,CAAC;YAC7B,MAAM,OAAO,GACX,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;gBAC1B,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;gBAC5B,MAAM,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;gBACjC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,mBAAmB;aACvD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,GACR,KAAK,YAAY,YAAY;gBAC7B,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,gBAAgB;gBACvC,CAAC,CAAC,gBAAgB;gBAClB,CAAC,CAAC,sBAAsB,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACrE,CAAC;IACH,CAAC;IACD,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC;YACzD,CAAC,CAAC,iBAAiB;YACnB,CAAC,CAAC,oBAAoB;QACxB,YAAY;QACZ,QAAQ;QACR,MAAM;KACP,CAAC;AACJ,CAAC","sourcesContent":["import { join } from \"node:path\";\nimport { OutpostError, positive } from \"../domain/errors.ts\";\nimport { safeDestination } from \"../infrastructure/files.ts\";\nimport { hashInspectionEntry } from \"../infrastructure/inspection-hash.ts\";\nimport { readInspectionFile } from \"../infrastructure/inspection-file.ts\";\nimport { recoveryChecksumPaths } from \"./recovery-checksum-paths.ts\";\nimport { recoveryChecksumDefaults } from \"./recovery-checksums.constants.ts\";\nimport type {\n RecoveryChecksumManifest,\n RecoveryChecksumResult,\n} from \"./recovery-checksums.types.ts\";\nimport type {\n RecoveryStructureCheck,\n RecoveryTransferState,\n} from \"./recovery-verification.types.ts\";\n\nfunction validManifest(\n value: unknown,\n expected: readonly string[],\n): value is RecoveryChecksumManifest {\n if (\n !value ||\n typeof value !== \"object\" ||\n !(\"version\" in value) ||\n value.version !== 1 ||\n !(\"algorithm\" in value) ||\n value.algorithm !== \"sha256\" ||\n !(\"entries\" in value) ||\n !Array.isArray(value.entries) ||\n value.entries.length !== expected.length\n )\n return false;\n const remaining = new Set(expected);\n if (remaining.size !== expected.length) return false;\n const entries: readonly unknown[] = value.entries;\n for (const entry of entries) {\n if (\n !entry ||\n typeof entry !== \"object\" ||\n !(\"path\" in entry) ||\n typeof entry.path !== \"string\" ||\n !remaining.delete(entry.path) ||\n !(\"kind\" in entry) ||\n (entry.kind !== \"file\" && entry.kind !== \"symlink\") ||\n !(\"bytes\" in entry) ||\n typeof entry.bytes !== \"number\" ||\n !Number.isSafeInteger(entry.bytes) ||\n entry.bytes < 0 ||\n !(\"sha256\" in entry) ||\n typeof entry.sha256 !== \"string\" ||\n !/^[a-f0-9]{64}$/.test(entry.sha256)\n )\n return false;\n }\n return remaining.size === 0;\n}\n\nexport async function verifyRecoveryChecksums(\n root: string,\n state: RecoveryTransferState,\n maxBytes: number = recoveryChecksumDefaults.maxBytes,\n): Promise<RecoveryChecksumResult> {\n positive(maxBytes, \"maxBytes\");\n const checks: RecoveryStructureCheck[] = [];\n let bytesChecked = 0;\n const manifestPath = join(root, recoveryChecksumDefaults.filename);\n const unavailable = (code: string): RecoveryChecksumResult => ({\n integrity: \"unverified\",\n bytesChecked,\n maxBytes,\n checks: [{ path: manifestPath, status: \"fail\", code }],\n });\n let manifest: unknown;\n try {\n manifest = JSON.parse(\n (\n await readInspectionFile(\n manifestPath,\n recoveryChecksumDefaults.maxManifestBytes,\n )\n ).toString(\"utf8\"),\n );\n } catch {\n return unavailable(\"CHECKSUMS_UNAVAILABLE\");\n }\n if (!validManifest(manifest, recoveryChecksumPaths(state)))\n return unavailable(\"INVALID_CHECKSUM_MANIFEST\");\n for (const entry of manifest.entries) {\n const path = join(root, entry.path);\n try {\n const actual = await hashInspectionEntry(\n await safeDestination(root, entry.path),\n maxBytes - bytesChecked,\n );\n bytesChecked += actual.bytes;\n const matches =\n actual.kind === entry.kind &&\n actual.bytes === entry.bytes &&\n actual.sha256 === entry.sha256;\n checks.push({\n path,\n status: matches ? \"pass\" : \"fail\",\n code: matches ? \"CHECKSUM_MATCH\" : \"CHECKSUM_MISMATCH\",\n });\n } catch (error) {\n const code =\n error instanceof OutpostError &&\n error.details.reason === \"CHECKSUM_LIMIT\"\n ? \"CHECKSUM_LIMIT\"\n : \"CHECKSUM_UNAVAILABLE\";\n checks.push({ path, status: \"fail\", code });\n return { integrity: \"unverified\", bytesChecked, maxBytes, checks };\n }\n }\n return {\n integrity: checks.every((check) => check.status === \"pass\")\n ? \"checksums-match\"\n : \"checksums-mismatch\",\n bytesChecked,\n maxBytes,\n checks,\n };\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { InspectionHash } from "../infrastructure/inspection-hash.types.ts";
|
|
2
|
+
import type { RecoveryStructureCheck } from "./recovery-verification.types.ts";
|
|
3
|
+
export interface RecoveryChecksumEntry extends InspectionHash {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
}
|
|
6
|
+
export interface RecoveryChecksumManifest {
|
|
7
|
+
readonly version: 1;
|
|
8
|
+
readonly algorithm: "sha256";
|
|
9
|
+
readonly entries: readonly RecoveryChecksumEntry[];
|
|
10
|
+
}
|
|
11
|
+
export type RecoveryIntegrity = "unverified" | "checksums-match" | "checksums-mismatch";
|
|
12
|
+
export interface RecoveryChecksumResult {
|
|
13
|
+
readonly integrity: RecoveryIntegrity;
|
|
14
|
+
readonly bytesChecked: number;
|
|
15
|
+
readonly maxBytes: number;
|
|
16
|
+
readonly checks: readonly RecoveryStructureCheck[];
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-checksums.types.js","sourceRoot":"","sources":["../../src/application/recovery-checksums.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { InspectionHash } from \"../infrastructure/inspection-hash.types.ts\";\nimport type { RecoveryStructureCheck } from \"./recovery-verification.types.ts\";\n\nexport interface RecoveryChecksumEntry extends InspectionHash {\n readonly path: string;\n}\nexport interface RecoveryChecksumManifest {\n readonly version: 1;\n readonly algorithm: \"sha256\";\n readonly entries: readonly RecoveryChecksumEntry[];\n}\nexport type RecoveryIntegrity =\n \"unverified\" | \"checksums-match\" | \"checksums-mismatch\";\nexport interface RecoveryChecksumResult {\n readonly integrity: RecoveryIntegrity;\n readonly bytesChecked: number;\n readonly maxBytes: number;\n readonly checks: readonly RecoveryStructureCheck[];\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { inspectLocks } from "../infrastructure/git/lock-inspection.js";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { directory } from "../infrastructure/files.js";
|
|
4
|
+
import { git } from "../infrastructure/git/command.js";
|
|
5
|
+
import { inspectWorktreeGit } from "../infrastructure/git/worktree-inspection.js";
|
|
6
|
+
import { storageInventory } from "../infrastructure/storage-inventory.js";
|
|
7
|
+
export async function inspectRecovery(options = {}) {
|
|
8
|
+
const requested = await directory(options.repository);
|
|
9
|
+
const repository = await directory((await git(requested, ["rev-parse", "--show-toplevel"])).trim());
|
|
10
|
+
const inventory = await storageInventory(join(repository, ".outpost"), options.maxEntries);
|
|
11
|
+
const gitReport = options.git
|
|
12
|
+
? await inspectWorktreeGit(repository, inventory.categories.find((category) => category.name === "workspaces")
|
|
13
|
+
?.entries ?? [])
|
|
14
|
+
: undefined;
|
|
15
|
+
const lockReport = options.locks
|
|
16
|
+
? await inspectLocks(inventory.categories.find((category) => category.name === "locks")
|
|
17
|
+
?.entries ?? [])
|
|
18
|
+
: undefined;
|
|
19
|
+
return {
|
|
20
|
+
repository,
|
|
21
|
+
activity: "unverified",
|
|
22
|
+
...inventory,
|
|
23
|
+
...(gitReport ? { git: gitReport } : {}),
|
|
24
|
+
...(lockReport ? { locks: lockReport } : {}),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=recovery-inspection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-inspection.js","sourceRoot":"","sources":["../../src/application/recovery-inspection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAM1E,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAqC,EAAE;IAEvC,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,MAAM,SAAS,CAChC,CAAC,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAChE,CAAC;IACF,MAAM,SAAS,GAAG,MAAM,gBAAgB,CACtC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,EAC5B,OAAO,CAAC,UAAU,CACnB,CAAC;IACF,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG;QAC3B,CAAC,CAAC,MAAM,kBAAkB,CACtB,UAAU,EACV,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,CAAC;YACrE,EAAE,OAAO,IAAI,EAAE,CAClB;QACH,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK;QAC9B,CAAC,CAAC,MAAM,YAAY,CAChB,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,CAAC;YAChE,EAAE,OAAO,IAAI,EAAE,CAClB;QACH,CAAC,CAAC,SAAS,CAAC;IACd,OAAO;QACL,UAAU;QACV,QAAQ,EAAE,YAAY;QACtB,GAAG,SAAS;QACZ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC;AACJ,CAAC","sourcesContent":["import { inspectLocks } from \"../infrastructure/git/lock-inspection.ts\";\nimport { join } from \"node:path\";\nimport { directory } from \"../infrastructure/files.ts\";\nimport { git } from \"../infrastructure/git/command.ts\";\nimport { inspectWorktreeGit } from \"../infrastructure/git/worktree-inspection.ts\";\nimport { storageInventory } from \"../infrastructure/storage-inventory.ts\";\nimport type {\n RecoveryInspection,\n RecoveryInspectionOptions,\n} from \"./recovery-inspection.types.ts\";\n\nexport async function inspectRecovery(\n options: RecoveryInspectionOptions = {},\n): Promise<RecoveryInspection> {\n const requested = await directory(options.repository);\n const repository = await directory(\n (await git(requested, [\"rev-parse\", \"--show-toplevel\"])).trim(),\n );\n const inventory = await storageInventory(\n join(repository, \".outpost\"),\n options.maxEntries,\n );\n const gitReport = options.git\n ? await inspectWorktreeGit(\n repository,\n inventory.categories.find((category) => category.name === \"workspaces\")\n ?.entries ?? [],\n )\n : undefined;\n const lockReport = options.locks\n ? await inspectLocks(\n inventory.categories.find((category) => category.name === \"locks\")\n ?.entries ?? [],\n )\n : undefined;\n return {\n repository,\n activity: \"unverified\",\n ...inventory,\n ...(gitReport ? { git: gitReport } : {}),\n ...(lockReport ? { locks: lockReport } : {}),\n };\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { LockInspection } from "../infrastructure/git/lock-inspection.types.ts";
|
|
2
|
+
import type { WorkspaceGitInspection } from "../infrastructure/git/worktree-inspection.types.ts";
|
|
3
|
+
import type { StorageInventory } from "../infrastructure/storage-inventory.types.ts";
|
|
4
|
+
export interface RecoveryInspectionOptions {
|
|
5
|
+
readonly repository?: string;
|
|
6
|
+
readonly maxEntries?: number;
|
|
7
|
+
readonly git?: boolean;
|
|
8
|
+
readonly locks?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface RecoveryInspection extends StorageInventory {
|
|
11
|
+
readonly repository: string;
|
|
12
|
+
readonly activity: "unverified";
|
|
13
|
+
readonly git?: WorkspaceGitInspection;
|
|
14
|
+
readonly locks?: LockInspection;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-inspection.types.js","sourceRoot":"","sources":["../../src/application/recovery-inspection.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { LockInspection } from \"../infrastructure/git/lock-inspection.types.ts\";\nimport type { WorkspaceGitInspection } from \"../infrastructure/git/worktree-inspection.types.ts\";\nimport type { StorageInventory } from \"../infrastructure/storage-inventory.types.ts\";\n\nexport interface RecoveryInspectionOptions {\n readonly repository?: string;\n readonly maxEntries?: number;\n readonly git?: boolean;\n readonly locks?: boolean;\n}\nexport interface RecoveryInspection extends StorageInventory {\n readonly repository: string;\n readonly activity: \"unverified\";\n readonly git?: WorkspaceGitInspection;\n readonly locks?: LockInspection;\n}\n"]}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { copyFile, lstat, mkdir, mkdtemp, realpath, rm, } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { directory, safeDestination } from "../infrastructure/files.js";
|
|
5
|
+
import { verificationGit as git } from "../infrastructure/git/verification-command.js";
|
|
6
|
+
import { hashInspectionEntry } from "../infrastructure/inspection-hash.js";
|
|
7
|
+
import { recoveryTransferPatches } from "./recovery-verification.constants.js";
|
|
8
|
+
export async function verifyRecoveryRestorability(root, state, repository) {
|
|
9
|
+
const temporary = await realpath(await mkdtemp(join(tmpdir(), "outpost-restore-check-")));
|
|
10
|
+
const checks = [];
|
|
11
|
+
let stage = "REPOSITORY_OBJECTS";
|
|
12
|
+
try {
|
|
13
|
+
const source = await directory(repository);
|
|
14
|
+
stage = "SOURCE_UNSUPPORTED";
|
|
15
|
+
const common = (await git(source, [
|
|
16
|
+
"rev-parse",
|
|
17
|
+
"--path-format=absolute",
|
|
18
|
+
"--git-common-dir",
|
|
19
|
+
])).trim();
|
|
20
|
+
const configuration = await git(source, [
|
|
21
|
+
"config",
|
|
22
|
+
"--local",
|
|
23
|
+
"--null",
|
|
24
|
+
"--list",
|
|
25
|
+
]);
|
|
26
|
+
if (/(?:extensions\.partialclone|remote\.[^\n\0]+\.(?:promisor|partialclonefilter))\n/i.test(configuration))
|
|
27
|
+
throw new Error("Partial repositories are unsupported");
|
|
28
|
+
for (const name of [
|
|
29
|
+
"shallow",
|
|
30
|
+
"objects/info/alternates",
|
|
31
|
+
"objects/info/http-alternates",
|
|
32
|
+
]) {
|
|
33
|
+
const exists = await lstat(join(common, name)).then(() => true, (error) => {
|
|
34
|
+
if (error &&
|
|
35
|
+
typeof error === "object" &&
|
|
36
|
+
"code" in error &&
|
|
37
|
+
error.code === "ENOENT")
|
|
38
|
+
return false;
|
|
39
|
+
throw error;
|
|
40
|
+
});
|
|
41
|
+
if (exists)
|
|
42
|
+
throw new Error("Repository depends on external or shallow objects");
|
|
43
|
+
}
|
|
44
|
+
const checkout = join(temporary, "checkout");
|
|
45
|
+
const snapshot = join(temporary, "transfer");
|
|
46
|
+
await mkdir(snapshot);
|
|
47
|
+
for (const name of [
|
|
48
|
+
...recoveryTransferPatches,
|
|
49
|
+
...(state.previous !== state.next ? ["commits.bundle"] : []),
|
|
50
|
+
]) {
|
|
51
|
+
stage = "TRANSFER_SNAPSHOT";
|
|
52
|
+
const path = await safeDestination(root, name);
|
|
53
|
+
const before = await hashInspectionEntry(path);
|
|
54
|
+
if (before.kind !== "file")
|
|
55
|
+
throw new Error("Expected a regular transfer file");
|
|
56
|
+
await copyFile(path, join(snapshot, name));
|
|
57
|
+
const copied = await hashInspectionEntry(join(snapshot, name));
|
|
58
|
+
if (before.sha256 !== copied.sha256 || before.bytes !== copied.bytes)
|
|
59
|
+
throw new Error("Transfer changed while copying");
|
|
60
|
+
}
|
|
61
|
+
stage = "REPOSITORY_OBJECTS";
|
|
62
|
+
await git(temporary, [
|
|
63
|
+
"clone",
|
|
64
|
+
"--local",
|
|
65
|
+
"--no-hardlinks",
|
|
66
|
+
"--no-checkout",
|
|
67
|
+
"--",
|
|
68
|
+
source,
|
|
69
|
+
checkout,
|
|
70
|
+
]);
|
|
71
|
+
if (state.previous !== state.next) {
|
|
72
|
+
stage = "BUNDLE_OBJECTS";
|
|
73
|
+
await git(checkout, [
|
|
74
|
+
"bundle",
|
|
75
|
+
"verify",
|
|
76
|
+
join(snapshot, "commits.bundle"),
|
|
77
|
+
]);
|
|
78
|
+
await git(checkout, [
|
|
79
|
+
"bundle",
|
|
80
|
+
"unbundle",
|
|
81
|
+
join(snapshot, "commits.bundle"),
|
|
82
|
+
]);
|
|
83
|
+
checks.push({
|
|
84
|
+
path: join(root, "commits.bundle"),
|
|
85
|
+
status: "pass",
|
|
86
|
+
code: "BUNDLE_OBJECTS_VALID",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
stage = "COMMIT_OBJECTS";
|
|
90
|
+
await git(checkout, ["cat-file", "-e", `${state.previous}^{commit}`]);
|
|
91
|
+
await git(checkout, ["cat-file", "-e", `${state.next}^{commit}`]);
|
|
92
|
+
await git(checkout, [
|
|
93
|
+
"fsck",
|
|
94
|
+
"--strict",
|
|
95
|
+
"--no-reflogs",
|
|
96
|
+
state.previous,
|
|
97
|
+
state.next,
|
|
98
|
+
]);
|
|
99
|
+
checks.push({ path: root, status: "pass", code: "COMMIT_OBJECTS_VALID" });
|
|
100
|
+
for (const [name, commit, cached] of [
|
|
101
|
+
["previous.patch", state.previous, false],
|
|
102
|
+
["previous-index.patch", state.previous, true],
|
|
103
|
+
["remote.patch", state.next, false],
|
|
104
|
+
]) {
|
|
105
|
+
stage = `PATCH_${name.toUpperCase().replaceAll(/[.-]/g, "_")}`;
|
|
106
|
+
await git(checkout, ["reset", "--hard", commit]);
|
|
107
|
+
const patch = join(snapshot, name);
|
|
108
|
+
if ((await lstat(patch)).size) {
|
|
109
|
+
const args = [
|
|
110
|
+
"apply",
|
|
111
|
+
"--binary",
|
|
112
|
+
...(cached ? ["--cached"] : []),
|
|
113
|
+
patch,
|
|
114
|
+
];
|
|
115
|
+
await git(checkout, [...args.slice(0, -1), "--check", patch]);
|
|
116
|
+
await git(checkout, args);
|
|
117
|
+
}
|
|
118
|
+
checks.push({
|
|
119
|
+
path: join(root, name),
|
|
120
|
+
status: "pass",
|
|
121
|
+
code: "PATCH_APPLIES",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
checks.push({
|
|
127
|
+
path: root,
|
|
128
|
+
status: "fail",
|
|
129
|
+
code: stage === "SOURCE_UNSUPPORTED" ? stage : `${stage}_FAILED`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
await rm(temporary, { recursive: true, force: true, maxRetries: 3 });
|
|
134
|
+
}
|
|
135
|
+
return checks;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=recovery-restorability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-restorability.js","sourceRoot":"","sources":["../../src/application/recovery-restorability.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n copyFile,\n lstat,\n mkdir,\n mkdtemp,\n realpath,\n rm,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { directory, safeDestination } from \"../infrastructure/files.ts\";\nimport { verificationGit as git } from \"../infrastructure/git/verification-command.ts\";\nimport { hashInspectionEntry } from \"../infrastructure/inspection-hash.ts\";\nimport { recoveryTransferPatches } from \"./recovery-verification.constants.ts\";\nimport type {\n RecoveryStructureCheck,\n RecoveryTransferState,\n} from \"./recovery-verification.types.ts\";\n\nexport async function verifyRecoveryRestorability(\n root: string,\n state: RecoveryTransferState,\n repository: string,\n): Promise<readonly RecoveryStructureCheck[]> {\n const temporary = await realpath(\n await mkdtemp(join(tmpdir(), \"outpost-restore-check-\")),\n );\n const checks: RecoveryStructureCheck[] = [];\n let stage = \"REPOSITORY_OBJECTS\";\n try {\n const source = await directory(repository);\n stage = \"SOURCE_UNSUPPORTED\";\n const common = (\n await git(source, [\n \"rev-parse\",\n \"--path-format=absolute\",\n \"--git-common-dir\",\n ])\n ).trim();\n const configuration = await git(source, [\n \"config\",\n \"--local\",\n \"--null\",\n \"--list\",\n ]);\n if (\n /(?:extensions\\.partialclone|remote\\.[^\\n\\0]+\\.(?:promisor|partialclonefilter))\\n/i.test(\n configuration,\n )\n )\n throw new Error(\"Partial repositories are unsupported\");\n for (const name of [\n \"shallow\",\n \"objects/info/alternates\",\n \"objects/info/http-alternates\",\n ]) {\n const exists = await lstat(join(common, name)).then(\n () => true,\n (error: unknown) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n )\n return false;\n throw error;\n },\n );\n if (exists)\n throw new Error(\"Repository depends on external or shallow objects\");\n }\n const checkout = join(temporary, \"checkout\");\n const snapshot = join(temporary, \"transfer\");\n await mkdir(snapshot);\n for (const name of [\n ...recoveryTransferPatches,\n ...(state.previous !== state.next ? [\"commits.bundle\"] : []),\n ]) {\n stage = \"TRANSFER_SNAPSHOT\";\n const path = await safeDestination(root, name);\n const before = await hashInspectionEntry(path);\n if (before.kind !== \"file\")\n throw new Error(\"Expected a regular transfer file\");\n await copyFile(path, join(snapshot, name));\n const copied = await hashInspectionEntry(join(snapshot, name));\n if (before.sha256 !== copied.sha256 || before.bytes !== copied.bytes)\n throw new Error(\"Transfer changed while copying\");\n }\n stage = \"REPOSITORY_OBJECTS\";\n await git(temporary, [\n \"clone\",\n \"--local\",\n \"--no-hardlinks\",\n \"--no-checkout\",\n \"--\",\n source,\n checkout,\n ]);\n if (state.previous !== state.next) {\n stage = \"BUNDLE_OBJECTS\";\n await git(checkout, [\n \"bundle\",\n \"verify\",\n join(snapshot, \"commits.bundle\"),\n ]);\n await git(checkout, [\n \"bundle\",\n \"unbundle\",\n join(snapshot, \"commits.bundle\"),\n ]);\n checks.push({\n path: join(root, \"commits.bundle\"),\n status: \"pass\",\n code: \"BUNDLE_OBJECTS_VALID\",\n });\n }\n stage = \"COMMIT_OBJECTS\";\n await git(checkout, [\"cat-file\", \"-e\", `${state.previous}^{commit}`]);\n await git(checkout, [\"cat-file\", \"-e\", `${state.next}^{commit}`]);\n await git(checkout, [\n \"fsck\",\n \"--strict\",\n \"--no-reflogs\",\n state.previous,\n state.next,\n ]);\n checks.push({ path: root, status: \"pass\", code: \"COMMIT_OBJECTS_VALID\" });\n for (const [name, commit, cached] of [\n [\"previous.patch\", state.previous, false],\n [\"previous-index.patch\", state.previous, true],\n [\"remote.patch\", state.next, false],\n ] as const) {\n stage = `PATCH_${name.toUpperCase().replaceAll(/[.-]/g, \"_\")}`;\n await git(checkout, [\"reset\", \"--hard\", commit]);\n const patch = join(snapshot, name);\n if ((await lstat(patch)).size) {\n const args = [\n \"apply\",\n \"--binary\",\n ...(cached ? [\"--cached\"] : []),\n patch,\n ];\n await git(checkout, [...args.slice(0, -1), \"--check\", patch]);\n await git(checkout, args);\n }\n checks.push({\n path: join(root, name),\n status: \"pass\",\n code: \"PATCH_APPLIES\",\n });\n }\n } catch {\n checks.push({\n path: root,\n status: \"fail\",\n code: stage === \"SOURCE_UNSUPPORTED\" ? stage : `${stage}_FAILED`,\n });\n } finally {\n await rm(temporary, { recursive: true, force: true, maxRetries: 3 });\n }\n return checks;\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { invariant } from "../domain/errors.js";
|
|
2
|
+
export function retentionPolicy(value) {
|
|
3
|
+
invariant(!!value && typeof value === "object", "Retention policy must be an object");
|
|
4
|
+
invariant("version" in value && value.version === 1, "Retention policy version must be 1");
|
|
5
|
+
invariant("scopes" in value &&
|
|
6
|
+
Array.isArray(value.scopes) &&
|
|
7
|
+
value.scopes.length > 0 &&
|
|
8
|
+
value.scopes.every((scope) => scope === "clean-workspaces" || scope === "closed-logs"), "Retention scopes must contain clean-workspaces or closed-logs");
|
|
9
|
+
invariant("minAgeMs" in value &&
|
|
10
|
+
typeof value.minAgeMs === "number" &&
|
|
11
|
+
Number.isSafeInteger(value.minAgeMs) &&
|
|
12
|
+
value.minAgeMs >= 0, "minAgeMs must be a nonnegative integer");
|
|
13
|
+
for (const key of ["maxBytes", "maxWorkspaces"]) {
|
|
14
|
+
if (!(key in value))
|
|
15
|
+
continue;
|
|
16
|
+
const limit = Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
17
|
+
invariant(typeof limit === "number" && Number.isSafeInteger(limit) && limit >= 0, `${key} must be a nonnegative integer`);
|
|
18
|
+
}
|
|
19
|
+
invariant(Object.keys(value).every((key) => ["version", "scopes", "minAgeMs", "maxBytes", "maxWorkspaces"].includes(key)), "Unsupported retention policy field");
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=recovery-retention-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-retention-policy.js","sourceRoot":"","sources":["../../src/application/recovery-retention-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,MAAM,UAAU,eAAe,CAC7B,KAAc;IAEd,SAAS,CACP,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EACpC,oCAAoC,CACrC,CAAC;IACF,SAAS,CACP,SAAS,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,EACzC,oCAAoC,CACrC,CAAC;IACF,SAAS,CACP,QAAQ,IAAI,KAAK;QACf,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;QAC3B,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QACvB,KAAK,CAAC,MAAM,CAAC,KAAK,CAChB,CAAC,KAAc,EAAE,EAAE,CACjB,KAAK,KAAK,kBAAkB,IAAI,KAAK,KAAK,aAAa,CAC1D,EACH,+DAA+D,CAChE,CAAC;IACF,SAAS,CACP,UAAU,IAAI,KAAK;QACjB,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;QAClC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC;QACpC,KAAK,CAAC,QAAQ,IAAI,CAAC,EACrB,wCAAwC,CACzC,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,eAAe,CAAU,EAAE,CAAC;QACzD,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC;YAAE,SAAS;QAC9B,MAAM,KAAK,GAAY,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC;QAC1E,SAAS,CACP,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EACtE,GAAG,GAAG,gCAAgC,CACvC,CAAC;IACJ,CAAC;IACD,SAAS,CACP,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAC/B,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC,QAAQ,CACrE,GAAG,CACJ,CACF,EACD,oCAAoC,CACrC,CAAC;AACJ,CAAC","sourcesContent":["import { invariant } from \"../domain/errors.ts\";\nimport type { RecoveryRetentionPolicy } from \"./recovery-retention.types.ts\";\n\nexport function retentionPolicy(\n value: unknown,\n): asserts value is RecoveryRetentionPolicy {\n invariant(\n !!value && typeof value === \"object\",\n \"Retention policy must be an object\",\n );\n invariant(\n \"version\" in value && value.version === 1,\n \"Retention policy version must be 1\",\n );\n invariant(\n \"scopes\" in value &&\n Array.isArray(value.scopes) &&\n value.scopes.length > 0 &&\n value.scopes.every(\n (scope: unknown) =>\n scope === \"clean-workspaces\" || scope === \"closed-logs\",\n ),\n \"Retention scopes must contain clean-workspaces or closed-logs\",\n );\n invariant(\n \"minAgeMs\" in value &&\n typeof value.minAgeMs === \"number\" &&\n Number.isSafeInteger(value.minAgeMs) &&\n value.minAgeMs >= 0,\n \"minAgeMs must be a nonnegative integer\",\n );\n for (const key of [\"maxBytes\", \"maxWorkspaces\"] as const) {\n if (!(key in value)) continue;\n const limit: unknown = Object.getOwnPropertyDescriptor(value, key)?.value;\n invariant(\n typeof limit === \"number\" && Number.isSafeInteger(limit) && limit >= 0,\n `${key} must be a nonnegative integer`,\n );\n }\n invariant(\n Object.keys(value).every((key) =>\n [\"version\", \"scopes\", \"minAgeMs\", \"maxBytes\", \"maxWorkspaces\"].includes(\n key,\n ),\n ),\n \"Unsupported retention policy field\",\n );\n}\n"]}
|