@elie-laloum/outpost 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +9 -5
- package/SECURITY.md +2 -0
- package/dist/adapters/models/openai-compatible.constants.d.ts +4 -0
- package/dist/adapters/models/openai-compatible.constants.js +10 -0
- package/dist/adapters/models/openai-compatible.constants.js.map +1 -0
- package/dist/adapters/models/openai-compatible.d.ts +3 -0
- package/dist/adapters/models/openai-compatible.js +78 -0
- package/dist/adapters/models/openai-compatible.js.map +1 -0
- package/dist/adapters/models/openai-compatible.types.d.ts +14 -0
- package/dist/adapters/models/openai-compatible.types.js +2 -0
- package/dist/adapters/models/openai-compatible.types.js.map +1 -0
- package/dist/adapters/models/openai-http.d.ts +1 -0
- package/dist/adapters/models/openai-http.js +30 -0
- package/dist/adapters/models/openai-http.js.map +1 -0
- package/dist/adapters/models/openai-request.d.ts +4 -0
- package/dist/adapters/models/openai-request.js +46 -0
- package/dist/adapters/models/openai-request.js.map +1 -0
- package/dist/adapters/models/openai-response.d.ts +3 -0
- package/dist/adapters/models/openai-response.js +65 -0
- package/dist/adapters/models/openai-response.js.map +1 -0
- package/dist/application/execution.types.d.ts +2 -0
- package/dist/application/execution.types.js.map +1 -1
- package/dist/application/outpost.types.d.ts +5 -0
- package/dist/application/outpost.types.js.map +1 -1
- package/dist/application/recovery-archive.d.ts +4 -0
- package/dist/application/recovery-archive.js +29 -0
- package/dist/application/recovery-archive.js.map +1 -0
- package/dist/application/recovery-archive.types.d.ts +10 -0
- package/dist/application/recovery-archive.types.js +2 -0
- package/dist/application/recovery-archive.types.js.map +1 -0
- package/dist/application/recovery-inspection.js +3 -0
- package/dist/application/recovery-inspection.js.map +1 -1
- package/dist/application/recovery-inspection.types.d.ts +2 -0
- package/dist/application/recovery-inspection.types.js.map +1 -1
- package/dist/application/recovery-retention.d.ts +2 -1
- package/dist/application/recovery-retention.js +9 -1
- package/dist/application/recovery-retention.js.map +1 -1
- package/dist/application/recovery-retention.types.d.ts +6 -0
- package/dist/application/recovery-retention.types.js.map +1 -1
- package/dist/application/remote-backup.js +8 -0
- package/dist/application/remote-backup.js.map +1 -1
- package/dist/application/remote-workspace.types.d.ts +2 -0
- package/dist/application/remote-workspace.types.js.map +1 -1
- package/dist/application/sandbox-agents.js +2 -1
- package/dist/application/sandbox-agents.js.map +1 -1
- package/dist/application/sandbox-dispatch.js +9 -0
- package/dist/application/sandbox-dispatch.js.map +1 -1
- package/dist/application/sandbox-provision.js +6 -0
- package/dist/application/sandbox-provision.js.map +1 -1
- package/dist/application/storage-reservation.js +3 -0
- package/dist/application/storage-reservation.js.map +1 -1
- package/dist/application/transport-inspection.constants.d.ts +2 -0
- package/dist/application/transport-inspection.constants.js +10 -0
- package/dist/application/transport-inspection.constants.js.map +1 -0
- package/dist/application/transport-inspection.d.ts +2 -0
- package/dist/application/transport-inspection.js +103 -0
- package/dist/application/transport-inspection.js.map +1 -0
- package/dist/application/transport-retention.d.ts +4 -0
- package/dist/application/transport-retention.js +153 -0
- package/dist/application/transport-retention.js.map +1 -0
- package/dist/domain/conversation.types.d.ts +2 -0
- package/dist/domain/conversation.types.js.map +1 -1
- package/dist/domain/model.types.d.ts +15 -0
- package/dist/domain/model.types.js +2 -0
- package/dist/domain/model.types.js.map +1 -0
- package/dist/domain/transport.constants.d.ts +2 -0
- package/dist/domain/transport.constants.js +3 -0
- package/dist/domain/transport.constants.js.map +1 -0
- package/dist/domain/transport.d.ts +6 -0
- package/dist/domain/transport.js +21 -0
- package/dist/domain/transport.js.map +1 -0
- package/dist/domain/transport.types.d.ts +31 -0
- package/dist/domain/transport.types.js +2 -0
- package/dist/domain/transport.types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/artifact-store.js +10 -0
- package/dist/infrastructure/artifact-store.js.map +1 -1
- package/dist/infrastructure/artifact-store.types.d.ts +3 -1
- package/dist/infrastructure/artifact-store.types.js.map +1 -1
- package/dist/infrastructure/conversations/capture.js +1 -1
- package/dist/infrastructure/conversations/capture.js.map +1 -1
- package/dist/infrastructure/conversations.d.ts +2 -0
- package/dist/infrastructure/conversations.js +2 -0
- package/dist/infrastructure/conversations.js.map +1 -1
- package/dist/infrastructure/inspection-file.js +3 -3
- package/dist/infrastructure/inspection-file.js.map +1 -1
- package/dist/infrastructure/inspection-hash.js +4 -3
- package/dist/infrastructure/inspection-hash.js.map +1 -1
- package/dist/infrastructure/inspection-path.d.ts +1 -0
- package/dist/infrastructure/inspection-path.js +18 -0
- package/dist/infrastructure/inspection-path.js.map +1 -0
- package/dist/infrastructure/journal.js +6 -0
- package/dist/infrastructure/journal.js.map +1 -1
- package/dist/infrastructure/journal.types.d.ts +3 -0
- package/dist/infrastructure/journal.types.js.map +1 -1
- package/dist/infrastructure/local-transport.d.ts +3 -0
- package/dist/infrastructure/local-transport.js +146 -0
- package/dist/infrastructure/local-transport.js.map +1 -0
- package/dist/infrastructure/local-transport.types.d.ts +3 -0
- package/dist/infrastructure/local-transport.types.js +2 -0
- package/dist/infrastructure/local-transport.types.js.map +1 -0
- package/dist/infrastructure/resource-activity-inspection.d.ts +2 -1
- package/dist/infrastructure/resource-activity-inspection.js +2 -2
- package/dist/infrastructure/resource-activity-inspection.js.map +1 -1
- package/dist/infrastructure/resource-activity.js +42 -14
- package/dist/infrastructure/resource-activity.js.map +1 -1
- package/dist/infrastructure/resource-activity.types.d.ts +2 -0
- package/dist/infrastructure/resource-activity.types.js.map +1 -1
- package/dist/infrastructure/s3-transport.d.ts +4 -0
- package/dist/infrastructure/s3-transport.js +144 -0
- package/dist/infrastructure/s3-transport.js.map +1 -0
- package/dist/infrastructure/s3-transport.types.d.ts +6 -0
- package/dist/infrastructure/s3-transport.types.js +2 -0
- package/dist/infrastructure/s3-transport.types.js.map +1 -0
- package/dist/infrastructure/storage-inventory.types.d.ts +2 -1
- package/dist/infrastructure/storage-inventory.types.js.map +1 -1
- package/dist/infrastructure/storage-reservations.types.d.ts +2 -0
- package/dist/infrastructure/storage-reservations.types.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq-resources.d.ts +13 -0
- package/dist/infrastructure/task-queue-bullmq-resources.js +118 -0
- package/dist/infrastructure/task-queue-bullmq-resources.js.map +1 -0
- package/dist/infrastructure/task-queue-bullmq-state.d.ts +5 -0
- package/dist/infrastructure/task-queue-bullmq-state.js +26 -0
- package/dist/infrastructure/task-queue-bullmq-state.js.map +1 -0
- package/dist/infrastructure/task-queue-bullmq.constants.d.ts +7 -0
- package/dist/infrastructure/task-queue-bullmq.constants.js +79 -0
- package/dist/infrastructure/task-queue-bullmq.constants.js.map +1 -0
- package/dist/infrastructure/task-queue-bullmq.d.ts +3 -0
- package/dist/infrastructure/task-queue-bullmq.js +124 -0
- package/dist/infrastructure/task-queue-bullmq.js.map +1 -0
- package/dist/infrastructure/task-queue-bullmq.types.d.ts +17 -0
- package/dist/infrastructure/task-queue-bullmq.types.js +2 -0
- package/dist/infrastructure/task-queue-bullmq.types.js.map +1 -0
- package/dist/infrastructure/transport-archive.constants.d.ts +6 -0
- package/dist/infrastructure/transport-archive.constants.js +7 -0
- package/dist/infrastructure/transport-archive.constants.js.map +1 -0
- package/dist/infrastructure/transport-archive.d.ts +5 -0
- package/dist/infrastructure/transport-archive.js +157 -0
- package/dist/infrastructure/transport-archive.js.map +1 -0
- package/dist/infrastructure/transport-archive.types.d.ts +17 -0
- package/dist/infrastructure/transport-archive.types.js +2 -0
- package/dist/infrastructure/transport-archive.types.js.map +1 -0
- package/dist/infrastructure/transport-artifact-store.d.ts +3 -0
- package/dist/infrastructure/transport-artifact-store.js +31 -0
- package/dist/infrastructure/transport-artifact-store.js.map +1 -0
- package/dist/infrastructure/transport-artifact-store.types.d.ts +4 -0
- package/dist/infrastructure/transport-artifact-store.types.js +2 -0
- package/dist/infrastructure/transport-artifact-store.types.js.map +1 -0
- package/dist/infrastructure/transport-checkpoint.d.ts +5 -0
- package/dist/infrastructure/transport-checkpoint.js +105 -0
- package/dist/infrastructure/transport-checkpoint.js.map +1 -0
- package/dist/infrastructure/transport-checkpoint.types.d.ts +9 -0
- package/dist/infrastructure/transport-checkpoint.types.js +2 -0
- package/dist/infrastructure/transport-checkpoint.types.js.map +1 -0
- package/dist/infrastructure/transport-conversations.d.ts +4 -0
- package/dist/infrastructure/transport-conversations.js +69 -0
- package/dist/infrastructure/transport-conversations.js.map +1 -0
- package/dist/infrastructure/transport-conversations.types.d.ts +4 -0
- package/dist/infrastructure/transport-conversations.types.js +2 -0
- package/dist/infrastructure/transport-conversations.types.js.map +1 -0
- package/dist/infrastructure/transport-envelope.d.ts +7 -0
- package/dist/infrastructure/transport-envelope.js +47 -0
- package/dist/infrastructure/transport-envelope.js.map +1 -0
- package/dist/infrastructure/transport-journal.d.ts +6 -0
- package/dist/infrastructure/transport-journal.js +93 -0
- package/dist/infrastructure/transport-journal.js.map +1 -0
- package/dist/infrastructure/transport-journal.types.d.ts +10 -0
- package/dist/infrastructure/transport-journal.types.js +2 -0
- package/dist/infrastructure/transport-journal.types.js.map +1 -0
- package/dist/infrastructure/transport-json.d.ts +6 -0
- package/dist/infrastructure/transport-json.js +46 -0
- package/dist/infrastructure/transport-json.js.map +1 -0
- package/dist/infrastructure/transport-reservations.d.ts +5 -0
- package/dist/infrastructure/transport-reservations.js +89 -0
- package/dist/infrastructure/transport-reservations.js.map +1 -0
- package/dist/infrastructure/transport-reservations.types.d.ts +4 -0
- package/dist/infrastructure/transport-reservations.types.js +2 -0
- package/dist/infrastructure/transport-reservations.types.js.map +1 -0
- package/dist/infrastructure/transport.constants.d.ts +8 -0
- package/dist/infrastructure/transport.constants.js +9 -0
- package/dist/infrastructure/transport.constants.js.map +1 -0
- package/dist/infrastructure/workflow-checkpoint.js +7 -0
- package/dist/infrastructure/workflow-checkpoint.js.map +1 -1
- package/dist/infrastructure/workflow-checkpoint.types.d.ts +3 -1
- package/dist/infrastructure/workflow-checkpoint.types.js.map +1 -1
- package/package.json +26 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.2.0
|
|
4
|
+
|
|
5
|
+
- Add experimental `openaiCompatible()` and typed model-provider contracts for direct, non-streaming Chat Completions or Responses calls without Codex. Bound requests and response sizes, support cancellation and optional reported usage, and reject incomplete or unsupported outputs. Tool execution and the agent harness remain planned for phase two; live service compatibility is unvalidated.
|
|
6
|
+
- Add a bilingual Model providers reference family with experimental icons and generated warning banners explaining the limitations. Add the same warning treatment to Firecracker and FirecrackerOptions.
|
|
7
|
+
- Add local/S3 object transports for artifacts, exclusively owned checkpoints, segmented journals, native conversation snapshots, verified recovery archives, shared storage reservations, resource activity and remote inventory/retention/quota operations. Preserve existing directory stores and local execution paths; AWS SDK loading remains optional. Remote ownership recovery is explicit and authenticated live storage campaigns remain outstanding.
|
|
8
|
+
- Add the optional `@elie-laloum/outpost/queues/bullmq` adapter for standalone Redis and BullMQ 5, preserving queue identity, lossless JSON results, fenced leases, cancellation and deadlines. Include asynchronous connection cleanup, real Redis integration tests and bilingual reference and operational guidance.
|
|
9
|
+
|
|
10
|
+
- Rebuild the bilingual documentation with separate Guide and Reference navigation, family overviews, contextual API descriptions, preserved symbol URLs and redirects for moved guides. Add complete runnable preparations and a schema-validation guide covering Zod, Valibot and JSON Schema.
|
|
11
|
+
- Group reference families under five fixed sections with short English labels in both locales, localized overview links with house icons, and keyboard-accessible desktop/mobile navigation. Group egress policies with sandbox providers.
|
|
12
|
+
- Avoid recreating filesystem roots when initializing local transports on Windows, and accept native short/case aliases during inspection without allowing symlink traversal. Preserve child transcripts when capturing Windows conversations, verify relocated paths as decoded JSON, and build the library before running documented Docker/Podman examples in CI.
|
|
13
|
+
|
|
3
14
|
## 4.1.0
|
|
4
15
|
|
|
5
16
|
- Replace global CLI parsing and manual help with Commander subcommands and command-specific options; use Clack selection prompts for interactive initialization. Previously ignored options belonging to other commands are now rejected. Headless and JSON output remain plain.
|
package/README.md
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
Outpost is a TypeScript library for running coding agents in reusable sandboxes, managing their Git workspaces and composing typed workflows. Claude Code, Codex and Gemini CLI adapters work with Docker, Podman, Vercel, Daytona or explicit host execution. Gemini supports fresh sessions only; native conversation capture, resume and fork are available for Claude Code and Codex.
|
|
6
6
|
|
|
7
|
-
Version 4.
|
|
7
|
+
Version 4.2.0 adds local/S3 storage transports, an optional BullMQ/Redis task queue and experimental direct text model calls. The bilingual documentation now separates practical guides from the API reference. Direct model calls do not yet execute tools or edit repositories. See the [changelog](CHANGELOG.md#420) for details and the [roadmap](https://elie-laloum.github.io/outpost/project/roadmap/) for remaining validation and upcoming priorities.
|
|
8
8
|
|
|
9
9
|
## Get started
|
|
10
10
|
|
|
11
|
+
New to Outpost? Follow the [complete first-run workshop](https://elie-laloum.github.io/outpost/guide/start/quickstart/): choose Codex or Claude and account or API-key access, create a disposable TypeScript repository, then fix and verify a real test. The [Guide](https://elie-laloum.github.io/outpost/guide/) teaches the concepts; the [Reference](https://elie-laloum.github.io/outpost/reference/) explains exact contracts. Every [cookbook recipe](https://elie-laloum.github.io/outpost/guide/cookbook/) includes its own preparation and runnable code.
|
|
12
|
+
|
|
11
13
|
Requires Node.js **24+**, Git, a target repository with a commit, and the credentials of your chosen agent. The workflow can live in its own directory. This example uses Docker.
|
|
12
14
|
|
|
13
15
|
```sh
|
|
@@ -22,12 +24,14 @@ Copy `.env.example` to `.env` and declare `OPENAI_API_KEY`. An empty declaration
|
|
|
22
24
|
node run.ts "Add validation, run tests and commit the change"
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
`init` creates `package.json`, `run.ts`, `brief.md`, `.env.example`, `.gitignore` and a container recipe directly in the workflow directory. Existing package manifests are preserved; explicit CommonJS projects get `run.mts` for compatibility. The script resolves its brief, environment and relative repository paths from its own directory. See [multi-repository workflows](https://elie-laloum.github.io/outpost/workflows/sandbox-tasks/) to orchestrate several repositories.
|
|
27
|
+
`init` creates `package.json`, `run.ts`, `brief.md`, `.env.example`, `.gitignore` and a container recipe directly in the workflow directory. Existing package manifests are preserved; explicit CommonJS projects get `run.mts` for compatibility. The script resolves its brief, environment and relative repository paths from its own directory. See [multi-repository workflows](https://elie-laloum.github.io/outpost/guide/workflows/sandbox-tasks/) to orchestrate several repositories.
|
|
26
28
|
|
|
27
|
-
Generated Codex API-key workflows prepare login inside the sandbox. For account login and credential storage, see [Connect Codex](https://elie-laloum.github.io/outpost/agents/connect-codex/) before dispatching.
|
|
29
|
+
Generated Codex API-key workflows prepare login inside the sandbox. For account login and credential storage, see [Connect Codex](https://elie-laloum.github.io/outpost/guide/agents/connect-codex/) before dispatching.
|
|
28
30
|
|
|
29
31
|
## Use the library
|
|
30
32
|
|
|
33
|
+
After preparing the selected agent credentials and provider, library calls follow this shape. For a fully runnable version with explicit authentication, use the [dispatch workshop](https://elie-laloum.github.io/outpost/guide/agents/dispatch/).
|
|
34
|
+
|
|
31
35
|
```ts
|
|
32
36
|
import { dispatch, codex } from "@elie-laloum/outpost";
|
|
33
37
|
|
|
@@ -40,9 +44,9 @@ const result = await dispatch({
|
|
|
40
44
|
console.log(result.branch, result.commits);
|
|
41
45
|
```
|
|
42
46
|
|
|
43
|
-
`repository` selects a local Git checkout; without it, library calls use the current working directory. See [repository paths](https://elie-laloum.github.io/outpost/
|
|
47
|
+
`repository` selects a local Git checkout; without it, library calls use the current working directory. See [repository paths](https://elie-laloum.github.io/outpost/guide/environment/repositories/) for external checkouts and paths relative to the workflow script.
|
|
44
48
|
|
|
45
|
-
Learn about [sandboxes](https://elie-laloum.github.io/outpost/
|
|
49
|
+
Learn about [sandboxes](https://elie-laloum.github.io/outpost/guide/environment/lifecycle/), [workflows](https://elie-laloum.github.io/outpost/guide/workflows/graph/), [providers](https://elie-laloum.github.io/outpost/guide/environment/providers/overview/) and [recovery](https://elie-laloum.github.io/outpost/guide/operations/recovery/) in the English/French documentation. The [roadmap](https://elie-laloum.github.io/outpost/project/roadmap/) describes future work.
|
|
46
50
|
|
|
47
51
|
## Development
|
|
48
52
|
|
package/SECURITY.md
CHANGED
|
@@ -15,3 +15,5 @@ Prompt command expansion only recognizes commands present in the original prompt
|
|
|
15
15
|
Conversation transcripts, logs, bundles and patches may contain secrets. Runtime files are ignored by Git and sensitive files are created with restrictive permissions where supported. Keep API keys in environment variables or ignored `.env` files. Never embed tokens in tracked configuration, remote URLs or examples.
|
|
16
16
|
|
|
17
17
|
Report vulnerabilities privately using the repository's security reporting channel when enabled, or contact the maintainer through the hosting profile. Do not include live credentials in reports. V1 receives fixes for reproducible security defects.
|
|
18
|
+
|
|
19
|
+
Explicit storage transports can send artifacts, journals, transcripts, recovery payloads and operational metadata to the configured object store. The caller owns the S3 client and credentials; they are not forwarded to agents. Use a dedicated private bucket prefix and access policy. Object revisions fence cooperating writers but do not authenticate artifact producers or operators. Stop an abandoned runner independently before releasing its checkpoint ownership; a remote PID is not proof of inactivity.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const MODEL_TIMEOUT_MS = 120_000;
|
|
2
|
+
export const MODEL_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
3
|
+
export const MODEL_MAX_TIMEOUT_MS = 2_147_483_647;
|
|
4
|
+
export const MODEL_REQUEST_FIELDS = new Set([
|
|
5
|
+
"prompt",
|
|
6
|
+
"system",
|
|
7
|
+
"maxOutputTokens",
|
|
8
|
+
"signal",
|
|
9
|
+
]);
|
|
10
|
+
//# sourceMappingURL=openai-compatible.constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible.constants.js","sourceRoot":"","sources":["../../../src/adapters/models/openai-compatible.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACxC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACpD,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAAC;AAClD,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IAC1C,QAAQ;IACR,QAAQ;IACR,iBAAiB;IACjB,QAAQ;CACT,CAAC,CAAC","sourcesContent":["export const MODEL_TIMEOUT_MS = 120_000;\nexport const MODEL_RESPONSE_BYTES = 8 * 1024 * 1024;\nexport const MODEL_MAX_TIMEOUT_MS = 2_147_483_647;\nexport const MODEL_REQUEST_FIELDS = new Set([\n \"prompt\",\n \"system\",\n \"maxOutputTokens\",\n \"signal\",\n]);\n"]}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { invariant, OutpostError, positive } from "../../domain/errors.js";
|
|
2
|
+
import { MODEL_MAX_TIMEOUT_MS, MODEL_RESPONSE_BYTES, MODEL_TIMEOUT_MS, } from "./openai-compatible.constants.js";
|
|
3
|
+
import { modelProtocols, validateModelRequest } from "./openai-request.js";
|
|
4
|
+
import { modelJson } from "./openai-http.js";
|
|
5
|
+
export function openaiCompatible(options) {
|
|
6
|
+
let base;
|
|
7
|
+
try {
|
|
8
|
+
base = new URL(options.baseUrl);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
throw new OutpostError("configuration", "Model baseUrl must be an absolute HTTP(S) URL");
|
|
12
|
+
}
|
|
13
|
+
invariant(["http:", "https:"].includes(base.protocol) &&
|
|
14
|
+
!base.username &&
|
|
15
|
+
!base.password &&
|
|
16
|
+
!base.search &&
|
|
17
|
+
!base.hash, "Model baseUrl must use HTTP(S) without credentials, query or fragment");
|
|
18
|
+
invariant(typeof options.model === "string" && options.model.trim(), "Model name must be nonempty text");
|
|
19
|
+
invariant(options.apiKey === false ||
|
|
20
|
+
(typeof options.apiKey === "string" &&
|
|
21
|
+
options.apiKey.trim() &&
|
|
22
|
+
!/[\r\n]/.test(options.apiKey)), "Model apiKey must be a nonempty key or false for unauthenticated endpoints");
|
|
23
|
+
const api = options.api ?? "chat-completions";
|
|
24
|
+
invariant(Object.hasOwn(modelProtocols, api), "Unsupported model API protocol");
|
|
25
|
+
const protocol = modelProtocols[api];
|
|
26
|
+
const endpoint = `${base.href.replace(/\/+$/, "")}/${protocol.path}`;
|
|
27
|
+
const timeoutMs = positive(options.timeoutMs ?? MODEL_TIMEOUT_MS, "Model timeoutMs");
|
|
28
|
+
invariant(timeoutMs <= MODEL_MAX_TIMEOUT_MS, "Model timeoutMs exceeds the supported timer range");
|
|
29
|
+
const maxBytes = positive(options.maxResponseBytes ?? MODEL_RESPONSE_BYTES, "Model maxResponseBytes");
|
|
30
|
+
const model = options.model;
|
|
31
|
+
const apiKey = options.apiKey;
|
|
32
|
+
return Object.freeze({
|
|
33
|
+
name: "openai-compatible",
|
|
34
|
+
async generate(request) {
|
|
35
|
+
validateModelRequest(request);
|
|
36
|
+
const deadline = new AbortController();
|
|
37
|
+
const signal = request.signal
|
|
38
|
+
? AbortSignal.any([request.signal, deadline.signal])
|
|
39
|
+
: deadline.signal;
|
|
40
|
+
const timer = setTimeout(() => deadline.abort(), timeoutMs);
|
|
41
|
+
try {
|
|
42
|
+
signal.throwIfAborted();
|
|
43
|
+
const response = await fetch(endpoint, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
redirect: "error",
|
|
46
|
+
headers: {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
...(apiKey === false ? {} : { Authorization: `Bearer ${apiKey}` }),
|
|
49
|
+
},
|
|
50
|
+
body: JSON.stringify(protocol.build(model, request)),
|
|
51
|
+
signal,
|
|
52
|
+
});
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
await response.body?.cancel();
|
|
55
|
+
throw new OutpostError("provider", `Model request failed with HTTP ${response.status}`, { status: response.status });
|
|
56
|
+
}
|
|
57
|
+
const value = await modelJson(response, maxBytes);
|
|
58
|
+
signal.throwIfAborted();
|
|
59
|
+
return protocol.read(value);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (signal.aborted) {
|
|
63
|
+
const timedOut = deadline.signal.aborted && !request.signal?.aborted;
|
|
64
|
+
throw new OutpostError(timedOut ? "timeout" : "aborted", timedOut
|
|
65
|
+
? "Model request timed out"
|
|
66
|
+
: "Model request was cancelled");
|
|
67
|
+
}
|
|
68
|
+
if (error instanceof OutpostError)
|
|
69
|
+
throw error;
|
|
70
|
+
throw new OutpostError("provider", "Model request failed during HTTP transport");
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
clearTimeout(timer);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=openai-compatible.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible.js","sourceRoot":"","sources":["../../../src/adapters/models/openai-compatible.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,UAAU,gBAAgB,CAC9B,OAAgC;IAEhC,IAAI,IAAS,CAAC;IACd,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,+CAA+C,CAChD,CAAC;IACJ,CAAC;IACD,SAAS,CACP,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;QACzC,CAAC,IAAI,CAAC,QAAQ;QACd,CAAC,IAAI,CAAC,QAAQ;QACd,CAAC,IAAI,CAAC,MAAM;QACZ,CAAC,IAAI,CAAC,IAAI,EACZ,uEAAuE,CACxE,CAAC;IACF,SAAS,CACP,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EACzD,kCAAkC,CACnC,CAAC;IACF,SAAS,CACP,OAAO,CAAC,MAAM,KAAK,KAAK;QACtB,CAAC,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ;YACjC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE;YACrB,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EACnC,4EAA4E,CAC7E,CAAC;IACF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,kBAAkB,CAAC;IAC9C,SAAS,CACP,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,EAClC,gCAAgC,CACjC,CAAC;IACF,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAE,CAAC;IACtC,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;IACrE,MAAM,SAAS,GAAG,QAAQ,CACxB,OAAO,CAAC,SAAS,IAAI,gBAAgB,EACrC,iBAAiB,CAClB,CAAC;IACF,SAAS,CACP,SAAS,IAAI,oBAAoB,EACjC,mDAAmD,CACpD,CAAC;IACF,MAAM,QAAQ,GAAG,QAAQ,CACvB,OAAO,CAAC,gBAAgB,IAAI,oBAAoB,EAChD,wBAAwB,CACzB,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,mBAAmB;QACzB,KAAK,CAAC,QAAQ,CAAC,OAAqB;YAClC,oBAAoB,CAAC,OAAO,CAAC,CAAC;YAC9B,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;YACvC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;gBAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACpD,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YACpB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;YAC5D,IAAI,CAAC;gBACH,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;oBACrC,MAAM,EAAE,MAAM;oBACd,QAAQ,EAAE,OAAO;oBACjB,OAAO,EAAE;wBACP,cAAc,EAAE,kBAAkB;wBAClC,GAAG,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,CAAC;qBACnE;oBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;oBACpD,MAAM;iBACP,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBACjB,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;oBAC9B,MAAM,IAAI,YAAY,CACpB,UAAU,EACV,kCAAkC,QAAQ,CAAC,MAAM,EAAE,EACnD,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAC5B,CAAC;gBACJ,CAAC;gBACD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBAClD,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBACnB,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;oBACrE,MAAM,IAAI,YAAY,CACpB,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAChC,QAAQ;wBACN,CAAC,CAAC,yBAAyB;wBAC3B,CAAC,CAAC,6BAA6B,CAClC,CAAC;gBACJ,CAAC;gBACD,IAAI,KAAK,YAAY,YAAY;oBAAE,MAAM,KAAK,CAAC;gBAC/C,MAAM,IAAI,YAAY,CACpB,UAAU,EACV,4CAA4C,CAC7C,CAAC;YACJ,CAAC;oBAAS,CAAC;gBACT,YAAY,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { invariant, OutpostError, positive } from \"../../domain/errors.ts\";\nimport type { ModelProvider, ModelRequest } from \"../../domain/model.types.ts\";\nimport type { OpenAICompatibleOptions } from \"./openai-compatible.types.ts\";\nimport {\n MODEL_MAX_TIMEOUT_MS,\n MODEL_RESPONSE_BYTES,\n MODEL_TIMEOUT_MS,\n} from \"./openai-compatible.constants.ts\";\nimport { modelProtocols, validateModelRequest } from \"./openai-request.ts\";\nimport { modelJson } from \"./openai-http.ts\";\n\nexport function openaiCompatible(\n options: OpenAICompatibleOptions,\n): ModelProvider {\n let base: URL;\n try {\n base = new URL(options.baseUrl);\n } catch {\n throw new OutpostError(\n \"configuration\",\n \"Model baseUrl must be an absolute HTTP(S) URL\",\n );\n }\n invariant(\n [\"http:\", \"https:\"].includes(base.protocol) &&\n !base.username &&\n !base.password &&\n !base.search &&\n !base.hash,\n \"Model baseUrl must use HTTP(S) without credentials, query or fragment\",\n );\n invariant(\n typeof options.model === \"string\" && options.model.trim(),\n \"Model name must be nonempty text\",\n );\n invariant(\n options.apiKey === false ||\n (typeof options.apiKey === \"string\" &&\n options.apiKey.trim() &&\n !/[\\r\\n]/.test(options.apiKey)),\n \"Model apiKey must be a nonempty key or false for unauthenticated endpoints\",\n );\n const api = options.api ?? \"chat-completions\";\n invariant(\n Object.hasOwn(modelProtocols, api),\n \"Unsupported model API protocol\",\n );\n const protocol = modelProtocols[api]!;\n const endpoint = `${base.href.replace(/\\/+$/, \"\")}/${protocol.path}`;\n const timeoutMs = positive(\n options.timeoutMs ?? MODEL_TIMEOUT_MS,\n \"Model timeoutMs\",\n );\n invariant(\n timeoutMs <= MODEL_MAX_TIMEOUT_MS,\n \"Model timeoutMs exceeds the supported timer range\",\n );\n const maxBytes = positive(\n options.maxResponseBytes ?? MODEL_RESPONSE_BYTES,\n \"Model maxResponseBytes\",\n );\n const model = options.model;\n const apiKey = options.apiKey;\n return Object.freeze({\n name: \"openai-compatible\",\n async generate(request: ModelRequest) {\n validateModelRequest(request);\n const deadline = new AbortController();\n const signal = request.signal\n ? AbortSignal.any([request.signal, deadline.signal])\n : deadline.signal;\n const timer = setTimeout(() => deadline.abort(), timeoutMs);\n try {\n signal.throwIfAborted();\n const response = await fetch(endpoint, {\n method: \"POST\",\n redirect: \"error\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(apiKey === false ? {} : { Authorization: `Bearer ${apiKey}` }),\n },\n body: JSON.stringify(protocol.build(model, request)),\n signal,\n });\n if (!response.ok) {\n await response.body?.cancel();\n throw new OutpostError(\n \"provider\",\n `Model request failed with HTTP ${response.status}`,\n { status: response.status },\n );\n }\n const value = await modelJson(response, maxBytes);\n signal.throwIfAborted();\n return protocol.read(value);\n } catch (error) {\n if (signal.aborted) {\n const timedOut = deadline.signal.aborted && !request.signal?.aborted;\n throw new OutpostError(\n timedOut ? \"timeout\" : \"aborted\",\n timedOut\n ? \"Model request timed out\"\n : \"Model request was cancelled\",\n );\n }\n if (error instanceof OutpostError) throw error;\n throw new OutpostError(\n \"provider\",\n \"Model request failed during HTTP transport\",\n );\n } finally {\n clearTimeout(timer);\n }\n },\n });\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ModelRequest, ModelResult } from "../../domain/model.types.ts";
|
|
2
|
+
export interface OpenAICompatibleOptions {
|
|
3
|
+
readonly baseUrl: string;
|
|
4
|
+
readonly model: string;
|
|
5
|
+
readonly apiKey: string | false;
|
|
6
|
+
readonly api?: "chat-completions" | "responses";
|
|
7
|
+
readonly timeoutMs?: number;
|
|
8
|
+
readonly maxResponseBytes?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ModelProtocol {
|
|
11
|
+
readonly path: string;
|
|
12
|
+
build(model: string, request: ModelRequest): Record<string, unknown>;
|
|
13
|
+
read(value: unknown): ModelResult;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible.types.js","sourceRoot":"","sources":["../../../src/adapters/models/openai-compatible.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ModelRequest, ModelResult } from \"../../domain/model.types.ts\";\n\nexport interface OpenAICompatibleOptions {\n readonly baseUrl: string;\n readonly model: string;\n readonly apiKey: string | false;\n readonly api?: \"chat-completions\" | \"responses\";\n readonly timeoutMs?: number;\n readonly maxResponseBytes?: number;\n}\n\nexport interface ModelProtocol {\n readonly path: string;\n build(model: string, request: ModelRequest): Record<string, unknown>;\n read(value: unknown): ModelResult;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function modelJson(response: Response, maxBytes: number): Promise<unknown>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { OutpostError } from "../../domain/errors.js";
|
|
2
|
+
export async function modelJson(response, maxBytes) {
|
|
3
|
+
const reader = response.body?.getReader();
|
|
4
|
+
if (!reader)
|
|
5
|
+
throw new OutpostError("response", "Model response has no body");
|
|
6
|
+
const chunks = [];
|
|
7
|
+
let size = 0;
|
|
8
|
+
try {
|
|
9
|
+
for (;;) {
|
|
10
|
+
const { done, value } = await reader.read();
|
|
11
|
+
if (done)
|
|
12
|
+
break;
|
|
13
|
+
size += value.byteLength;
|
|
14
|
+
if (size > maxBytes)
|
|
15
|
+
throw new OutpostError("response", "Model response exceeds maxResponseBytes");
|
|
16
|
+
chunks.push(value);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
await reader.cancel().catch(() => undefined);
|
|
21
|
+
reader.releaseLock();
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new OutpostError("response", "Model response is not valid JSON");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=openai-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-http.js","sourceRoot":"","sources":["../../../src/adapters/models/openai-http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAkB,EAClB,QAAgB;IAEhB,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;IAC1C,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,YAAY,CAAC,UAAU,EAAE,4BAA4B,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC;YACzB,IAAI,IAAI,GAAG,QAAQ;gBACjB,MAAM,IAAI,YAAY,CACpB,UAAU,EACV,yCAAyC,CAC1C,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,YAAY,CAAC,UAAU,EAAE,kCAAkC,CAAC,CAAC;IACzE,CAAC;AACH,CAAC","sourcesContent":["import { OutpostError } from \"../../domain/errors.ts\";\n\nexport async function modelJson(\n response: Response,\n maxBytes: number,\n): Promise<unknown> {\n const reader = response.body?.getReader();\n if (!reader) throw new OutpostError(\"response\", \"Model response has no body\");\n const chunks: Uint8Array[] = [];\n let size = 0;\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > maxBytes)\n throw new OutpostError(\n \"response\",\n \"Model response exceeds maxResponseBytes\",\n );\n chunks.push(value);\n }\n } finally {\n await reader.cancel().catch(() => undefined);\n reader.releaseLock();\n }\n try {\n return JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n } catch {\n throw new OutpostError(\"response\", \"Model response is not valid JSON\");\n }\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ModelRequest } from "../../domain/model.types.ts";
|
|
2
|
+
import type { ModelProtocol } from "./openai-compatible.types.ts";
|
|
3
|
+
export declare function validateModelRequest(request: ModelRequest): void;
|
|
4
|
+
export declare const modelProtocols: Readonly<Record<string, ModelProtocol>>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { invariant, positive } from "../../domain/errors.js";
|
|
2
|
+
import { MODEL_REQUEST_FIELDS } from "./openai-compatible.constants.js";
|
|
3
|
+
import { readChatCompletion, readModelResponse } from "./openai-response.js";
|
|
4
|
+
export function validateModelRequest(request) {
|
|
5
|
+
invariant(request !== null && typeof request === "object", "Model request must be an object");
|
|
6
|
+
invariant(Object.keys(request).every((key) => MODEL_REQUEST_FIELDS.has(key)), "Unsupported model request field; tools, streaming and conversations are not implemented");
|
|
7
|
+
invariant(typeof request.prompt === "string" && request.prompt.trim(), "Model prompt must be nonempty text");
|
|
8
|
+
invariant(request.system === undefined || typeof request.system === "string", "Model system instructions must be text");
|
|
9
|
+
if (request.maxOutputTokens !== undefined)
|
|
10
|
+
positive(request.maxOutputTokens, "Model maxOutputTokens");
|
|
11
|
+
}
|
|
12
|
+
export const modelProtocols = {
|
|
13
|
+
"chat-completions": {
|
|
14
|
+
path: "chat/completions",
|
|
15
|
+
build: (model, request) => ({
|
|
16
|
+
model,
|
|
17
|
+
messages: [
|
|
18
|
+
...(request.system === undefined
|
|
19
|
+
? []
|
|
20
|
+
: [{ role: "system", content: request.system }]),
|
|
21
|
+
{ role: "user", content: request.prompt },
|
|
22
|
+
],
|
|
23
|
+
stream: false,
|
|
24
|
+
store: false,
|
|
25
|
+
...(request.maxOutputTokens === undefined
|
|
26
|
+
? {}
|
|
27
|
+
: { max_completion_tokens: request.maxOutputTokens }),
|
|
28
|
+
}),
|
|
29
|
+
read: readChatCompletion,
|
|
30
|
+
},
|
|
31
|
+
responses: {
|
|
32
|
+
path: "responses",
|
|
33
|
+
build: (model, request) => ({
|
|
34
|
+
model,
|
|
35
|
+
input: request.prompt,
|
|
36
|
+
...(request.system === undefined ? {} : { instructions: request.system }),
|
|
37
|
+
stream: false,
|
|
38
|
+
store: false,
|
|
39
|
+
...(request.maxOutputTokens === undefined
|
|
40
|
+
? {}
|
|
41
|
+
: { max_output_tokens: request.maxOutputTokens }),
|
|
42
|
+
}),
|
|
43
|
+
read: readModelResponse,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=openai-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-request.js","sourceRoot":"","sources":["../../../src/adapters/models/openai-request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAG7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,MAAM,UAAU,oBAAoB,CAAC,OAAqB;IACxD,SAAS,CACP,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAC/C,iCAAiC,CAClC,CAAC;IACF,SAAS,CACP,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAClE,yFAAyF,CAC1F,CAAC;IACF,SAAS,CACP,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAC3D,oCAAoC,CACrC,CAAC;IACF,SAAS,CACP,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAClE,wCAAwC,CACzC,CAAC;IACF,IAAI,OAAO,CAAC,eAAe,KAAK,SAAS;QACvC,QAAQ,CAAC,OAAO,CAAC,eAAe,EAAE,uBAAuB,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAA4C;IACrE,kBAAkB,EAAE;QAClB,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YAC1B,KAAK;YACL,QAAQ,EAAE;gBACR,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS;oBAC9B,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;gBAClD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE;aAC1C;YACD,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,KAAK;YACZ,GAAG,CAAC,OAAO,CAAC,eAAe,KAAK,SAAS;gBACvC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,qBAAqB,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC;SACxD,CAAC;QACF,IAAI,EAAE,kBAAkB;KACzB;IACD,SAAS,EAAE;QACT,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YAC1B,KAAK;YACL,KAAK,EAAE,OAAO,CAAC,MAAM;YACrB,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YACzE,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,KAAK;YACZ,GAAG,CAAC,OAAO,CAAC,eAAe,KAAK,SAAS;gBACvC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,iBAAiB,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC;SACpD,CAAC;QACF,IAAI,EAAE,iBAAiB;KACxB;CACF,CAAC","sourcesContent":["import { invariant, positive } from \"../../domain/errors.ts\";\nimport type { ModelRequest } from \"../../domain/model.types.ts\";\nimport type { ModelProtocol } from \"./openai-compatible.types.ts\";\nimport { MODEL_REQUEST_FIELDS } from \"./openai-compatible.constants.ts\";\nimport { readChatCompletion, readModelResponse } from \"./openai-response.ts\";\n\nexport function validateModelRequest(request: ModelRequest): void {\n invariant(\n request !== null && typeof request === \"object\",\n \"Model request must be an object\",\n );\n invariant(\n Object.keys(request).every((key) => MODEL_REQUEST_FIELDS.has(key)),\n \"Unsupported model request field; tools, streaming and conversations are not implemented\",\n );\n invariant(\n typeof request.prompt === \"string\" && request.prompt.trim(),\n \"Model prompt must be nonempty text\",\n );\n invariant(\n request.system === undefined || typeof request.system === \"string\",\n \"Model system instructions must be text\",\n );\n if (request.maxOutputTokens !== undefined)\n positive(request.maxOutputTokens, \"Model maxOutputTokens\");\n}\n\nexport const modelProtocols: Readonly<Record<string, ModelProtocol>> = {\n \"chat-completions\": {\n path: \"chat/completions\",\n build: (model, request) => ({\n model,\n messages: [\n ...(request.system === undefined\n ? []\n : [{ role: \"system\", content: request.system }]),\n { role: \"user\", content: request.prompt },\n ],\n stream: false,\n store: false,\n ...(request.maxOutputTokens === undefined\n ? {}\n : { max_completion_tokens: request.maxOutputTokens }),\n }),\n read: readChatCompletion,\n },\n responses: {\n path: \"responses\",\n build: (model, request) => ({\n model,\n input: request.prompt,\n ...(request.system === undefined ? {} : { instructions: request.system }),\n stream: false,\n store: false,\n ...(request.maxOutputTokens === undefined\n ? {}\n : { max_output_tokens: request.maxOutputTokens }),\n }),\n read: readModelResponse,\n },\n};\n"]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { OutpostError } from "../../domain/errors.js";
|
|
2
|
+
function requireResponse(condition) {
|
|
3
|
+
if (!condition)
|
|
4
|
+
throw new OutpostError("response", "Invalid or unsupported model response");
|
|
5
|
+
}
|
|
6
|
+
function object(value) {
|
|
7
|
+
requireResponse(value !== null && typeof value === "object" && !Array.isArray(value));
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
function tokens(value) {
|
|
11
|
+
requireResponse(typeof value === "number" && Number.isSafeInteger(value) && value >= 0);
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
function usage(value, input, output, details) {
|
|
15
|
+
if (value === undefined || value === null)
|
|
16
|
+
return undefined;
|
|
17
|
+
const data = object(value);
|
|
18
|
+
const cached = data[details] == null
|
|
19
|
+
? 0
|
|
20
|
+
: tokens(object(data[details]).cached_tokens ?? 0);
|
|
21
|
+
const result = {
|
|
22
|
+
input: tokens(data[input]),
|
|
23
|
+
output: tokens(data[output]),
|
|
24
|
+
cached,
|
|
25
|
+
};
|
|
26
|
+
requireResponse(cached <= result.input);
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
export function readChatCompletion(value) {
|
|
30
|
+
const data = object(value);
|
|
31
|
+
requireResponse(Array.isArray(data.choices) && data.choices.length === 1);
|
|
32
|
+
const choice = object(data.choices[0]);
|
|
33
|
+
requireResponse(choice.finish_reason === "stop");
|
|
34
|
+
const message = object(choice.message);
|
|
35
|
+
requireResponse(message.role === "assistant" && typeof message.content === "string");
|
|
36
|
+
requireResponse(message.refusal == null && message.function_call == null);
|
|
37
|
+
requireResponse(message.tool_calls == null ||
|
|
38
|
+
(Array.isArray(message.tool_calls) && message.tool_calls.length === 0));
|
|
39
|
+
const reported = usage(data.usage, "prompt_tokens", "completion_tokens", "prompt_tokens_details");
|
|
40
|
+
return { text: message.content, ...(reported ? { usage: reported } : {}) };
|
|
41
|
+
}
|
|
42
|
+
export function readModelResponse(value) {
|
|
43
|
+
const data = object(value);
|
|
44
|
+
requireResponse(data.status === "completed" && data.error == null);
|
|
45
|
+
requireResponse(Array.isArray(data.output));
|
|
46
|
+
const texts = [];
|
|
47
|
+
for (const value of data.output) {
|
|
48
|
+
const item = object(value);
|
|
49
|
+
if (item.type === "reasoning")
|
|
50
|
+
continue;
|
|
51
|
+
requireResponse(item.type === "message" &&
|
|
52
|
+
item.role === "assistant" &&
|
|
53
|
+
item.status === "completed");
|
|
54
|
+
requireResponse(Array.isArray(item.content));
|
|
55
|
+
for (const value of item.content) {
|
|
56
|
+
const part = object(value);
|
|
57
|
+
requireResponse(part.type === "output_text" && typeof part.text === "string");
|
|
58
|
+
texts.push(part.text);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
requireResponse(texts.length > 0);
|
|
62
|
+
const reported = usage(data.usage, "input_tokens", "output_tokens", "input_tokens_details");
|
|
63
|
+
return { text: texts.join(""), ...(reported ? { usage: reported } : {}) };
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=openai-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-response.js","sourceRoot":"","sources":["../../../src/adapters/models/openai-response.ts"],"names":[],"mappings":"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","sourcesContent":["import { OutpostError } from \"../../domain/errors.ts\";\nimport type { ModelResult } from \"../../domain/model.types.ts\";\nimport type { Usage } from \"../../domain/agent.types.ts\";\n\nfunction requireResponse(condition: unknown): asserts condition {\n if (!condition)\n throw new OutpostError(\"response\", \"Invalid or unsupported model response\");\n}\n\nfunction object(value: unknown): Record<string, unknown> {\n requireResponse(\n value !== null && typeof value === \"object\" && !Array.isArray(value),\n );\n return value as Record<string, unknown>;\n}\n\nfunction tokens(value: unknown): number {\n requireResponse(\n typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0,\n );\n return value;\n}\n\nfunction usage(\n value: unknown,\n input: string,\n output: string,\n details: string,\n): Usage | undefined {\n if (value === undefined || value === null) return undefined;\n const data = object(value);\n const cached =\n data[details] == null\n ? 0\n : tokens(object(data[details]).cached_tokens ?? 0);\n const result = {\n input: tokens(data[input]),\n output: tokens(data[output]),\n cached,\n };\n requireResponse(cached <= result.input);\n return result;\n}\n\nexport function readChatCompletion(value: unknown): ModelResult {\n const data = object(value);\n requireResponse(Array.isArray(data.choices) && data.choices.length === 1);\n const choice = object(data.choices[0]);\n requireResponse(choice.finish_reason === \"stop\");\n const message = object(choice.message);\n requireResponse(\n message.role === \"assistant\" && typeof message.content === \"string\",\n );\n requireResponse(message.refusal == null && message.function_call == null);\n requireResponse(\n message.tool_calls == null ||\n (Array.isArray(message.tool_calls) && message.tool_calls.length === 0),\n );\n const reported = usage(\n data.usage,\n \"prompt_tokens\",\n \"completion_tokens\",\n \"prompt_tokens_details\",\n );\n return { text: message.content, ...(reported ? { usage: reported } : {}) };\n}\n\nexport function readModelResponse(value: unknown): ModelResult {\n const data = object(value);\n requireResponse(data.status === \"completed\" && data.error == null);\n requireResponse(Array.isArray(data.output));\n const texts: string[] = [];\n for (const value of data.output) {\n const item = object(value);\n if (item.type === \"reasoning\") continue;\n requireResponse(\n item.type === \"message\" &&\n item.role === \"assistant\" &&\n item.status === \"completed\",\n );\n requireResponse(Array.isArray(item.content));\n for (const value of item.content) {\n const part = object(value);\n requireResponse(\n part.type === \"output_text\" && typeof part.text === \"string\",\n );\n texts.push(part.text);\n }\n }\n requireResponse(texts.length > 0);\n const reported = usage(\n data.usage,\n \"input_tokens\",\n \"output_tokens\",\n \"input_tokens_details\",\n );\n return { text: texts.join(\"\"), ...(reported ? { usage: reported } : {}) };\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TransportReference } from "../domain/transport.types.ts";
|
|
1
2
|
import type { AgentAdapter, AgentObservation, Usage } from "../domain/agent.types.ts";
|
|
2
3
|
import type { Brief } from "../domain/prompts.types.ts";
|
|
3
4
|
import type { ResponseSpec } from "../domain/response.types.ts";
|
|
@@ -29,6 +30,7 @@ export interface Turn {
|
|
|
29
30
|
readonly status: number;
|
|
30
31
|
readonly conversation?: string;
|
|
31
32
|
readonly transcript?: string;
|
|
33
|
+
readonly transcriptReference?: TransportReference;
|
|
32
34
|
readonly usage: Usage;
|
|
33
35
|
readonly durationMs: number;
|
|
34
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.types.js","sourceRoot":"","sources":["../../src/application/execution.types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AgentAdapter,\n AgentObservation,\n Usage,\n} from \"../domain/agent.types.ts\";\nimport type { Brief } from \"../domain/prompts.types.ts\";\nimport type { ResponseSpec } from \"../domain/response.types.ts\";\nimport type { Logging } from \"../infrastructure/journal.types.ts\";\n\nexport interface DispatchOptions<T = undefined> {\n readonly agent?: AgentAdapter;\n readonly logging?: Logging;\n readonly label?: string;\n readonly brief: Brief;\n readonly passes?: number;\n readonly until?: string | readonly string[];\n readonly idleMs?: number;\n readonly idleWarningMs?: number;\n readonly settleMs?: number;\n readonly deadlineMs?: number;\n readonly expansionMs?: number;\n readonly signal?: AbortSignal;\n readonly continuation?: { readonly id: string; readonly fork?: boolean };\n readonly response?: ResponseSpec<T>;\n readonly observe?: (event: AgentObservation) => void;\n readonly warn?: (message: string) => void;\n readonly diagnostic?: (message: string) => void;\n}\n\nexport interface Turn {\n readonly text: string;\n readonly status: number;\n readonly conversation?: string;\n readonly transcript?: string;\n readonly usage: Usage;\n readonly durationMs: number;\n}\n\nexport interface AgentOutput {\n readonly completed: boolean;\n readonly conversation: string | undefined;\n append(chunk: string): void;\n flush(): void;\n result(): Pick<Turn, \"text\" | \"usage\" | \"conversation\">;\n}\n\nexport interface ActivityWatchdog {\n refresh(completed: boolean): void;\n close(): void;\n}\n\nexport interface Execution<T> {\n readonly text: string;\n readonly turns: readonly Turn[];\n readonly usage: Usage;\n readonly conversation?: string;\n readonly value: T;\n readonly completed: boolean;\n readonly completion?: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"execution.types.js","sourceRoot":"","sources":["../../src/application/execution.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TransportReference } from \"../domain/transport.types.ts\";\nimport type {\n AgentAdapter,\n AgentObservation,\n Usage,\n} from \"../domain/agent.types.ts\";\nimport type { Brief } from \"../domain/prompts.types.ts\";\nimport type { ResponseSpec } from \"../domain/response.types.ts\";\nimport type { Logging } from \"../infrastructure/journal.types.ts\";\n\nexport interface DispatchOptions<T = undefined> {\n readonly agent?: AgentAdapter;\n readonly logging?: Logging;\n readonly label?: string;\n readonly brief: Brief;\n readonly passes?: number;\n readonly until?: string | readonly string[];\n readonly idleMs?: number;\n readonly idleWarningMs?: number;\n readonly settleMs?: number;\n readonly deadlineMs?: number;\n readonly expansionMs?: number;\n readonly signal?: AbortSignal;\n readonly continuation?: { readonly id: string; readonly fork?: boolean };\n readonly response?: ResponseSpec<T>;\n readonly observe?: (event: AgentObservation) => void;\n readonly warn?: (message: string) => void;\n readonly diagnostic?: (message: string) => void;\n}\n\nexport interface Turn {\n readonly text: string;\n readonly status: number;\n readonly conversation?: string;\n readonly transcript?: string;\n readonly transcriptReference?: TransportReference;\n readonly usage: Usage;\n readonly durationMs: number;\n}\n\nexport interface AgentOutput {\n readonly completed: boolean;\n readonly conversation: string | undefined;\n append(chunk: string): void;\n flush(): void;\n result(): Pick<Turn, \"text\" | \"usage\" | \"conversation\">;\n}\n\nexport interface ActivityWatchdog {\n refresh(completed: boolean): void;\n close(): void;\n}\n\nexport interface Execution<T> {\n readonly text: string;\n readonly turns: readonly Turn[];\n readonly usage: Usage;\n readonly conversation?: string;\n readonly value: T;\n readonly completed: boolean;\n readonly completion?: string;\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Transport, TransportReference } from "../domain/transport.types.ts";
|
|
1
2
|
import type { AgentAdapter } from "../domain/agent.types.ts";
|
|
2
3
|
import type { Command, CommandResult } from "../domain/command.types.ts";
|
|
3
4
|
import type { Brief } from "../domain/prompts.types.ts";
|
|
@@ -42,6 +43,8 @@ export interface SandboxOptions extends WorkspaceOptions {
|
|
|
42
43
|
readonly logging?: Logging;
|
|
43
44
|
readonly bootstrap?: boolean;
|
|
44
45
|
readonly conversationHome?: string;
|
|
46
|
+
readonly recoveryTransport?: Transport;
|
|
47
|
+
readonly activityTransport?: Transport;
|
|
45
48
|
}
|
|
46
49
|
export interface AttachOptions {
|
|
47
50
|
readonly ask?: VariableQuestion;
|
|
@@ -64,6 +67,8 @@ export interface DispatchResult<T> extends Execution<T> {
|
|
|
64
67
|
readonly directory: string;
|
|
65
68
|
readonly commits: readonly Commit[];
|
|
66
69
|
readonly transcript?: string;
|
|
70
|
+
readonly transcriptReference?: TransportReference;
|
|
71
|
+
readonly logReference?: TransportReference;
|
|
67
72
|
readonly log?: string;
|
|
68
73
|
readonly retainedDirectory?: string;
|
|
69
74
|
resume<U = undefined>(options: ContinuationOptions<U>): Promise<DispatchResult<U>>;
|
|
@@ -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 { StorageReservationOptions } from \"../infrastructure/storage-reservations.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 storageQuota?: Omit<StorageReservationOptions, \"signal\">;\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"]}
|
|
1
|
+
{"version":3,"file":"outpost.types.js","sourceRoot":"","sources":["../../src/application/outpost.types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n Transport,\n TransportReference,\n} from \"../domain/transport.types.ts\";\nimport 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 { StorageReservationOptions } from \"../infrastructure/storage-reservations.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 storageQuota?: Omit<StorageReservationOptions, \"signal\">;\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 readonly recoveryTransport?: Transport;\n readonly activityTransport?: Transport;\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 transcriptReference?: TransportReference;\n readonly logReference?: TransportReference;\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,4 @@
|
|
|
1
|
+
import type { TransportReference } from "../domain/transport.types.ts";
|
|
2
|
+
import type { RecoveryArchiveOptions, RecoveryArchiveRestoreOptions } from "./recovery-archive.types.ts";
|
|
3
|
+
export declare function archiveRecovery(options: RecoveryArchiveOptions): Promise<TransportReference>;
|
|
4
|
+
export declare function materializeRecoveryArchive(options: RecoveryArchiveRestoreOptions): Promise<string>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { archiveFiles, restoreArchiveFiles, } from "../infrastructure/transport-archive.js";
|
|
3
|
+
import { snapshotRecoveryTransfer } from "./recovery-restore-snapshot.js";
|
|
4
|
+
import { recoveryChecksumPaths } from "./recovery-checksum-paths.js";
|
|
5
|
+
import { recoveryChecksumDefaults } from "./recovery-checksums.constants.js";
|
|
6
|
+
import { verifyRecoveryTransfer } from "./recovery-verification.js";
|
|
7
|
+
import { invariant } from "../domain/errors.js";
|
|
8
|
+
export async function archiveRecovery(options) {
|
|
9
|
+
const snapshot = await snapshotRecoveryTransfer(options.directory, options.maxBytes);
|
|
10
|
+
try {
|
|
11
|
+
return await archiveFiles(options.transporter, snapshot.directory, [
|
|
12
|
+
...recoveryChecksumPaths(snapshot.state),
|
|
13
|
+
recoveryChecksumDefaults.filename,
|
|
14
|
+
], `recovery/${randomUUID()}`, options.maxBytes);
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
await snapshot.dispose();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function materializeRecoveryArchive(options) {
|
|
21
|
+
await restoreArchiveFiles(options.transporter, options.reference, options.destination, options.maxBytes);
|
|
22
|
+
const verified = await verifyRecoveryTransfer(options.destination, {
|
|
23
|
+
checksums: true,
|
|
24
|
+
...(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes }),
|
|
25
|
+
});
|
|
26
|
+
invariant(verified.complete && verified.integrity === "checksums-match", "Recovery archive integrity verification failed; destination retained");
|
|
27
|
+
return options.destination;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=recovery-archive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-archive.js","sourceRoot":"","sources":["../../src/application/recovery-archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EACL,YAAY,EACZ,mBAAmB,GACpB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMhD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAA+B;IAE/B,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC7C,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,QAAQ,CACjB,CAAC;IACF,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CACvB,OAAO,CAAC,WAAW,EACnB,QAAQ,CAAC,SAAS,EAClB;YACE,GAAG,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC;YACxC,wBAAwB,CAAC,QAAQ;SAClC,EACD,YAAY,UAAU,EAAE,EAAE,EAC1B,OAAO,CAAC,QAAQ,CACjB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAsC;IAEtC,MAAM,mBAAmB,CACvB,OAAO,CAAC,WAAW,EACnB,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,WAAW,EACnB,OAAO,CAAC,QAAQ,CACjB,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,OAAO,CAAC,WAAW,EAAE;QACjE,SAAS,EAAE,IAAI;QACf,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;KAC1E,CAAC,CAAC;IACH,SAAS,CACP,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,KAAK,iBAAiB,EAC7D,sEAAsE,CACvE,CAAC;IACF,OAAO,OAAO,CAAC,WAAW,CAAC;AAC7B,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { TransportReference } from \"../domain/transport.types.ts\";\nimport {\n archiveFiles,\n restoreArchiveFiles,\n} from \"../infrastructure/transport-archive.ts\";\nimport { snapshotRecoveryTransfer } from \"./recovery-restore-snapshot.ts\";\nimport { recoveryChecksumPaths } from \"./recovery-checksum-paths.ts\";\nimport { recoveryChecksumDefaults } from \"./recovery-checksums.constants.ts\";\nimport { verifyRecoveryTransfer } from \"./recovery-verification.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type {\n RecoveryArchiveOptions,\n RecoveryArchiveRestoreOptions,\n} from \"./recovery-archive.types.ts\";\n\nexport async function archiveRecovery(\n options: RecoveryArchiveOptions,\n): Promise<TransportReference> {\n const snapshot = await snapshotRecoveryTransfer(\n options.directory,\n options.maxBytes,\n );\n try {\n return await archiveFiles(\n options.transporter,\n snapshot.directory,\n [\n ...recoveryChecksumPaths(snapshot.state),\n recoveryChecksumDefaults.filename,\n ],\n `recovery/${randomUUID()}`,\n options.maxBytes,\n );\n } finally {\n await snapshot.dispose();\n }\n}\n\nexport async function materializeRecoveryArchive(\n options: RecoveryArchiveRestoreOptions,\n): Promise<string> {\n await restoreArchiveFiles(\n options.transporter,\n options.reference,\n options.destination,\n options.maxBytes,\n );\n const verified = await verifyRecoveryTransfer(options.destination, {\n checksums: true,\n ...(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes }),\n });\n invariant(\n verified.complete && verified.integrity === \"checksums-match\",\n \"Recovery archive integrity verification failed; destination retained\",\n );\n return options.destination;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TransportReference, TransportStoreOptions } from "../domain/transport.types.ts";
|
|
2
|
+
export interface RecoveryArchiveOptions extends TransportStoreOptions {
|
|
3
|
+
readonly directory: string;
|
|
4
|
+
readonly maxBytes?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface RecoveryArchiveRestoreOptions extends TransportStoreOptions {
|
|
7
|
+
readonly reference: TransportReference;
|
|
8
|
+
readonly destination: string;
|
|
9
|
+
readonly maxBytes?: number;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-archive.types.js","sourceRoot":"","sources":["../../src/application/recovery-archive.types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n TransportReference,\n TransportStoreOptions,\n} from \"../domain/transport.types.ts\";\nexport interface RecoveryArchiveOptions extends TransportStoreOptions {\n readonly directory: string;\n readonly maxBytes?: number;\n}\nexport interface RecoveryArchiveRestoreOptions extends TransportStoreOptions {\n readonly reference: TransportReference;\n readonly destination: string;\n readonly maxBytes?: number;\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { inspectTransportRecovery } from "./transport-inspection.js";
|
|
1
2
|
import { inspectResourceActivity } from "../infrastructure/resource-activity-inspection.js";
|
|
2
3
|
import { inspectLocks } from "../infrastructure/git/lock-inspection.js";
|
|
3
4
|
import { join } from "node:path";
|
|
@@ -6,6 +7,8 @@ import { git } from "../infrastructure/git/command.js";
|
|
|
6
7
|
import { inspectWorktreeGit } from "../infrastructure/git/worktree-inspection.js";
|
|
7
8
|
import { storageInventory } from "../infrastructure/storage-inventory.js";
|
|
8
9
|
export async function inspectRecovery(options = {}) {
|
|
10
|
+
if (options.transporter)
|
|
11
|
+
return inspectTransportRecovery(options);
|
|
9
12
|
const requested = await directory(options.repository);
|
|
10
13
|
const repository = await directory((await git(requested, ["rev-parse", "--show-toplevel"])).trim());
|
|
11
14
|
const inventory = await storageInventory(join(repository, ".outpost"), options.maxEntries);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recovery-inspection.js","sourceRoot":"","sources":["../../src/application/recovery-inspection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,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,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS;QACjC,CAAC,CAAC,MAAM,uBAAuB,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC;QAC/D,CAAC,CAAC,SAAS,CAAC;IACd,OAAO;QACL,UAAU;QACV,QAAQ,EAAE,YAAY;QACtB,GAAG,SAAS;QACZ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,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 { inspectResourceActivity } from \"../infrastructure/resource-activity-inspection.ts\";\nimport { 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 const resources = options.resources\n ? await inspectResourceActivity(repository, options.maxEntries)\n : undefined;\n return {\n repository,\n activity: \"unverified\",\n ...inventory,\n ...(resources ? { resources } : {}),\n ...(gitReport ? { git: gitReport } : {}),\n ...(lockReport ? { locks: lockReport } : {}),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"recovery-inspection.js","sourceRoot":"","sources":["../../src/application/recovery-inspection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,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,IAAI,OAAO,CAAC,WAAW;QAAE,OAAO,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAClE,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,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS;QACjC,CAAC,CAAC,MAAM,uBAAuB,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC;QAC/D,CAAC,CAAC,SAAS,CAAC;IACd,OAAO;QACL,UAAU;QACV,QAAQ,EAAE,YAAY;QACtB,GAAG,SAAS;QACZ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,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 { inspectTransportRecovery } from \"./transport-inspection.ts\";\nimport { inspectResourceActivity } from \"../infrastructure/resource-activity-inspection.ts\";\nimport { 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 if (options.transporter) return inspectTransportRecovery(options);\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 const resources = options.resources\n ? await inspectResourceActivity(repository, options.maxEntries)\n : undefined;\n return {\n repository,\n activity: \"unverified\",\n ...inventory,\n ...(resources ? { resources } : {}),\n ...(gitReport ? { git: gitReport } : {}),\n ...(lockReport ? { locks: lockReport } : {}),\n };\n}\n"]}
|