@usine/server 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -1
- package/dist/backend.d.ts +12 -9
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +6 -2
- package/dist/backend.js.map +1 -1
- package/dist/backup.d.ts +4 -0
- package/dist/backup.d.ts.map +1 -0
- package/dist/backup.js +13 -0
- package/dist/backup.js.map +1 -0
- package/dist/cli.d.ts +36 -7
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +115 -28
- package/dist/cli.js.map +1 -1
- package/dist/export-run.d.ts +22 -0
- package/dist/export-run.d.ts.map +1 -0
- package/dist/export-run.js +85 -0
- package/dist/export-run.js.map +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +94 -138
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +1 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -7
- package/dist/index.js.map +1 -1
- package/dist/main.js +18 -8
- package/dist/main.js.map +1 -1
- package/dist/shutdown.d.ts +7 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +49 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/up.d.ts +2 -2
- package/dist/up.d.ts.map +1 -1
- package/dist/up.js +48 -25
- package/dist/up.js.map +1 -1
- package/dist/web/assets/_name-BHFMXhWe.js +1 -0
- package/dist/web/assets/_name-Cz2YmpSb.js +1 -0
- package/dist/web/assets/_name-D1NH8oUE.js +6 -0
- package/dist/web/assets/badge-BQobsECb.js +142 -0
- package/dist/web/assets/bash-CLZ0U2zV.js +1 -0
- package/dist/web/assets/button-BoOukj77.js +1 -0
- package/dist/web/assets/core-Cg4Mi2IQ.js +12 -0
- package/dist/web/assets/diff-woXpYk--.js +1 -0
- package/dist/web/assets/empty-DbVYU7bi.js +1 -0
- package/dist/web/assets/engine-javascript-h-x4hGa4.js +141 -0
- package/dist/web/assets/index-CJ-Nk5DM.js +10 -0
- package/dist/web/assets/index-DxGXwXIP.css +2 -0
- package/dist/web/assets/json-qhed-kSA.js +1 -0
- package/dist/web/assets/loops-huxrr83I.js +1 -0
- package/dist/web/assets/operator-copy-BDZ_fazz.js +1 -0
- package/dist/web/assets/overview-DTxvvQ4b.js +1 -0
- package/dist/web/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/dist/web/assets/routes-CbvAb2gn.js +1 -0
- package/dist/web/assets/run-drawer-3blrdBMZ.js +157 -0
- package/dist/web/assets/status-badge-BTkHx8qb.js +1 -0
- package/dist/web/assets/table-B8cLYNvq.js +1 -0
- package/dist/web/assets/typescript-bsJCZSQ-.js +1 -0
- package/dist/web/assets/useCompositeItem-CuLyiETJ.js +1 -0
- package/dist/web/assets/with-selector-N6m4X0X_.js +1 -0
- package/dist/web/index.html +9 -2
- package/package.json +9 -9
- package/dist/web/assets/index-CjRDHHWF.css +0 -2
- package/dist/web/assets/index-DmN0SkGf.js +0 -295
package/README.md
CHANGED
|
@@ -12,4 +12,45 @@ The command prints `http://127.0.0.1:7331` and stays attached to the terminal. P
|
|
|
12
12
|
|
|
13
13
|
Without GitHub App credentials, it opens the setup screen in the default browser, logs the typed credential error, and leaves both trigger streams idle instead of crashing. The browser command has a two-second timeout; a failed opener produces a warning and does not stop the server. Existing Runs, transcript detail, and database-backed Loop pause state remain observable, while interventions stay unavailable. Credentials may come from `USINE_GITHUB_APP_ID` plus `USINE_GITHUB_PRIVATE_KEY`, or from a mode-0600 `.usine/github-app.json` file with `app_id` and `private_key` fields. The running process reads credentials only at startup, so stop and rerun `usine up` after adding them; the setup screen states that restart requirement explicitly.
|
|
14
14
|
|
|
15
|
-
The local-only UI opens each project as a Board built from its authored or proposed lanes. Moving an Item
|
|
15
|
+
The local-only UI opens each project as a Board built from its authored or proposed lanes. Proposed lanes are read-only. Configure `repos[].lanes` in `usine.yaml` and restart `usine up` to enable moves; see the [lane configuration example](../../packages/config/README.md). Moving an Item into an authored label-backed lane exchanges only the labels in that map, preserving descriptive labels outside it; normal polling then evaluates label-protocol loops. Board cards show the latest Run and open its existing detail drawer. The UI can also approve, retry, or cancel a Run; pause or unpause a Loop's database runtime state; page backward through older transcript rows; and tail parent and one-level child session activity.
|
|
16
|
+
|
|
17
|
+
Run conversations remember the reader’s filter, inspected disclosures and reading place when the drawer reopens or the page refreshes. Bookmarks are specific to each Run and browser origin; unread activity remains pending while a saved place is restored. See the [conversation reader behavior](../web/README.md#returning-to-a-conversation) for retention and history-recovery limits.
|
|
18
|
+
|
|
19
|
+
Direct browser requests for UI routes serve the application shell, so refreshing or sharing a Project or Configuration URL works. Unknown `/api/*` routes, missing `/assets/*` files, and other file-like paths remain 404 responses.
|
|
20
|
+
|
|
21
|
+
Run conversations summarize adjacent completed tools by their recorded actions, including the files read or changed and recognized test or build invocations. Expand a group to inspect each tool and its result.
|
|
22
|
+
|
|
23
|
+
The operator API includes `POST /api/cycle-budgets/reset` with an Ask identity. It uses the same request-origin guard and typed error contract as other interventions; stale Asks return 409 and needs-setup mode rejects resets until the runtime is available.
|
|
24
|
+
|
|
25
|
+
## Runtime backup and Run evidence
|
|
26
|
+
|
|
27
|
+
From the instance folder, copy the runtime store while the orchestrator runs:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
usine backup /path/to/runtime-backup.sqlite
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`usine backup` copies all runtime tables, including committed WAL data, while the orchestrator runs. It opens the source read-only and doesn't need GitHub credentials.
|
|
34
|
+
|
|
35
|
+
Use a new filename in an existing writable directory on a filesystem that supports hard links. The command writes a complete backup with owner-only permissions and won't overwrite existing files. Errors identify the affected path and cause.
|
|
36
|
+
|
|
37
|
+
Keep the backup outside the instance folder to protect it against loss of that folder. Back up the authored instance files and credentials separately. To restore, stop the orchestrator, move the existing `.usine/runtime.sqlite` and any `runtime.sqlite-wal` / `runtime.sqlite-shm` files aside, and copy the backup to `.usine/runtime.sqlite`. Restart with the matching instance configuration and engine version. Restoring an older backup also restores its older deduplication ledger, so work performed after that backup can run again.
|
|
38
|
+
|
|
39
|
+
From the instance folder, export one Run into a local JSON file:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
usine export-run <runId>
|
|
43
|
+
usine export-run <runId> --output /path/to/evidence.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The default destination is `run-<encoded-runId>.json` in the current directory; characters such as `/` in the Run id are percent-encoded. The output directory must already exist. The command writes a complete file with owner-only permissions, preserves existing destinations, and prints its path after success. A missing Run, unreadable runtime store, encoding failure, or write failure returns a nonzero exit status.
|
|
47
|
+
|
|
48
|
+
The versioned JSON contains `exportedAt`, the full durable Run `snapshot` (Event, effective task and Agent, repository revision, Step result, and all Attempts), and every saved transcript envelope for those Attempts in append order. The snapshot and transcripts come from one database transaction, including history beyond the drawer's current page. Active Runs continue accumulating history, so export a settled Run for its final evidence.
|
|
49
|
+
|
|
50
|
+
Exporting opens the instance's existing `.usine/runtime.sqlite` in read-only mode, without creating tables, running migrations, starting Attempts, or polling triggers. The command keeps the output local. Transcripts can contain repository content and tool output; inspect the file before sharing it. A Run export preserves selected evidence; use `usine backup <path>` for a restorable runtime database, as described in [ADR 0010](../../docs/adr/0010-single-sqlite-runtime-store.md).
|
|
51
|
+
|
|
52
|
+
## Stopping and updating
|
|
53
|
+
|
|
54
|
+
Send SIGTERM or press Ctrl+C once to stop trigger polling and drain admitted Attempts. The server waits up to `max_attempt_minutes` from the shutdown request before closing the runtime. A second SIGTERM or Ctrl+C stops the wait immediately. Queued Runs and automatic retries remain saved for the next start. An Attempt interrupted by the deadline or force stop uses normal restart recovery.
|
|
55
|
+
|
|
56
|
+
After `pnpm build`, reload the page to use the rebuilt web bundle; no process restart is required. Instance configuration and GitHub credentials are read at startup.
|
package/dist/backend.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { LoadedInstance } from "@usine/config";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import type { LoadedInstance } from "@usine/config/instance";
|
|
2
|
+
import { LoopName } from "@usine/core/loop";
|
|
3
|
+
import { CycleBudgetAskId } from "@usine/core/cycle-budget";
|
|
4
|
+
import { RunId } from "@usine/core/run";
|
|
5
|
+
import { type BoardMove, type FactoryOverview, type RunDetailView, type TranscriptRequest, type Operator, type OperatorError, type OperatorObservation } from "@usine/orchestrator/operator";
|
|
4
6
|
import { Context, Effect, Layer, Schema } from "effect";
|
|
5
7
|
declare const BackendUnavailableError_base: Schema.Class<BackendUnavailableError, Schema.TaggedStruct<"BackendUnavailableError", {
|
|
6
8
|
readonly message: Schema.String;
|
|
@@ -10,13 +12,14 @@ export declare class BackendUnavailableError extends BackendUnavailableError_bas
|
|
|
10
12
|
export type BackendError = OperatorError | BackendUnavailableError;
|
|
11
13
|
declare const FactoryBackend_base: Context.ServiceClass<FactoryBackend, "@usine/server/FactoryBackend", {
|
|
12
14
|
readonly overview: Effect.Effect<FactoryOverview, BackendError>;
|
|
13
|
-
readonly detail: (runId:
|
|
14
|
-
readonly approve: (runId:
|
|
15
|
-
readonly
|
|
16
|
-
readonly
|
|
15
|
+
readonly detail: (runId: RunId, request: TranscriptRequest) => Effect.Effect<RunDetailView, BackendError>;
|
|
16
|
+
readonly approve: (runId: RunId) => Effect.Effect<void, BackendError>;
|
|
17
|
+
readonly resetCycleBudget: (askId: CycleBudgetAskId) => Effect.Effect<void, BackendError>;
|
|
18
|
+
readonly retry: (runId: RunId) => Effect.Effect<void, BackendError>;
|
|
19
|
+
readonly cancel: (runId: RunId) => Effect.Effect<void, BackendError>;
|
|
17
20
|
readonly moveBoardItem: (move: BoardMove) => Effect.Effect<void, BackendError>;
|
|
18
|
-
readonly pause: (loop:
|
|
19
|
-
readonly unpause: (loop:
|
|
21
|
+
readonly pause: (loop: LoopName) => Effect.Effect<void, BackendError>;
|
|
22
|
+
readonly unpause: (loop: LoopName) => Effect.Effect<void, BackendError>;
|
|
20
23
|
}>;
|
|
21
24
|
export declare class FactoryBackend extends FactoryBackend_base {
|
|
22
25
|
}
|
package/dist/backend.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EACL,KAAK,SAAS,EACd,KAAK,eAAe,EAEpB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;AAExD,qBAAa,uBAAwB,SAAQ,4BAI3C;CAAG;AAEL,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,uBAAuB,CAAC;;uBAK5C,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC;qBAC9C,CACf,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,KACvB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC;sBAC7B,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;+BAC1C,CAAC,KAAK,EAAE,gBAAgB,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;oBACzE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;qBAClD,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;4BAC5C,CAAC,IAAI,EAAE,SAAS,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;oBAC9D,CAAC,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;sBACnD,CAAC,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;;AAd3E,qBAAa,cAAe,SAAQ,mBAgBD;CAAG;AAEtC,eAAO,MAAM,gBAAgB,aACjB,cAAc,YACd,QAAQ,CAAC,SAAS,CAAC,KAC5B,KAAK,CAAC,KAAK,CAAC,cAAc,CAWzB,CAAC;AAEL,eAAO,MAAM,sBAAsB,aACvB,cAAc,YACd,MAAM,eACH,mBAAmB,CAAC,SAAS,CAAC,KAC1C,KAAK,CAAC,KAAK,CAAC,cAAc,CAwB5B,CAAC"}
|
package/dist/backend.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { LoopName } from "@usine/core/loop";
|
|
2
|
+
import { CycleBudgetAskId } from "@usine/core/cycle-budget";
|
|
3
|
+
import { RunId } from "@usine/core/run";
|
|
4
|
+
import { NeedsSetupOverview, } from "@usine/orchestrator/operator";
|
|
3
5
|
import { Context, Effect, Layer, Schema } from "effect";
|
|
4
6
|
export class BackendUnavailableError extends Schema.TaggedError("@usine/server/BackendUnavailableError")("BackendUnavailableError", {
|
|
5
7
|
message: Schema.String,
|
|
@@ -11,6 +13,7 @@ export const liveBackendLayer = (instance, operator) => Layer.succeed(FactoryBac
|
|
|
11
13
|
overview: operator.overview(instance),
|
|
12
14
|
detail: operator.detail,
|
|
13
15
|
approve: operator.approve,
|
|
16
|
+
resetCycleBudget: operator.resetCycleBudget,
|
|
14
17
|
retry: operator.retry,
|
|
15
18
|
cancel: operator.cancel,
|
|
16
19
|
moveBoardItem: (move) => operator.moveBoardItem(instance, move),
|
|
@@ -29,6 +32,7 @@ export const needsSetupBackendLayer = (instance, errorTag, observation) => {
|
|
|
29
32
|
overview,
|
|
30
33
|
detail: observation.detail,
|
|
31
34
|
approve: fail,
|
|
35
|
+
resetCycleBudget: fail,
|
|
32
36
|
retry: fail,
|
|
33
37
|
cancel: fail,
|
|
34
38
|
moveBoardItem: fail,
|
package/dist/backend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAGL,kBAAkB,GAMnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExD,MAAM,OAAO,uBAAwB,SAAQ,MAAM,CAAC,WAAW,CAC7D,uCAAuC,CACxC,CAAC,yBAAyB,EAAE;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CAAC;CAAG;AAIL,MAAM,OAAO,cAAe,SAAQ,OAAO,CAAC,OAAO,EAgBhD,CAAC,8BAA8B,CAAC;CAAG;AAEtC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,QAAwB,EACxB,QAA6B,EACA,EAAE,CAC/B,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;IACrC,MAAM,EAAE,QAAQ,CAAC,MAAM;IACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;IACzB,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;IAC3C,KAAK,EAAE,QAAQ,CAAC,KAAK;IACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;IACvB,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC;IAC/D,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IACzD,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;CAC9D,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,QAAwB,EACxB,QAAgB,EAChB,WAA2C,EACd,EAAE;IAC/B,MAAM,WAAW,GAAG,IAAI,uBAAuB,CAAC;QAC9C,OAAO,EAAE,qEAAqE;KAC/E,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,WAAW;SACzB,QAAQ,CAAC,QAAQ,CAAC;SAClB,IAAI,CACH,MAAM,CAAC,GAAG,CACR,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAChC,IAAI,kBAAkB,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAClE,CACF,CAAC;IACJ,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACnC,QAAQ;QACR,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,OAAO,EAAE,IAAI;QACb,gBAAgB,EAAE,IAAI;QACtB,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,aAAa,EAAE,IAAI;QACnB,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;AACL,CAAC,CAAC"}
|
package/dist/backup.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Effect, Path } from "effect";
|
|
2
|
+
/** Copies the current instance's runtime database to `output`, resolved from the working directory. */
|
|
3
|
+
export declare const backup: (output: string) => Effect.Effect<void, import("@usine/engine/local-sqlite").RuntimeStoreBackupError, Path.Path>;
|
|
4
|
+
//# sourceMappingURL=backup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE/C,uGAAuG;AACvG,eAAO,MAAM,MAAM,kHAOjB,CAAC"}
|
package/dist/backup.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { InstanceDirectory } from "@usine/core/instance";
|
|
2
|
+
import { backup as backupDatabase } from "@usine/engine/local-sqlite";
|
|
3
|
+
import { Console, Effect, Path } from "effect";
|
|
4
|
+
/** Copies the current instance's runtime database to `output`, resolved from the working directory. */
|
|
5
|
+
export const backup = Effect.fn("Cli.backup")(function* (output) {
|
|
6
|
+
const directory = InstanceDirectory.make(process.cwd());
|
|
7
|
+
const path = yield* Path.Path;
|
|
8
|
+
const destination = path.resolve(output);
|
|
9
|
+
yield* Effect.annotateCurrentSpan({ instanceDirectory: directory, destination });
|
|
10
|
+
yield* backupDatabase(directory, destination);
|
|
11
|
+
yield* Console.log(`Backed up runtime store to ${destination}`);
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=backup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup.js","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE/C,uGAAuG;AACvG,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAc;IACrE,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;IACjF,KAAK,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC9C,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const DEFAULT_PORT = 7331;
|
|
|
5
5
|
export declare const BROWSER_OPEN_TIMEOUT = "2 seconds";
|
|
6
6
|
export declare const Port: Schema.brand<Schema.Int, "ServerPort">;
|
|
7
7
|
export type Port = typeof Port.Type;
|
|
8
|
-
export declare const CLI_USAGE = "Usage:\n usine up [--port <port>]\n usine --help\n usine --version\n\nOptions:\n -p, --port <port>
|
|
8
|
+
export declare const CLI_USAGE = "Usage:\n usine up [--port <port>] [--allow-volatile-instance]\n usine backup <path>\n usine export-run <runId> [--output <path>]\n usine --help\n usine --version\n\nOptions:\n -p, --port <port> Listen on this port (default: 7331)\n --allow-volatile-instance Start even when the instance folder sits under a temp path\n -o, --output <path> Write Run evidence here (default: run-<encoded-runId>.json)\n -h, --help Print this usage\n -v, --version Print the pinned @usine/server version\n\nEnvironment:\n USINE_PORT Listen on this port when --port is absent\n USINE_ALLOW_VOLATILE_INSTANCE Same as --allow-volatile-instance when set to 1";
|
|
9
9
|
declare const CliUsageError_base: Schema.Class<CliUsageError, Schema.TaggedStruct<"CliUsageError", {
|
|
10
10
|
readonly message: Schema.String;
|
|
11
11
|
}>, import("effect/Cause").YieldableError>;
|
|
@@ -27,6 +27,13 @@ declare const ServerStartError_base: Schema.Class<ServerStartError, Schema.Tagge
|
|
|
27
27
|
}>, import("effect/Cause").YieldableError>;
|
|
28
28
|
export declare class ServerStartError extends ServerStartError_base {
|
|
29
29
|
}
|
|
30
|
+
declare const VolatileInstanceDirectoryError_base: Schema.Class<VolatileInstanceDirectoryError, Schema.TaggedStruct<"VolatileInstanceDirectoryError", {
|
|
31
|
+
readonly directory: Schema.String;
|
|
32
|
+
readonly root: Schema.String;
|
|
33
|
+
}>, import("effect/Cause").YieldableError>;
|
|
34
|
+
/** Raised when the instance folder sits under a path the OS may clear, since its runtime store is the only copy of run history. */
|
|
35
|
+
export declare class VolatileInstanceDirectoryError extends VolatileInstanceDirectoryError_base {
|
|
36
|
+
}
|
|
30
37
|
declare const BrowserOpenError_base: Schema.Class<BrowserOpenError, Schema.TaggedStruct<"BrowserOpenError", {
|
|
31
38
|
readonly command: Schema.String;
|
|
32
39
|
readonly cause: Schema.Defect;
|
|
@@ -41,18 +48,40 @@ export declare class VersionCommand extends VersionCommand_base {
|
|
|
41
48
|
}
|
|
42
49
|
declare const UpCommand_base: Schema.Class<UpCommand, Schema.TaggedStruct<"UpCommand", {
|
|
43
50
|
readonly port: Schema.brand<Schema.Int, "ServerPort">;
|
|
51
|
+
readonly allowVolatileInstance: Schema.Boolean;
|
|
44
52
|
}>, {}>;
|
|
45
53
|
export declare class UpCommand extends UpCommand_base {
|
|
46
54
|
}
|
|
47
|
-
|
|
55
|
+
declare const ExportRunCommand_base: Schema.Class<ExportRunCommand, Schema.TaggedStruct<"ExportRunCommand", {
|
|
56
|
+
readonly runId: Schema.brand<Schema.NonEmptyString, "RunId">;
|
|
57
|
+
readonly output: Schema.Option<Schema.NonEmptyString>;
|
|
58
|
+
}>, {}>;
|
|
59
|
+
/** Exports one Run from the current instance into a new local JSON file. */
|
|
60
|
+
export declare class ExportRunCommand extends ExportRunCommand_base {
|
|
61
|
+
}
|
|
62
|
+
declare const BackupCommand_base: Schema.Class<BackupCommand, Schema.TaggedStruct<"BackupCommand", {
|
|
63
|
+
readonly output: Schema.NonEmptyString;
|
|
64
|
+
}>, {}>;
|
|
65
|
+
/** Copies the current instance's runtime store into a new SQLite file. */
|
|
66
|
+
export declare class BackupCommand extends BackupCommand_base {
|
|
67
|
+
}
|
|
68
|
+
export interface CliEnvironment {
|
|
69
|
+
readonly port: Option.Option<string>;
|
|
70
|
+
readonly allowVolatileInstance: Option.Option<string>;
|
|
71
|
+
}
|
|
72
|
+
export declare const CliCommand: Schema.Union<readonly [typeof HelpCommand, typeof VersionCommand, typeof UpCommand, typeof ExportRunCommand, typeof BackupCommand]>;
|
|
48
73
|
export type CliCommand = typeof CliCommand.Type;
|
|
49
|
-
/**
|
|
50
|
-
export declare const parseCli: (args: readonly string[],
|
|
51
|
-
/**
|
|
74
|
+
/** Parses process arguments and the environment into one validated CLI command. */
|
|
75
|
+
export declare const parseCli: (args: readonly string[], environment: CliEnvironment) => Effect.Effect<BackupCommand | ExportRunCommand | HelpCommand | UpCommand | VersionCommand, CliUsageError, never>;
|
|
76
|
+
/** Directories the OS may clear: `os.tmpdir()`, `$TMPDIR`, and the usual temp locations. */
|
|
77
|
+
export declare const volatileRoots: (environmentTmpdir: Option.Option<string>) => ReadonlyArray<string>;
|
|
78
|
+
/** Returns the volatile root the directory sits under, if any. Paths are compared as given, with symlinks unresolved. */
|
|
79
|
+
export declare const volatileRoot: (directory: string, roots: ReadonlyArray<string>) => Option.Option<string>;
|
|
80
|
+
/** Reads the version of this installed server from its package.json. */
|
|
52
81
|
export declare const packageVersion: () => Effect.Effect<string, CliVersionError, FileSystem.FileSystem>;
|
|
53
|
-
/**
|
|
82
|
+
/** Maps a bind failure to the CLI's startup error, so an address already in use is reported as such. */
|
|
54
83
|
export declare const serverStartError: (port: Port, error: ServeError) => PortInUseError | ServerStartError;
|
|
55
|
-
/**
|
|
84
|
+
/** Opens the setup page in a browser; call it only after the HTTP server has bound. */
|
|
56
85
|
export declare const openBrowser: (url: string, timeout?: Duration.Input | undefined) => Effect.Effect<undefined, BrowserOpenError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
57
86
|
export {};
|
|
58
87
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAIA,OAAO,EAAW,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC/E,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAEvE,eAAO,MAAM,YAAY,OAAQ,CAAC;AAClC,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAEhD,eAAO,MAAM,IAAI,wCAEiB,CAAC;AACnC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAC;AAIpC,eAAO,MAAM,SAAS,wtBAgB2D,CAAC;;;;AAElF,qBAAa,aAAc,SAAQ,kBAGlC;CAAG;;;;AAEJ,qBAAa,eAAgB,SAAQ,oBAEW;CAAG;;;;AAEnD,qBAAa,cAAe,SAAQ,mBAED;CAAG;;;;;AAEtC,qBAAa,gBAAiB,SAAQ,qBAEuB;CAAG;;;;;AAEhE,mIAAmI;AACnI,qBAAa,8BAA+B,SAAQ,mCAKlD;CAAG;;;;;AAEL,qBAAa,gBAAiB,SAAQ,qBAKpC;CAAG;;AAEL,qBAAa,WAAY,SAAQ,gBAGhC;CAAG;;AAEJ,qBAAa,cAAe,SAAQ,mBAEb;CAAG;;;;;AAE1B,qBAAa,SAAU,SAAQ,cAG9B;CAAG;;;;;AAEJ,4EAA4E;AAC5E,qBAAa,gBAAiB,SAAQ,qBAKpC;CAAG;;;;AAEL,0EAA0E;AAC1E,qBAAa,aAAc,SAAQ,kBAGlC;CAAG;AAEJ,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;CACvD;AAED,eAAO,MAAM,UAAU,qIAMrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAC;AAyEhD,mFAAmF;AACnF,eAAO,MAAM,QAAQ,4KAmBnB,CAAC;AAEH,4FAA4F;AAC5F,eAAO,MAAM,aAAa,sBAAuB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAG,aAAa,CAAC,MAAM,CAW5D,CAAC;AAKlC,yHAAyH;AACzH,eAAO,MAAM,YAAY,cACZ,MAAM,SACV,aAAa,CAAC,MAAM,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,MAAM,CAGtB,CAAC;AAMF,wEAAwE;AACxE,eAAO,MAAM,cAAc,qEAUzB,CAAC;AAIH,wGAAwG;AACxG,eAAO,MAAM,gBAAgB,SAAU,IAAI,SAAS,UAAU,sCAGN,CAAC;AAUzD,uFAAuF;AACvF,eAAO,MAAM,WAAW,4IAyBtB,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { tmpdir } from "node:os";
|
|
2
|
+
import { resolve, sep } from "node:path";
|
|
1
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { RunId } from "@usine/core/run";
|
|
2
5
|
import { Console, Duration, Effect, FileSystem, Option, Schema } from "effect";
|
|
3
6
|
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
4
7
|
export const DEFAULT_PORT = 7_331;
|
|
@@ -6,17 +9,22 @@ export const BROWSER_OPEN_TIMEOUT = "2 seconds";
|
|
|
6
9
|
export const Port = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65_535 }, { message: "Expected a TCP port" })).pipe(Schema.brand("ServerPort"));
|
|
7
10
|
const PortFromString = Schema.NumberFromString.pipe(Schema.decodeTo(Port));
|
|
8
11
|
export const CLI_USAGE = `Usage:
|
|
9
|
-
usine up [--port <port>]
|
|
12
|
+
usine up [--port <port>] [--allow-volatile-instance]
|
|
13
|
+
usine backup <path>
|
|
14
|
+
usine export-run <runId> [--output <path>]
|
|
10
15
|
usine --help
|
|
11
16
|
usine --version
|
|
12
17
|
|
|
13
18
|
Options:
|
|
14
|
-
-p, --port <port>
|
|
15
|
-
-
|
|
16
|
-
-
|
|
19
|
+
-p, --port <port> Listen on this port (default: 7331)
|
|
20
|
+
--allow-volatile-instance Start even when the instance folder sits under a temp path
|
|
21
|
+
-o, --output <path> Write Run evidence here (default: run-<encoded-runId>.json)
|
|
22
|
+
-h, --help Print this usage
|
|
23
|
+
-v, --version Print the pinned @usine/server version
|
|
17
24
|
|
|
18
25
|
Environment:
|
|
19
|
-
USINE_PORT
|
|
26
|
+
USINE_PORT Listen on this port when --port is absent
|
|
27
|
+
USINE_ALLOW_VOLATILE_INSTANCE Same as --allow-volatile-instance when set to 1`;
|
|
20
28
|
export class CliUsageError extends Schema.TaggedError("@usine/server/CliUsageError")("CliUsageError", { message: Schema.String }) {
|
|
21
29
|
}
|
|
22
30
|
export class CliVersionError extends Schema.TaggedError("@usine/server/CliVersionError")("CliVersionError", { cause: Schema.Defect() }) {
|
|
@@ -25,6 +33,12 @@ export class PortInUseError extends Schema.TaggedError("@usine/server/PortInUseE
|
|
|
25
33
|
}
|
|
26
34
|
export class ServerStartError extends Schema.TaggedError("@usine/server/ServerStartError")("ServerStartError", { port: Port, cause: Schema.Defect() }) {
|
|
27
35
|
}
|
|
36
|
+
/** Raised when the instance folder sits under a path the OS may clear, since its runtime store is the only copy of run history. */
|
|
37
|
+
export class VolatileInstanceDirectoryError extends Schema.TaggedError("@usine/server/VolatileInstanceDirectoryError")("VolatileInstanceDirectoryError", {
|
|
38
|
+
directory: Schema.String,
|
|
39
|
+
root: Schema.String,
|
|
40
|
+
}) {
|
|
41
|
+
}
|
|
28
42
|
export class BrowserOpenError extends Schema.TaggedError("@usine/server/BrowserOpenError")("BrowserOpenError", {
|
|
29
43
|
command: Schema.String,
|
|
30
44
|
cause: Schema.Defect(),
|
|
@@ -34,42 +48,115 @@ export class HelpCommand extends Schema.TaggedClass("@usine/server/HelpCommand")
|
|
|
34
48
|
}
|
|
35
49
|
export class VersionCommand extends Schema.TaggedClass("@usine/server/VersionCommand")("VersionCommand", {}) {
|
|
36
50
|
}
|
|
37
|
-
export class UpCommand extends Schema.TaggedClass("@usine/server/UpCommand")("UpCommand", { port: Port }) {
|
|
51
|
+
export class UpCommand extends Schema.TaggedClass("@usine/server/UpCommand")("UpCommand", { port: Port, allowVolatileInstance: Schema.Boolean }) {
|
|
52
|
+
}
|
|
53
|
+
/** Exports one Run from the current instance into a new local JSON file. */
|
|
54
|
+
export class ExportRunCommand extends Schema.TaggedClass("@usine/server/ExportRunCommand")("ExportRunCommand", {
|
|
55
|
+
runId: RunId,
|
|
56
|
+
output: Schema.Option(Schema.NonEmptyString),
|
|
57
|
+
}) {
|
|
58
|
+
}
|
|
59
|
+
/** Copies the current instance's runtime store into a new SQLite file. */
|
|
60
|
+
export class BackupCommand extends Schema.TaggedClass("@usine/server/BackupCommand")("BackupCommand", { output: Schema.NonEmptyString }) {
|
|
38
61
|
}
|
|
39
|
-
export const CliCommand = Schema.Union([
|
|
62
|
+
export const CliCommand = Schema.Union([
|
|
63
|
+
HelpCommand,
|
|
64
|
+
VersionCommand,
|
|
65
|
+
UpCommand,
|
|
66
|
+
ExportRunCommand,
|
|
67
|
+
BackupCommand,
|
|
68
|
+
]);
|
|
40
69
|
const usageError = (message = CLI_USAGE) => new CliUsageError({ message });
|
|
41
70
|
const decodePort = (source, value) => Schema.decodeUnknownEffect(PortFromString)(value).pipe(Effect.mapError(() => usageError(`${source} must be a whole number between 1 and 65535.\n\n${CLI_USAGE}`)));
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
71
|
+
const ALLOW_VOLATILE_FLAG = "--allow-volatile-instance";
|
|
72
|
+
const exportRunCommand = (args) => {
|
|
73
|
+
const [runId, flag, output] = args;
|
|
74
|
+
if (runId === undefined ||
|
|
75
|
+
runId.startsWith("-") ||
|
|
76
|
+
!(args.length === 1 || (args.length === 3 && (flag === "--output" || flag === "-o"))))
|
|
77
|
+
return Effect.fail(usageError());
|
|
78
|
+
return Schema.decodeUnknownEffect(ExportRunCommand)({
|
|
79
|
+
_tag: "ExportRunCommand",
|
|
80
|
+
runId,
|
|
81
|
+
output: Option.fromUndefinedOr(output),
|
|
82
|
+
}).pipe(Effect.mapError(() => usageError()));
|
|
83
|
+
};
|
|
84
|
+
const backupCommand = (args) => {
|
|
85
|
+
const [output] = args;
|
|
86
|
+
if (args.length !== 1 || output === undefined || output.startsWith("-"))
|
|
87
|
+
return Effect.fail(usageError());
|
|
88
|
+
return Schema.decodeUnknownEffect(BackupCommand)({ _tag: "BackupCommand", output }).pipe(Effect.mapError(() => usageError()));
|
|
89
|
+
};
|
|
90
|
+
const upCommand = (args, environment) => Effect.gen(function* () {
|
|
91
|
+
let port = Option.none();
|
|
92
|
+
let allowVolatileInstance = Option.exists(environment.allowVolatileInstance, (v) => v === "1");
|
|
93
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
94
|
+
const arg = args[index];
|
|
95
|
+
if (arg === "--port" || arg === "-p") {
|
|
96
|
+
const value = args[index + 1];
|
|
97
|
+
if (value === undefined)
|
|
98
|
+
return yield* usageError();
|
|
99
|
+
port = Option.some(value);
|
|
100
|
+
index += 1;
|
|
101
|
+
}
|
|
102
|
+
else if (arg?.startsWith("--port=")) {
|
|
103
|
+
port = Option.some(arg.slice("--port=".length));
|
|
104
|
+
}
|
|
105
|
+
else if (arg === ALLOW_VOLATILE_FLAG) {
|
|
106
|
+
allowVolatileInstance = true;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
return yield* usageError();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const resolvedPort = yield* Option.match(port, {
|
|
113
|
+
onNone: () => Option.match(environment.port, {
|
|
45
114
|
onNone: () => Effect.succeed(Port.make(DEFAULT_PORT)),
|
|
46
115
|
onSome: (value) => decodePort("USINE_PORT", value),
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return decodePort("--port", args[0].slice("--port=".length));
|
|
55
|
-
}
|
|
56
|
-
return Effect.fail(usageError());
|
|
57
|
-
};
|
|
58
|
-
/** Parse process arguments and environment into one validated CLI command. */
|
|
59
|
-
export const parseCli = Effect.fn("Cli.parse")((args, environmentPort) => {
|
|
116
|
+
}),
|
|
117
|
+
onSome: (value) => decodePort("--port", value),
|
|
118
|
+
});
|
|
119
|
+
return new UpCommand({ port: resolvedPort, allowVolatileInstance });
|
|
120
|
+
});
|
|
121
|
+
/** Parses process arguments and the environment into one validated CLI command. */
|
|
122
|
+
export const parseCli = Effect.fn("Cli.parse")((args, environment) => {
|
|
60
123
|
if ((args.length === 1 && (args[0] === "--help" || args[0] === "-h")) ||
|
|
61
|
-
(args.length === 2 &&
|
|
124
|
+
(args.length === 2 &&
|
|
125
|
+
(args[0] === "up" || args[0] === "export-run" || args[0] === "backup") &&
|
|
126
|
+
(args[1] === "--help" || args[1] === "-h"))) {
|
|
62
127
|
return Effect.succeed(new HelpCommand());
|
|
63
128
|
}
|
|
64
129
|
if (args.length === 1 && (args[0] === "--version" || args[0] === "-v")) {
|
|
65
130
|
return Effect.succeed(new VersionCommand());
|
|
66
131
|
}
|
|
132
|
+
if (args[0] === "backup")
|
|
133
|
+
return backupCommand(args.slice(1));
|
|
134
|
+
if (args[0] === "export-run")
|
|
135
|
+
return exportRunCommand(args.slice(1));
|
|
67
136
|
if (args[0] !== "up")
|
|
68
137
|
return Effect.fail(usageError());
|
|
69
|
-
return
|
|
138
|
+
return upCommand(args.slice(1), environment);
|
|
70
139
|
});
|
|
140
|
+
/** Directories the OS may clear: `os.tmpdir()`, `$TMPDIR`, and the usual temp locations. */
|
|
141
|
+
export const volatileRoots = (environmentTmpdir) => [
|
|
142
|
+
...new Set([
|
|
143
|
+
tmpdir(),
|
|
144
|
+
...Option.toArray(environmentTmpdir),
|
|
145
|
+
"/tmp",
|
|
146
|
+
"/private/tmp",
|
|
147
|
+
"/var/folders",
|
|
148
|
+
]),
|
|
149
|
+
]
|
|
150
|
+
.filter((root) => root.length > 0)
|
|
151
|
+
.map((root) => resolve(root));
|
|
152
|
+
const isUnder = (directory, root) => directory === root || directory.startsWith(root.endsWith(sep) ? root : `${root}${sep}`);
|
|
153
|
+
/** Returns the volatile root the directory sits under, if any. Paths are compared as given, with symlinks unresolved. */
|
|
154
|
+
export const volatileRoot = (directory, roots) => {
|
|
155
|
+
const resolved = resolve(directory);
|
|
156
|
+
return Option.fromNullishOr(roots.find((root) => isUnder(resolved, root)));
|
|
157
|
+
};
|
|
71
158
|
const PackageMetadataFromJson = Schema.fromJsonString(Schema.Struct({ version: Schema.NonEmptyString }));
|
|
72
|
-
/**
|
|
159
|
+
/** Reads the version of this installed server from its package.json. */
|
|
73
160
|
export const packageVersion = Effect.fn("Cli.packageVersion")(function* () {
|
|
74
161
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
75
162
|
const packagePath = fileURLToPath(new URL("../package.json", import.meta.url));
|
|
@@ -80,7 +167,7 @@ export const packageVersion = Effect.fn("Cli.packageVersion")(function* () {
|
|
|
80
167
|
return metadata.version;
|
|
81
168
|
});
|
|
82
169
|
const AddressInUse = Schema.Struct({ code: Schema.Literal("EADDRINUSE") });
|
|
83
|
-
/**
|
|
170
|
+
/** Maps a bind failure to the CLI's startup error, so an address already in use is reported as such. */
|
|
84
171
|
export const serverStartError = (port, error) => Schema.is(AddressInUse)(error.cause)
|
|
85
172
|
? new PortInUseError({ port })
|
|
86
173
|
: new ServerStartError({ port, cause: error.cause });
|
|
@@ -92,7 +179,7 @@ const browserCommand = (url) => {
|
|
|
92
179
|
}
|
|
93
180
|
return { command: "xdg-open", args: [url] };
|
|
94
181
|
};
|
|
95
|
-
/**
|
|
182
|
+
/** Opens the setup page in a browser; call it only after the HTTP server has bound. */
|
|
96
183
|
export const openBrowser = Effect.fn("Cli.openBrowser")(function* (url, timeout = BROWSER_OPEN_TIMEOUT) {
|
|
97
184
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
98
185
|
const { command, args } = browserCommand(url);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAG5E,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC;AAClC,MAAM,CAAC,MAAM,oBAAoB,GAAG,WAAW,CAAC;AAEhD,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAClC,MAAM,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CACtF,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;AAGnC,MAAM,cAAc,GAAG,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,SAAS,GAAG
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Effect, FileSystem, Option, Path, Schema } from "effect";
|
|
2
|
+
/** JSON encoding preserves timestamps, optional values, and typed Attempt outcomes. */
|
|
3
|
+
export declare const RunEvidenceFromJson: Schema.fromJsonString<Schema.toCodecJson<Schema.Struct<{
|
|
4
|
+
readonly snapshot: typeof import("@usine/engine/run-reader").RunSnapshot;
|
|
5
|
+
readonly transcript: Schema.$Array<typeof import("@usine/engine/transcript").TranscriptEntry>;
|
|
6
|
+
readonly version: Schema.Literal<1>;
|
|
7
|
+
readonly exportedAt: Schema.DateTimeUtc;
|
|
8
|
+
}>>>;
|
|
9
|
+
declare const RunExportError_base: Schema.Class<RunExportError, Schema.TaggedStruct<"RunExportError", {
|
|
10
|
+
readonly runId: Schema.brand<Schema.NonEmptyString, "RunId">;
|
|
11
|
+
readonly operation: Schema.Literals<readonly ["read", "encode", "write"]>;
|
|
12
|
+
readonly path: Schema.String;
|
|
13
|
+
readonly reason: Schema.String;
|
|
14
|
+
readonly cause: Schema.Defect;
|
|
15
|
+
}>, import("effect/Cause").YieldableError>;
|
|
16
|
+
/** Reading, encoding, or writing Run evidence failed; no successful export was reported. */
|
|
17
|
+
export declare class RunExportError extends RunExportError_base {
|
|
18
|
+
}
|
|
19
|
+
/** Exports from the current instance without loading GitHub credentials or starting execution. */
|
|
20
|
+
export declare const exportRun: (runId: string & import("effect/Brand").Brand<"RunId">, output: Option.Option<string>) => Effect.Effect<void, RunExportError | import("@usine/engine/engine").RunNotFoundError, FileSystem.FileSystem | Path.Path>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=export-run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-run.d.ts","sourceRoot":"","sources":["../src/export-run.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,MAAM,EAAE,UAAU,EAAS,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE5F,uFAAuF;AACvF,eAAO,MAAM,mBAAmB;;;;;IAS/B,CAAC;;;;;;;;AAEF,4FAA4F;AAC5F,qBAAa,cAAe,SAAQ,mBAQlC;CAAG;AAoDL,kGAAkG;AAClG,eAAO,MAAM,SAAS,oNA2CrB,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { InstanceDirectory } from "@usine/core/instance";
|
|
2
|
+
import { RunId } from "@usine/core/run";
|
|
3
|
+
import { runReaderLayer } from "@usine/engine/local-sqlite";
|
|
4
|
+
import { RunEvidence, RunReader } from "@usine/engine/run-reader";
|
|
5
|
+
import { Console, DateTime, Effect, FileSystem, Match, Option, Path, Schema } from "effect";
|
|
6
|
+
/** JSON encoding preserves timestamps, optional values, and typed Attempt outcomes. */
|
|
7
|
+
export const RunEvidenceFromJson = Schema.fromJsonString(Schema.toCodecJson(Schema.Struct({
|
|
8
|
+
version: Schema.Literal(1),
|
|
9
|
+
exportedAt: Schema.DateTimeUtc,
|
|
10
|
+
...RunEvidence.fields,
|
|
11
|
+
})), { space: 2 });
|
|
12
|
+
/** Reading, encoding, or writing Run evidence failed; no successful export was reported. */
|
|
13
|
+
export class RunExportError extends Schema.TaggedError("@usine/server/RunExportError")("RunExportError", {
|
|
14
|
+
runId: RunId,
|
|
15
|
+
operation: Schema.Literals(["read", "encode", "write"]),
|
|
16
|
+
path: Schema.String,
|
|
17
|
+
reason: Schema.String,
|
|
18
|
+
cause: Schema.Defect(),
|
|
19
|
+
}) {
|
|
20
|
+
}
|
|
21
|
+
/** Writes a complete evidence file without overwriting an existing destination. */
|
|
22
|
+
const writeRunEvidence = Effect.fn("RunEvidence.write")(function* (evidence, output) {
|
|
23
|
+
const runId = evidence.snapshot.run.id;
|
|
24
|
+
yield* Effect.annotateCurrentSpan({ runId, output });
|
|
25
|
+
const json = yield* Schema.encodeEffect(RunEvidenceFromJson)({
|
|
26
|
+
version: 1,
|
|
27
|
+
exportedAt: yield* DateTime.now,
|
|
28
|
+
...evidence,
|
|
29
|
+
}).pipe(Effect.mapError((cause) => new RunExportError({ runId, operation: "encode", path: output, reason: cause._tag, cause })));
|
|
30
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
31
|
+
const path = yield* Path.Path;
|
|
32
|
+
yield* Effect.scoped(Effect.gen(function* () {
|
|
33
|
+
const temporary = yield* fileSystem.makeTempDirectoryScoped({
|
|
34
|
+
directory: path.dirname(output),
|
|
35
|
+
prefix: ".usine-export-",
|
|
36
|
+
});
|
|
37
|
+
const staged = path.join(temporary, "evidence.json");
|
|
38
|
+
yield* fileSystem.writeFileString(staged, `${json}\n`, { mode: 0o600 });
|
|
39
|
+
// Publish the complete file atomically. A hard link refuses an existing destination.
|
|
40
|
+
yield* fileSystem.link(staged, output);
|
|
41
|
+
})).pipe(Effect.mapError((cause) => new RunExportError({
|
|
42
|
+
runId,
|
|
43
|
+
operation: "write",
|
|
44
|
+
path: output,
|
|
45
|
+
reason: cause.reason._tag,
|
|
46
|
+
cause,
|
|
47
|
+
})));
|
|
48
|
+
yield* Effect.logInfo("Run evidence exported", {
|
|
49
|
+
runId,
|
|
50
|
+
output,
|
|
51
|
+
attempts: evidence.snapshot.attempts.length,
|
|
52
|
+
transcriptRows: evidence.transcript.length,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
/** Exports from the current instance without loading GitHub credentials or starting execution. */
|
|
56
|
+
export const exportRun = Effect.fn("Cli.exportRun")(function* (runId, output) {
|
|
57
|
+
const directory = InstanceDirectory.make(process.cwd());
|
|
58
|
+
const path = yield* Path.Path;
|
|
59
|
+
const destination = path.resolve(Option.getOrElse(output, () => `run-${encodeURIComponent(runId)}.json`));
|
|
60
|
+
yield* Effect.annotateCurrentSpan({ runId, instanceDirectory: directory, output: destination });
|
|
61
|
+
const databasePath = path.join(directory, ".usine", "runtime.sqlite");
|
|
62
|
+
const reader = runReaderLayer(directory);
|
|
63
|
+
const evidence = yield* Effect.flatMap(RunReader, (reader) => reader.evidence(runId)).pipe(Effect.provide(reader), Effect.mapError((cause) => cause._tag === "RunNotFoundError"
|
|
64
|
+
? cause
|
|
65
|
+
: new RunExportError({
|
|
66
|
+
runId,
|
|
67
|
+
operation: "read",
|
|
68
|
+
path: databasePath,
|
|
69
|
+
reason: cause._tag,
|
|
70
|
+
cause,
|
|
71
|
+
})));
|
|
72
|
+
yield* writeRunEvidence(evidence, destination);
|
|
73
|
+
yield* Console.log(`Exported Run ${runId} to ${destination}`);
|
|
74
|
+
}, Effect.tapError((error) => Effect.logWarning("Run evidence export failed", Match.valueTags(error, {
|
|
75
|
+
RunNotFoundError: ({ runId, _tag }) => ({ runId, errorTag: _tag }),
|
|
76
|
+
RunExportError: ({ runId, _tag, operation, path, reason, cause }) => ({
|
|
77
|
+
runId,
|
|
78
|
+
errorTag: _tag,
|
|
79
|
+
operation,
|
|
80
|
+
path,
|
|
81
|
+
reason,
|
|
82
|
+
cause,
|
|
83
|
+
}),
|
|
84
|
+
}))));
|
|
85
|
+
//# sourceMappingURL=export-run.js.map
|