@cydm/happy-elves 0.1.0-beta.31 → 0.1.0-beta.310
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/apps/cli/dist/commands/app.js +10 -0
- package/apps/cli/dist/commands/daemon.js +92 -4
- package/apps/cli/dist/commands/gateway.d.ts +2 -0
- package/apps/cli/dist/commands/gateway.js +429 -0
- package/apps/cli/dist/commands/lib/args.js +49 -0
- package/apps/cli/dist/commands/lib/bootstrap-daemon.d.ts +2 -2
- package/apps/cli/dist/commands/lib/bootstrap-daemon.js +2 -2
- package/apps/cli/dist/commands/lib/doctor.d.ts +11 -0
- package/apps/cli/dist/commands/lib/doctor.js +276 -11
- package/apps/cli/dist/commands/lib/gateway-store.d.ts +38 -0
- package/apps/cli/dist/commands/lib/gateway-store.js +33 -0
- package/apps/cli/dist/commands/lib/index.d.ts +4 -2
- package/apps/cli/dist/commands/lib/index.js +2 -0
- package/apps/cli/dist/commands/lib/json.d.ts +2 -2
- package/apps/cli/dist/commands/lib/json.js +5 -2
- package/apps/cli/dist/commands/lib/local-daemon.d.ts +1 -0
- package/apps/cli/dist/commands/lib/local-daemon.js +14 -0
- package/apps/cli/dist/commands/lib/paths.d.ts +2 -0
- package/apps/cli/dist/commands/lib/paths.js +2 -0
- package/apps/cli/dist/commands/lib/relay-db-audit.d.ts +37 -0
- package/apps/cli/dist/commands/lib/relay-db-audit.js +300 -0
- package/apps/cli/dist/commands/lib/relay-http.d.ts +1 -1
- package/apps/cli/dist/commands/lib/scope.d.ts +1 -1
- package/apps/cli/dist/commands/lib/session-output.d.ts +15 -1
- package/apps/cli/dist/commands/lib/session-output.js +214 -6
- package/apps/cli/dist/commands/lib/session-view.d.ts +2 -2
- package/apps/cli/dist/commands/lib/status.js +5 -1
- package/apps/cli/dist/commands/lib/types.d.ts +4 -2
- package/apps/cli/dist/commands/lib/usage.js +123 -10
- package/apps/cli/dist/commands/lib/workspace.d.ts +2 -2
- package/apps/cli/dist/commands/lib/workspace.js +63 -10
- package/apps/cli/dist/commands/machine.js +50 -9
- package/apps/cli/dist/commands/memory.d.ts +2 -0
- package/apps/cli/dist/commands/memory.js +179 -0
- package/apps/cli/dist/commands/relay.js +29 -2
- package/apps/cli/dist/commands/release.d.ts +2 -0
- package/apps/cli/dist/commands/release.js +197 -0
- package/apps/cli/dist/commands/remote.js +10 -2
- package/apps/cli/dist/commands/schedule.d.ts +2 -0
- package/apps/cli/dist/commands/schedule.js +273 -0
- package/apps/cli/dist/commands/session.js +517 -5
- package/apps/cli/dist/commands/turn.js +225 -9
- package/apps/cli/dist/commands/workspace.d.ts +2 -0
- package/apps/cli/dist/commands/workspace.js +68 -0
- package/apps/cli/package.json +6 -0
- package/apps/daemon/dist/gateway/adapters.d.ts +38 -0
- package/apps/daemon/dist/gateway/adapters.js +2 -0
- package/apps/daemon/dist/gateway/feishu.d.ts +65 -0
- package/apps/daemon/dist/gateway/feishu.js +493 -0
- package/apps/daemon/dist/gateway/format.d.ts +2 -0
- package/apps/daemon/dist/gateway/format.js +19 -0
- package/apps/daemon/dist/gateway/handler.d.ts +7 -0
- package/apps/daemon/dist/gateway/handler.js +151 -0
- package/apps/daemon/dist/gateway/runtime.d.ts +33 -0
- package/apps/daemon/dist/gateway/runtime.js +850 -0
- package/apps/daemon/dist/gateway/store.d.ts +92 -0
- package/apps/daemon/dist/gateway/store.js +268 -0
- package/apps/daemon/dist/memory/handler.d.ts +7 -0
- package/apps/daemon/dist/memory/handler.js +105 -0
- package/apps/daemon/dist/memory/manager.d.ts +44 -0
- package/apps/daemon/dist/memory/manager.js +359 -0
- package/apps/daemon/dist/paths.d.ts +3 -0
- package/apps/daemon/dist/paths.js +3 -0
- package/apps/daemon/dist/relay/admission.d.ts +30 -0
- package/apps/daemon/dist/relay/admission.js +31 -0
- package/apps/daemon/dist/relay/connection.js +37 -1
- package/apps/daemon/dist/relay/devtools.d.ts +1 -1
- package/apps/daemon/dist/relay/register.js +2 -0
- package/apps/daemon/dist/relay/send.d.ts +2 -2
- package/apps/daemon/dist/relay/send.js +2 -0
- package/apps/daemon/dist/relay-http.d.ts +1 -1
- package/apps/daemon/dist/runtime/external-provider.d.ts +1 -1
- package/apps/daemon/dist/runtime/external-provider.js +187 -17
- package/apps/daemon/dist/runtime.d.ts +1 -2
- package/apps/daemon/dist/runtime.js +0 -3
- package/apps/daemon/dist/schedule/handler.d.ts +9 -0
- package/apps/daemon/dist/schedule/handler.js +148 -0
- package/apps/daemon/dist/schedule/runner.d.ts +21 -0
- package/apps/daemon/dist/schedule/runner.js +547 -0
- package/apps/daemon/dist/schedule/store.d.ts +9 -0
- package/apps/daemon/dist/schedule/store.js +143 -0
- package/apps/daemon/dist/session/create-session.d.ts +1 -1
- package/apps/daemon/dist/session/directory.d.ts +1 -1
- package/apps/daemon/dist/session/events.d.ts +15 -2
- package/apps/daemon/dist/session/events.js +76 -24
- package/apps/daemon/dist/session/file-preview.d.ts +1 -1
- package/apps/daemon/dist/session/lifecycle.d.ts +26 -3
- package/apps/daemon/dist/session/lifecycle.js +161 -22
- package/apps/daemon/dist/session/metadata.d.ts +2 -2
- package/apps/daemon/dist/session/metadata.js +42 -1
- package/apps/daemon/dist/session/primitives.d.ts +1 -1
- package/apps/daemon/dist/session/primitives.js +37 -6
- package/apps/daemon/dist/session/prompt.d.ts +28 -1
- package/apps/daemon/dist/session/prompt.js +340 -5
- package/apps/daemon/dist/session/reconcile.d.ts +3 -0
- package/apps/daemon/dist/session/reconcile.js +235 -0
- package/apps/daemon/dist/session/runtime-handle.d.ts +1 -1
- package/apps/daemon/dist/start.js +5 -1
- package/apps/daemon/dist/state.d.ts +2 -2
- package/apps/daemon/dist/turn-coordinator.d.ts +1 -0
- package/apps/daemon/dist/turn-coordinator.js +4 -0
- package/apps/daemon/dist/types.d.ts +16 -1
- package/apps/daemon/package.json +3 -25
- package/apps/relay/dist/connections.d.ts +2 -0
- package/apps/relay/dist/controller-handlers.d.ts +42 -2
- package/apps/relay/dist/controller-handlers.js +349 -37
- package/apps/relay/dist/db.js +296 -2
- package/apps/relay/dist/errors.d.ts +2 -1
- package/apps/relay/dist/errors.js +3 -1
- package/apps/relay/dist/http-routes.js +659 -33
- package/apps/relay/dist/http-schemas.d.ts +156 -0
- package/apps/relay/dist/http-schemas.js +85 -0
- package/apps/relay/dist/index.js +31 -1
- package/apps/relay/dist/machine-handlers.d.ts +15 -7
- package/apps/relay/dist/machine-handlers.js +567 -27
- package/apps/relay/dist/projections.d.ts +1 -1
- package/apps/relay/dist/projections.js +13 -0
- package/apps/relay/dist/relay-context.d.ts +41 -3
- package/apps/relay/dist/relay-context.js +244 -19
- package/apps/relay/dist/repositories.d.ts +2 -2
- package/apps/relay/dist/repositories.js +28 -1
- package/apps/relay/dist/runtime-bindings.d.ts +25 -0
- package/apps/relay/dist/runtime-bindings.js +49 -0
- package/apps/relay/dist/scope.d.ts +1 -1
- package/apps/relay/dist/types.d.ts +71 -1
- package/apps/relay/dist/websocket.js +2 -0
- package/package.json +5 -11
- package/packages/agent-sdk/dist/index.d.ts +80 -0
- package/packages/agent-sdk/dist/index.js +16 -0
- package/packages/client/dist/account.d.ts +35 -2
- package/packages/client/dist/account.js +98 -1
- package/packages/client/dist/client.d.ts +59 -6
- package/packages/client/dist/client.js +312 -58
- package/packages/client/dist/index.d.ts +1 -1
- package/packages/client/dist/parsers.d.ts +28 -2
- package/packages/client/dist/parsers.js +167 -0
- package/packages/client/dist/transport.d.ts +21 -1
- package/packages/client/dist/transport.js +69 -6
- package/packages/client/dist/types.d.ts +177 -1
- package/packages/client/dist/validation.d.ts +1 -1
- package/packages/runtime/dist/index.d.ts +66 -0
- package/packages/runtime-acpx/dist/index.d.ts +1 -1
- package/packages/runtime-acpx/dist/index.js +8 -0
- package/packages/runtime-cli/dist/claude-history.d.ts +1 -2
- package/packages/runtime-cli/dist/claude-history.js +0 -3
- package/packages/runtime-cli/dist/claude-session-store.d.ts +0 -1
- package/packages/runtime-cli/dist/claude-session-store.js +1 -1
- package/packages/runtime-cli/dist/claude-turn.d.ts +2 -1
- package/packages/runtime-cli/dist/claude-turn.js +29 -9
- package/packages/runtime-cli/dist/codex-app-server.d.ts +8 -3
- package/packages/runtime-cli/dist/codex-app-server.js +122 -25
- package/packages/runtime-cli/dist/codex-history.d.ts +1 -2
- package/packages/runtime-cli/dist/codex-history.js +11 -5
- package/packages/runtime-cli/dist/codex-protocol.d.ts +2 -2
- package/packages/runtime-cli/dist/codex-protocol.js +4 -4
- package/packages/runtime-cli/dist/history-merge.d.ts +1 -1
- package/packages/runtime-cli/dist/index.d.ts +1 -1
- package/packages/runtime-cli/dist/index.js +108 -2
- package/packages/runtime-cli/dist/permissions.d.ts +1 -1
- package/packages/runtime-cli/dist/session-store.d.ts +2 -1
- package/packages/runtime-cli/dist/session-store.js +9 -8
- package/packages/shared/dist/index.d.ts +2 -0
- package/packages/shared/dist/index.js +2 -0
- package/packages/shared/dist/protocol-schemas.d.ts +1077 -0
- package/packages/shared/dist/protocol-schemas.js +273 -0
- package/packages/shared/dist/protocol-types.d.ts +371 -3
- package/packages/shared/dist/protocol.d.ts +181 -2
- package/packages/shared/dist/protocol.js +197 -1
- package/packages/shared/dist/session-tags.d.ts +12 -0
- package/packages/shared/dist/session-tags.js +50 -0
- package/apps/cli/dist/commands/account.js.map +0 -1
- package/apps/cli/dist/commands/app.js.map +0 -1
- package/apps/cli/dist/commands/collect.js.map +0 -1
- package/apps/cli/dist/commands/command.js.map +0 -1
- package/apps/cli/dist/commands/config.js.map +0 -1
- package/apps/cli/dist/commands/daemon.js.map +0 -1
- package/apps/cli/dist/commands/lib/args.js.map +0 -1
- package/apps/cli/dist/commands/lib/audit.js.map +0 -1
- package/apps/cli/dist/commands/lib/bootstrap-config.js.map +0 -1
- package/apps/cli/dist/commands/lib/bootstrap-daemon.js.map +0 -1
- package/apps/cli/dist/commands/lib/bootstrap-output.js.map +0 -1
- package/apps/cli/dist/commands/lib/bootstrap.js.map +0 -1
- package/apps/cli/dist/commands/lib/config.js.map +0 -1
- package/apps/cli/dist/commands/lib/doctor.js.map +0 -1
- package/apps/cli/dist/commands/lib/exit.js.map +0 -1
- package/apps/cli/dist/commands/lib/index.js.map +0 -1
- package/apps/cli/dist/commands/lib/json.js.map +0 -1
- package/apps/cli/dist/commands/lib/local-daemon.js.map +0 -1
- package/apps/cli/dist/commands/lib/loop-store.js.map +0 -1
- package/apps/cli/dist/commands/lib/paths.js.map +0 -1
- package/apps/cli/dist/commands/lib/relay-http.js.map +0 -1
- package/apps/cli/dist/commands/lib/scope.js.map +0 -1
- package/apps/cli/dist/commands/lib/session-output.js.map +0 -1
- package/apps/cli/dist/commands/lib/session-view.js.map +0 -1
- package/apps/cli/dist/commands/lib/status.js.map +0 -1
- package/apps/cli/dist/commands/lib/types.js.map +0 -1
- package/apps/cli/dist/commands/lib/usage.js.map +0 -1
- package/apps/cli/dist/commands/lib/workspace.js.map +0 -1
- package/apps/cli/dist/commands/loop.js.map +0 -1
- package/apps/cli/dist/commands/machine.js.map +0 -1
- package/apps/cli/dist/commands/relay.js.map +0 -1
- package/apps/cli/dist/commands/remote.js.map +0 -1
- package/apps/cli/dist/commands/session.js.map +0 -1
- package/apps/cli/dist/commands/token.js.map +0 -1
- package/apps/cli/dist/commands/turn.js.map +0 -1
- package/apps/cli/dist/errors.js.map +0 -1
- package/apps/cli/dist/index.js.map +0 -1
- package/apps/daemon/dist/app.js.map +0 -1
- package/apps/daemon/dist/args.js.map +0 -1
- package/apps/daemon/dist/audit.js.map +0 -1
- package/apps/daemon/dist/cli.js.map +0 -1
- package/apps/daemon/dist/config.js.map +0 -1
- package/apps/daemon/dist/errors.js.map +0 -1
- package/apps/daemon/dist/loop/runner.js.map +0 -1
- package/apps/daemon/dist/loop/store.js.map +0 -1
- package/apps/daemon/dist/pair.js.map +0 -1
- package/apps/daemon/dist/paths.js.map +0 -1
- package/apps/daemon/dist/process.js.map +0 -1
- package/apps/daemon/dist/relay/connection.js.map +0 -1
- package/apps/daemon/dist/relay/devtools.js.map +0 -1
- package/apps/daemon/dist/relay/register.js.map +0 -1
- package/apps/daemon/dist/relay/send.js.map +0 -1
- package/apps/daemon/dist/relay-http.js.map +0 -1
- package/apps/daemon/dist/runtime/external-provider.js.map +0 -1
- package/apps/daemon/dist/runtime.js.map +0 -1
- package/apps/daemon/dist/session/create-session.js.map +0 -1
- package/apps/daemon/dist/session/directory.js.map +0 -1
- package/apps/daemon/dist/session/events.js.map +0 -1
- package/apps/daemon/dist/session/file-preview.js.map +0 -1
- package/apps/daemon/dist/session/lifecycle.js.map +0 -1
- package/apps/daemon/dist/session/metadata.js.map +0 -1
- package/apps/daemon/dist/session/primitives.js.map +0 -1
- package/apps/daemon/dist/session/prompt.js.map +0 -1
- package/apps/daemon/dist/session/runtime-handle.js.map +0 -1
- package/apps/daemon/dist/start.js.map +0 -1
- package/apps/daemon/dist/state.js.map +0 -1
- package/apps/daemon/dist/turn-coordinator.js.map +0 -1
- package/apps/daemon/dist/types.js.map +0 -1
- package/apps/daemon/dist/utils.js.map +0 -1
- package/apps/relay/dist/auth.js.map +0 -1
- package/apps/relay/dist/connections.js.map +0 -1
- package/apps/relay/dist/controller-handlers.js.map +0 -1
- package/apps/relay/dist/db.js.map +0 -1
- package/apps/relay/dist/errors.js.map +0 -1
- package/apps/relay/dist/http-routes.js.map +0 -1
- package/apps/relay/dist/http-schemas.js.map +0 -1
- package/apps/relay/dist/index.js.map +0 -1
- package/apps/relay/dist/machine-handlers.js.map +0 -1
- package/apps/relay/dist/projections.js.map +0 -1
- package/apps/relay/dist/relay-context.js.map +0 -1
- package/apps/relay/dist/repositories.js.map +0 -1
- package/apps/relay/dist/retention.js.map +0 -1
- package/apps/relay/dist/scope.js.map +0 -1
- package/apps/relay/dist/security.js.map +0 -1
- package/apps/relay/dist/types.js.map +0 -1
- package/apps/relay/dist/websocket.js.map +0 -1
- package/apps/relay/package.json +0 -29
- package/packages/agent-sdk/dist/index.d.ts.map +0 -1
- package/packages/agent-sdk/dist/index.js.map +0 -1
- package/packages/agent-sdk/package.json +0 -20
- package/packages/client/dist/account.d.ts.map +0 -1
- package/packages/client/dist/account.js.map +0 -1
- package/packages/client/dist/client.d.ts.map +0 -1
- package/packages/client/dist/client.js.map +0 -1
- package/packages/client/dist/errors.d.ts.map +0 -1
- package/packages/client/dist/errors.js.map +0 -1
- package/packages/client/dist/http.d.ts.map +0 -1
- package/packages/client/dist/http.js.map +0 -1
- package/packages/client/dist/index.d.ts.map +0 -1
- package/packages/client/dist/index.js.map +0 -1
- package/packages/client/dist/parsers.d.ts.map +0 -1
- package/packages/client/dist/parsers.js.map +0 -1
- package/packages/client/dist/transport.d.ts.map +0 -1
- package/packages/client/dist/transport.js.map +0 -1
- package/packages/client/dist/types.d.ts.map +0 -1
- package/packages/client/dist/types.js.map +0 -1
- package/packages/client/dist/validation.d.ts.map +0 -1
- package/packages/client/dist/validation.js.map +0 -1
- package/packages/client/package.json +0 -22
- package/packages/pie-provider/dist/index.d.ts.map +0 -1
- package/packages/pie-provider/dist/index.js.map +0 -1
- package/packages/pie-provider/package.json +0 -26
- package/packages/runtime/dist/index.d.ts.map +0 -1
- package/packages/runtime/dist/index.js.map +0 -1
- package/packages/runtime/package.json +0 -19
- package/packages/runtime-acpx/dist/index.d.ts.map +0 -1
- package/packages/runtime-acpx/dist/index.js.map +0 -1
- package/packages/runtime-acpx/package.json +0 -23
- package/packages/runtime-cli/dist/async-queue.d.ts.map +0 -1
- package/packages/runtime-cli/dist/async-queue.js.map +0 -1
- package/packages/runtime-cli/dist/claude-history.d.ts.map +0 -1
- package/packages/runtime-cli/dist/claude-history.js.map +0 -1
- package/packages/runtime-cli/dist/claude-json.d.ts.map +0 -1
- package/packages/runtime-cli/dist/claude-json.js.map +0 -1
- package/packages/runtime-cli/dist/claude-rename.d.ts.map +0 -1
- package/packages/runtime-cli/dist/claude-rename.js.map +0 -1
- package/packages/runtime-cli/dist/claude-session-store.d.ts.map +0 -1
- package/packages/runtime-cli/dist/claude-session-store.js.map +0 -1
- package/packages/runtime-cli/dist/claude-turn.d.ts.map +0 -1
- package/packages/runtime-cli/dist/claude-turn.js.map +0 -1
- package/packages/runtime-cli/dist/codex-app-server.d.ts.map +0 -1
- package/packages/runtime-cli/dist/codex-app-server.js.map +0 -1
- package/packages/runtime-cli/dist/codex-approvals.d.ts.map +0 -1
- package/packages/runtime-cli/dist/codex-approvals.js.map +0 -1
- package/packages/runtime-cli/dist/codex-history.d.ts.map +0 -1
- package/packages/runtime-cli/dist/codex-history.js.map +0 -1
- package/packages/runtime-cli/dist/codex-json-rpc.d.ts.map +0 -1
- package/packages/runtime-cli/dist/codex-json-rpc.js.map +0 -1
- package/packages/runtime-cli/dist/codex-lifecycle.d.ts.map +0 -1
- package/packages/runtime-cli/dist/codex-lifecycle.js.map +0 -1
- package/packages/runtime-cli/dist/codex-protocol.d.ts.map +0 -1
- package/packages/runtime-cli/dist/codex-protocol.js.map +0 -1
- package/packages/runtime-cli/dist/command-resolver.d.ts.map +0 -1
- package/packages/runtime-cli/dist/command-resolver.js.map +0 -1
- package/packages/runtime-cli/dist/history-merge.d.ts.map +0 -1
- package/packages/runtime-cli/dist/history-merge.js.map +0 -1
- package/packages/runtime-cli/dist/index.d.ts.map +0 -1
- package/packages/runtime-cli/dist/index.js.map +0 -1
- package/packages/runtime-cli/dist/permissions.d.ts.map +0 -1
- package/packages/runtime-cli/dist/permissions.js.map +0 -1
- package/packages/runtime-cli/dist/session-store.d.ts.map +0 -1
- package/packages/runtime-cli/dist/session-store.js.map +0 -1
- package/packages/runtime-cli/package.json +0 -22
- package/packages/shared/dist/args.d.ts.map +0 -1
- package/packages/shared/dist/args.js.map +0 -1
- package/packages/shared/dist/crypto.d.ts.map +0 -1
- package/packages/shared/dist/crypto.js.map +0 -1
- package/packages/shared/dist/ids.d.ts.map +0 -1
- package/packages/shared/dist/ids.js.map +0 -1
- package/packages/shared/dist/index.d.ts.map +0 -1
- package/packages/shared/dist/index.js.map +0 -1
- package/packages/shared/dist/protocol-schemas.d.ts.map +0 -1
- package/packages/shared/dist/protocol-schemas.js.map +0 -1
- package/packages/shared/dist/protocol-types.d.ts.map +0 -1
- package/packages/shared/dist/protocol-types.js.map +0 -1
- package/packages/shared/dist/protocol.d.ts.map +0 -1
- package/packages/shared/dist/protocol.js.map +0 -1
- package/packages/shared/dist/session-name.d.ts.map +0 -1
- package/packages/shared/dist/session-name.js.map +0 -1
- package/packages/shared/dist/session-state.d.ts.map +0 -1
- package/packages/shared/dist/session-state.js.map +0 -1
- package/packages/shared/package.json +0 -24
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EncryptedSessionEvent, MachineSnapshot, SessionSnapshot } from "
|
|
1
|
+
import type { EncryptedSessionEvent, MachineSnapshot, SessionSnapshot } from "../../../packages/shared/dist/index.js";
|
|
2
2
|
import type { EventRow, MachineRow, SessionRow } from "./types.js";
|
|
3
3
|
export declare function parseJson<T>(value: string | null | undefined, fallback: T): T;
|
|
4
4
|
export declare function normalizeMachineCapabilities(value: unknown): MachineSnapshot["capabilities"];
|
|
@@ -89,12 +89,25 @@ export function sessionSnapshot(row, capabilitiesForMachine, historyModelForMach
|
|
|
89
89
|
encryptedMetadata: parseJson(row.encrypted_metadata, undefined),
|
|
90
90
|
currentHead: row.current_head ?? undefined,
|
|
91
91
|
lastTurnId: row.last_turn_id ?? undefined,
|
|
92
|
+
headBasis: sessionHeadBasis(row),
|
|
92
93
|
sourceSessionId: row.source_session_id ?? undefined,
|
|
93
94
|
sourceCheckpointId: row.source_checkpoint_id ?? undefined,
|
|
94
95
|
historyModel: historyModelForMachine?.(row.account_id, row.machine_id, row.agent),
|
|
95
96
|
capabilities: capabilitiesForMachine(row.account_id, row.machine_id, row.agent),
|
|
96
97
|
};
|
|
97
98
|
}
|
|
99
|
+
function sessionHeadBasis(row) {
|
|
100
|
+
const basis = {};
|
|
101
|
+
if (row.head_basis_event_id !== null)
|
|
102
|
+
basis.eventId = row.head_basis_event_id;
|
|
103
|
+
if (row.head_basis_message_id !== null)
|
|
104
|
+
basis.messageId = row.head_basis_message_id;
|
|
105
|
+
if (row.head_basis_logical_time !== null)
|
|
106
|
+
basis.logicalTime = row.head_basis_logical_time;
|
|
107
|
+
if (row.head_basis_turn_seq !== null)
|
|
108
|
+
basis.turnSeq = row.head_basis_turn_seq;
|
|
109
|
+
return Object.keys(basis).length > 0 ? basis : undefined;
|
|
110
|
+
}
|
|
98
111
|
export function eventSnapshot(row) {
|
|
99
112
|
return {
|
|
100
113
|
id: row.id,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
-
import { type EncryptedEnvelope, type EncryptedSessionEvent, type MachineSnapshot, type ServerMessage, type SessionSnapshot } from "
|
|
2
|
+
import { type EncryptedEnvelope, type EncryptedSessionEvent, type MachineSnapshot, type ServerMessage, type SessionSnapshot } from "../../../packages/shared/dist/index.js";
|
|
3
3
|
import { parseJson } from "./projections.js";
|
|
4
4
|
import { filterSnapshotForScope, isFullControllerToken, scopedTokenPublic, tokenScope } from "./scope.js";
|
|
5
|
-
import type { ControllerConnection, ControllerInviteRow, EventRow, MachineConnection, SessionRow, TokenKind, TokenRecord, WebSocketLike } from "./types.js";
|
|
5
|
+
import type { ControllerConnection, ControllerInviteRow, EventRow, MachineConnection, RelaySessionClaimRow, SessionRow, TokenKind, TokenRecord, WebSocketLike } from "./types.js";
|
|
6
6
|
type CreateRelayContextOptions = {
|
|
7
7
|
db: DatabaseSync;
|
|
8
8
|
eventReplayLimit: number;
|
|
@@ -29,6 +29,7 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
|
|
|
29
29
|
closeRevokedControllerConnections: (accountId: string, deviceId: string) => void;
|
|
30
30
|
closeRevokedMachineConnection: (accountId: string, machineId: string) => void;
|
|
31
31
|
connectedMachine: (accountId: string, machineId: string) => MachineConnection | undefined;
|
|
32
|
+
controllerDeviceOnline: (accountId: string, deviceId: string) => boolean;
|
|
32
33
|
controllersByAccount: Map<string, Set<ControllerConnection>>;
|
|
33
34
|
createPairingForAccount: (accountId: string) => {
|
|
34
35
|
pairingCode: string;
|
|
@@ -43,11 +44,13 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
|
|
|
43
44
|
accountId: string;
|
|
44
45
|
sessionId: string;
|
|
45
46
|
machineId: string;
|
|
47
|
+
source: "controller" | "machine";
|
|
46
48
|
messageId?: string;
|
|
47
49
|
turnId: string;
|
|
48
50
|
turnSeq?: number;
|
|
49
51
|
occurredAt?: number;
|
|
50
52
|
payload: EncryptedEnvelope;
|
|
53
|
+
updateSession?: boolean;
|
|
51
54
|
}) => EncryptedSessionEvent;
|
|
52
55
|
aliasedRuntimeEventHasRequestEvents: (params: {
|
|
53
56
|
accountId: string;
|
|
@@ -55,16 +58,39 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
|
|
|
55
58
|
machineId: string;
|
|
56
59
|
runtimeTurnId: string;
|
|
57
60
|
}) => boolean;
|
|
61
|
+
activeSessionClaim: (accountId: string, sessionId: string) => RelaySessionClaimRow | undefined;
|
|
62
|
+
claimSessionTurn: (params: {
|
|
63
|
+
accountId: string;
|
|
64
|
+
sessionId: string;
|
|
65
|
+
machineId: string;
|
|
66
|
+
requestId: string;
|
|
67
|
+
turnId: string;
|
|
68
|
+
commandType: "prompt";
|
|
69
|
+
createdAt?: number;
|
|
70
|
+
}) => {
|
|
71
|
+
ok: true;
|
|
72
|
+
} | {
|
|
73
|
+
ok: false;
|
|
74
|
+
claim: RelaySessionClaimRow;
|
|
75
|
+
};
|
|
58
76
|
isCommandPending: (accountId: string, requestId: string) => boolean;
|
|
77
|
+
isSessionCommandPending: (accountId: string, sessionId: string) => boolean;
|
|
59
78
|
isFullControllerToken: typeof isFullControllerToken;
|
|
60
79
|
machineCapabilities: (accountId: string, machineId: string) => MachineSnapshot["capabilities"] | undefined;
|
|
61
80
|
machineMessageProcessed: (accountId: string, machineId: string, messageId: string) => boolean;
|
|
62
81
|
machinesByKey: Map<string, MachineConnection>;
|
|
63
|
-
markCommandPending: (accountId: string, machineId: string, requestId: string
|
|
82
|
+
markCommandPending: (accountId: string, machineId: string, requestId: string, options?: {
|
|
83
|
+
command?: string;
|
|
84
|
+
sessionId?: string;
|
|
85
|
+
}) => void;
|
|
64
86
|
markMachineMessageProcessed: (accountId: string, machineId: string, messageId: string) => void;
|
|
87
|
+
markTokenSeen: (token: string) => void;
|
|
65
88
|
now: () => number;
|
|
66
89
|
parseJson: typeof parseJson;
|
|
67
90
|
previousCommandResponse: (accountId: string, requestId: string) => ServerMessage | undefined;
|
|
91
|
+
previousAdmissionAck: (accountId: string, requestId: string) => Extract<ServerMessage, {
|
|
92
|
+
type: "server:ack";
|
|
93
|
+
}> | undefined;
|
|
68
94
|
recordTurnAlias: (params: {
|
|
69
95
|
accountId: string;
|
|
70
96
|
sessionId: string;
|
|
@@ -77,6 +103,18 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
|
|
|
77
103
|
requireFullControllerToken: (authHeader: string | undefined) => TokenRecord;
|
|
78
104
|
requireHttpToken: (authHeader: string | undefined, kind: TokenKind) => TokenRecord;
|
|
79
105
|
resumeOfflineSessionsForMachine: (connection: MachineConnection) => void;
|
|
106
|
+
deliverOutboxCommand: (accountId: string, requestId: string) => "queued" | "delivered";
|
|
107
|
+
deliverQueuedCommandsForMachine: (connection: MachineConnection) => void;
|
|
108
|
+
finishSessionClaim: (params: {
|
|
109
|
+
accountId: string;
|
|
110
|
+
sessionId: string;
|
|
111
|
+
requestId?: string;
|
|
112
|
+
turnId?: string;
|
|
113
|
+
terminalStatus: "completed" | "cancelled" | "failed" | "error" | "unknown";
|
|
114
|
+
errorCode?: string;
|
|
115
|
+
finishedAt?: number;
|
|
116
|
+
}) => RelaySessionClaimRow | undefined;
|
|
117
|
+
markAdmissionStarted: (accountId: string, requestId: string, startedAt?: number) => void;
|
|
80
118
|
scopedTokenPublic: typeof scopedTokenPublic;
|
|
81
119
|
send: (socket: WebSocketLike, message: ServerMessage) => void;
|
|
82
120
|
sendAck: (connection: ControllerConnection, message: Extract<ServerMessage, {
|
|
@@ -3,8 +3,10 @@ import { createConnectionState, machineKey } from "./connections.js";
|
|
|
3
3
|
import { HttpError } from "./errors.js";
|
|
4
4
|
import { parseJson } from "./projections.js";
|
|
5
5
|
import { createRelayRepositories } from "./repositories.js";
|
|
6
|
+
import { markSessionRuntimeBindingsClosed } from "./runtime-bindings.js";
|
|
6
7
|
import { filterSnapshotForScope, isFullControllerToken, messageForScopedController, scopedListAllows, scopedTokenPublic, tokenScope, } from "./scope.js";
|
|
7
8
|
import { bearerToken, encodePairingCode, isPairingCodeMatch, tokenDigest } from "./security.js";
|
|
9
|
+
const REWRITE_HEAD_BASIS_PREFIX = "rewrite:";
|
|
8
10
|
export function createRelayContext(options) {
|
|
9
11
|
const { controllersByAccount, machinesByKey, pendingCommandRequests } = createConnectionState();
|
|
10
12
|
const now = options.now ?? Date.now;
|
|
@@ -34,6 +36,7 @@ export function createRelayContext(options) {
|
|
|
34
36
|
throw new HttpError(403, "AUTH_TOKEN_REVOKED", "Token has been revoked");
|
|
35
37
|
if (record.expires_at && record.expires_at <= now())
|
|
36
38
|
throw new HttpError(403, "AUTH_TOKEN_EXPIRED", "Token has expired");
|
|
39
|
+
markTokenSeen(record.token);
|
|
37
40
|
return record;
|
|
38
41
|
}
|
|
39
42
|
function requireFullControllerToken(authHeader) {
|
|
@@ -86,6 +89,19 @@ export function createRelayContext(options) {
|
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
91
|
}
|
|
92
|
+
function markTokenSeen(token) {
|
|
93
|
+
options.db.prepare("UPDATE tokens SET last_seen = ? WHERE token = ?").run(now(), token);
|
|
94
|
+
}
|
|
95
|
+
function controllerDeviceOnline(accountId, deviceId) {
|
|
96
|
+
const controllers = controllersByAccount.get(accountId);
|
|
97
|
+
if (!controllers)
|
|
98
|
+
return false;
|
|
99
|
+
for (const connection of controllers) {
|
|
100
|
+
if (connection.deviceId === deviceId)
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
89
105
|
function closeRevokedMachineConnection(accountId, machineId) {
|
|
90
106
|
const ts = now();
|
|
91
107
|
const rows = options.db
|
|
@@ -163,15 +179,117 @@ export function createRelayContext(options) {
|
|
|
163
179
|
.get(accountId, requestId);
|
|
164
180
|
return row ? JSON.parse(row.response) : undefined;
|
|
165
181
|
}
|
|
182
|
+
function previousAdmissionAck(accountId, requestId) {
|
|
183
|
+
const row = options.db
|
|
184
|
+
.prepare("SELECT * FROM relay_admissions WHERE account_id = ? AND request_id = ?")
|
|
185
|
+
.get(accountId, requestId);
|
|
186
|
+
if (!row)
|
|
187
|
+
return undefined;
|
|
188
|
+
return {
|
|
189
|
+
type: "server:ack",
|
|
190
|
+
requestId,
|
|
191
|
+
ok: true,
|
|
192
|
+
sessionId: row.session_id,
|
|
193
|
+
...(row.turn_id ? { turnId: row.turn_id } : {}),
|
|
194
|
+
admission: "replayed",
|
|
195
|
+
dispatch: row.dispatch,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function activeSessionClaim(accountId, sessionId) {
|
|
199
|
+
const claim = rawActiveSessionClaim(accountId, sessionId);
|
|
200
|
+
if (!claim)
|
|
201
|
+
return undefined;
|
|
202
|
+
const unknownErrorCode = claimUnknownExecutionErrorCode(claim);
|
|
203
|
+
if (unknownErrorCode) {
|
|
204
|
+
finishClaimRecord(claim, { terminalStatus: "unknown", errorCode: unknownErrorCode });
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
return claim;
|
|
208
|
+
}
|
|
209
|
+
function rawActiveSessionClaim(accountId, sessionId) {
|
|
210
|
+
return options.db
|
|
211
|
+
.prepare(`SELECT * FROM relay_session_claims
|
|
212
|
+
WHERE account_id = ? AND session_id = ? AND state = 'active'`)
|
|
213
|
+
.get(accountId, sessionId);
|
|
214
|
+
}
|
|
215
|
+
function claimUnknownExecutionErrorCode(claim) {
|
|
216
|
+
const admission = options.db
|
|
217
|
+
.prepare(`SELECT last_error_code
|
|
218
|
+
FROM relay_admissions
|
|
219
|
+
WHERE account_id = ? AND request_id = ?`)
|
|
220
|
+
.get(claim.account_id, claim.request_id);
|
|
221
|
+
const code = admission?.last_error_code;
|
|
222
|
+
return code === "EXECUTION_UNKNOWN" || code === "EXECUTION_NOT_FOUND" ? code : undefined;
|
|
223
|
+
}
|
|
224
|
+
function finishClaimRecord(claim, params) {
|
|
225
|
+
const ts = params.finishedAt ?? now();
|
|
226
|
+
options.db
|
|
227
|
+
.prepare(`UPDATE relay_admissions
|
|
228
|
+
SET finished_at = COALESCE(finished_at, ?),
|
|
229
|
+
terminal_status = COALESCE(terminal_status, ?),
|
|
230
|
+
last_error_code = COALESCE(?, last_error_code),
|
|
231
|
+
updated_at = ?
|
|
232
|
+
WHERE account_id = ? AND request_id = ?`)
|
|
233
|
+
.run(ts, params.terminalStatus, params.errorCode ?? null, ts, claim.account_id, claim.request_id);
|
|
234
|
+
options.db
|
|
235
|
+
.prepare("DELETE FROM relay_session_claims WHERE account_id = ? AND session_id = ? AND request_id = ?")
|
|
236
|
+
.run(claim.account_id, claim.session_id, claim.request_id);
|
|
237
|
+
if (params.terminalStatus === "unknown") {
|
|
238
|
+
options.db
|
|
239
|
+
.prepare(`UPDATE sessions
|
|
240
|
+
SET status = 'ready', updated_at = ?
|
|
241
|
+
WHERE account_id = ? AND id = ? AND machine_id = ? AND status = 'running'`)
|
|
242
|
+
.run(ts, claim.account_id, claim.session_id, claim.machine_id);
|
|
243
|
+
}
|
|
244
|
+
return claim;
|
|
245
|
+
}
|
|
246
|
+
function claimSessionTurn(params) {
|
|
247
|
+
const existing = activeSessionClaim(params.accountId, params.sessionId);
|
|
248
|
+
if (existing && existing.request_id !== params.requestId)
|
|
249
|
+
return { ok: false, claim: existing };
|
|
250
|
+
if (existing)
|
|
251
|
+
return { ok: true };
|
|
252
|
+
const ts = params.createdAt ?? now();
|
|
253
|
+
options.db
|
|
254
|
+
.prepare(`INSERT INTO relay_session_claims
|
|
255
|
+
(account_id, session_id, request_id, machine_id, turn_id, command_type, state, created_at, updated_at)
|
|
256
|
+
VALUES (?, ?, ?, ?, ?, ?, 'active', ?, ?)`)
|
|
257
|
+
.run(params.accountId, params.sessionId, params.requestId, params.machineId, params.turnId, params.commandType, ts, ts);
|
|
258
|
+
return { ok: true };
|
|
259
|
+
}
|
|
260
|
+
function markAdmissionStarted(accountId, requestId, startedAt = now()) {
|
|
261
|
+
options.db
|
|
262
|
+
.prepare(`UPDATE relay_admissions
|
|
263
|
+
SET started_at = COALESCE(started_at, ?), updated_at = ?
|
|
264
|
+
WHERE account_id = ? AND request_id = ?`)
|
|
265
|
+
.run(startedAt, startedAt, accountId, requestId);
|
|
266
|
+
}
|
|
267
|
+
function finishSessionClaim(params) {
|
|
268
|
+
const claim = rawActiveSessionClaim(params.accountId, params.sessionId);
|
|
269
|
+
if (!claim)
|
|
270
|
+
return undefined;
|
|
271
|
+
if (params.requestId && claim.request_id !== params.requestId)
|
|
272
|
+
return claim;
|
|
273
|
+
if (params.turnId && claim.turn_id !== params.turnId)
|
|
274
|
+
return claim;
|
|
275
|
+
return finishClaimRecord(claim, params);
|
|
276
|
+
}
|
|
166
277
|
function commandKey(accountId, requestId) {
|
|
167
278
|
return `${accountId}:${requestId}`;
|
|
168
279
|
}
|
|
169
|
-
function markCommandPending(accountId, machineId, requestId) {
|
|
170
|
-
pendingCommandRequests.set(commandKey(accountId, requestId), { accountId, machineId, requestId });
|
|
280
|
+
function markCommandPending(accountId, machineId, requestId, options = {}) {
|
|
281
|
+
pendingCommandRequests.set(commandKey(accountId, requestId), { accountId, machineId, requestId, ...options });
|
|
171
282
|
}
|
|
172
283
|
function isCommandPending(accountId, requestId) {
|
|
173
284
|
return pendingCommandRequests.has(commandKey(accountId, requestId));
|
|
174
285
|
}
|
|
286
|
+
function isSessionCommandPending(accountId, sessionId) {
|
|
287
|
+
for (const pending of pendingCommandRequests.values()) {
|
|
288
|
+
if (pending.accountId === accountId && pending.sessionId === sessionId)
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
175
293
|
function clearCommandPending(accountId, requestId) {
|
|
176
294
|
pendingCommandRequests.delete(commandKey(accountId, requestId));
|
|
177
295
|
}
|
|
@@ -223,6 +341,48 @@ export function createRelayContext(options) {
|
|
|
223
341
|
message: "Machine is offline",
|
|
224
342
|
});
|
|
225
343
|
}
|
|
344
|
+
function deliverOutboxCommand(accountId, requestId) {
|
|
345
|
+
const row = options.db
|
|
346
|
+
.prepare("SELECT * FROM relay_dispatch_outbox WHERE account_id = ? AND request_id = ?")
|
|
347
|
+
.get(accountId, requestId);
|
|
348
|
+
if (!row)
|
|
349
|
+
return "queued";
|
|
350
|
+
if (row.state === "delivered")
|
|
351
|
+
return "delivered";
|
|
352
|
+
const machine = connectedMachine(accountId, row.machine_id);
|
|
353
|
+
if (!machine)
|
|
354
|
+
return "queued";
|
|
355
|
+
const command = JSON.parse(row.message);
|
|
356
|
+
send(machine.socket, command);
|
|
357
|
+
const ts = now();
|
|
358
|
+
options.db
|
|
359
|
+
.prepare(`UPDATE relay_dispatch_outbox
|
|
360
|
+
SET state = 'delivered', delivered_at = ?, updated_at = ?
|
|
361
|
+
WHERE account_id = ? AND request_id = ? AND state = 'queued'`)
|
|
362
|
+
.run(ts, ts, accountId, requestId);
|
|
363
|
+
options.db
|
|
364
|
+
.prepare(`UPDATE relay_admissions
|
|
365
|
+
SET dispatch = 'delivered', updated_at = ?
|
|
366
|
+
WHERE account_id = ? AND request_id = ?`)
|
|
367
|
+
.run(ts, accountId, requestId);
|
|
368
|
+
if (command.type === "machine:prompt") {
|
|
369
|
+
markAdmissionStarted(accountId, requestId, ts);
|
|
370
|
+
const session = setSessionStatus(command.sessionId, "running");
|
|
371
|
+
if (session)
|
|
372
|
+
broadcastControllers(accountId, { type: "server:session", session });
|
|
373
|
+
}
|
|
374
|
+
return "delivered";
|
|
375
|
+
}
|
|
376
|
+
function deliverQueuedCommandsForMachine(connection) {
|
|
377
|
+
const rows = options.db
|
|
378
|
+
.prepare(`SELECT * FROM relay_dispatch_outbox
|
|
379
|
+
WHERE account_id = ? AND machine_id = ? AND state = 'queued'
|
|
380
|
+
ORDER BY created_at ASC`)
|
|
381
|
+
.all(connection.accountId, connection.machineId);
|
|
382
|
+
for (const row of rows) {
|
|
383
|
+
deliverOutboxCommand(connection.accountId, row.request_id);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
226
386
|
function broadcastControllers(accountId, message) {
|
|
227
387
|
const controllers = controllersByAccount.get(accountId);
|
|
228
388
|
if (!controllers)
|
|
@@ -309,8 +469,28 @@ export function createRelayContext(options) {
|
|
|
309
469
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
310
470
|
.run(params.accountId, params.sessionId, params.machineId, params.messageId ?? null, params.turnId, seqRow.nextSeq, params.turnSeq ?? null, JSON.stringify(params.payload), createdAt, params.occurredAt ?? null);
|
|
311
471
|
const eventId = Number(result.lastInsertRowid);
|
|
312
|
-
if (
|
|
313
|
-
|
|
472
|
+
if (params.updateSession === false) {
|
|
473
|
+
// Keep late closed-session events addressable without changing the
|
|
474
|
+
// session projection or workspace ordering.
|
|
475
|
+
}
|
|
476
|
+
else if (shouldAdvanceSessionHead(params, eventId, createdAt)) {
|
|
477
|
+
const order = logicalEventOrder({
|
|
478
|
+
id: eventId,
|
|
479
|
+
createdAt,
|
|
480
|
+
messageId: params.messageId,
|
|
481
|
+
occurredAt: params.occurredAt,
|
|
482
|
+
seq: params.turnSeq,
|
|
483
|
+
turnSeq: params.turnSeq,
|
|
484
|
+
});
|
|
485
|
+
options.db.prepare(`UPDATE sessions
|
|
486
|
+
SET current_head = ?,
|
|
487
|
+
last_turn_id = ?,
|
|
488
|
+
head_basis_event_id = ?,
|
|
489
|
+
head_basis_message_id = ?,
|
|
490
|
+
head_basis_logical_time = ?,
|
|
491
|
+
head_basis_turn_seq = ?,
|
|
492
|
+
updated_at = ?
|
|
493
|
+
WHERE id = ?`).run(`event:${eventId}`, params.turnId, eventId, params.messageId ?? null, order.time, order.seq, createdAt, params.sessionId);
|
|
314
494
|
}
|
|
315
495
|
else {
|
|
316
496
|
options.db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(createdAt, params.sessionId);
|
|
@@ -330,19 +510,24 @@ export function createRelayContext(options) {
|
|
|
330
510
|
}
|
|
331
511
|
function shouldAdvanceSessionHead(params, eventId, createdAt) {
|
|
332
512
|
const session = options.db
|
|
333
|
-
.prepare(
|
|
513
|
+
.prepare(`SELECT current_head, last_turn_id, status, head_basis_event_id, head_basis_message_id,
|
|
514
|
+
head_basis_logical_time, head_basis_turn_seq
|
|
515
|
+
FROM sessions
|
|
516
|
+
WHERE account_id = ? AND id = ? AND machine_id = ?`)
|
|
334
517
|
.get(params.accountId, params.sessionId, params.machineId);
|
|
335
518
|
const currentHead = session?.current_head;
|
|
519
|
+
if (session?.status === "closed")
|
|
520
|
+
return false;
|
|
336
521
|
if (!currentHead)
|
|
337
522
|
return true;
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
523
|
+
if (typeof session?.head_basis_message_id === "string" &&
|
|
524
|
+
session.head_basis_message_id.startsWith(REWRITE_HEAD_BASIS_PREFIX) &&
|
|
525
|
+
params.source === "machine") {
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
if (session?.status === "running" && params.source === "machine" && session.last_turn_id && params.turnId !== session.last_turn_id) {
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
346
531
|
const nextOrder = logicalEventOrder({
|
|
347
532
|
id: eventId,
|
|
348
533
|
createdAt,
|
|
@@ -351,7 +536,34 @@ export function createRelayContext(options) {
|
|
|
351
536
|
seq: params.turnSeq,
|
|
352
537
|
turnSeq: params.turnSeq,
|
|
353
538
|
});
|
|
354
|
-
const currentOrder =
|
|
539
|
+
const currentOrder = sessionHeadBasisOrder(session) ?? currentHeadEventOrder(params, currentHead);
|
|
540
|
+
if (!currentOrder)
|
|
541
|
+
return !isHistoricalBackfillEvent(params);
|
|
542
|
+
if (nextOrder.time !== currentOrder.time)
|
|
543
|
+
return nextOrder.time > currentOrder.time;
|
|
544
|
+
if (nextOrder.seq !== currentOrder.seq)
|
|
545
|
+
return nextOrder.seq > currentOrder.seq;
|
|
546
|
+
return nextOrder.id > currentOrder.id;
|
|
547
|
+
}
|
|
548
|
+
function sessionHeadBasisOrder(session) {
|
|
549
|
+
if (session.head_basis_logical_time === null || session.head_basis_turn_seq === null)
|
|
550
|
+
return undefined;
|
|
551
|
+
return {
|
|
552
|
+
time: session.head_basis_logical_time,
|
|
553
|
+
seq: session.head_basis_turn_seq,
|
|
554
|
+
id: session.head_basis_event_id ?? 0,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function currentHeadEventOrder(params, currentHead) {
|
|
558
|
+
const currentEventId = /^event:(\d+)$/.exec(currentHead)?.[1];
|
|
559
|
+
if (!currentEventId)
|
|
560
|
+
return undefined;
|
|
561
|
+
const current = options.db
|
|
562
|
+
.prepare("SELECT * FROM session_events WHERE account_id = ? AND session_id = ? AND machine_id = ? AND id = ?")
|
|
563
|
+
.get(params.accountId, params.sessionId, params.machineId, Number(currentEventId));
|
|
564
|
+
if (!current)
|
|
565
|
+
return undefined;
|
|
566
|
+
return logicalEventOrder({
|
|
355
567
|
id: current.id,
|
|
356
568
|
createdAt: current.created_at,
|
|
357
569
|
messageId: current.message_id ?? undefined,
|
|
@@ -359,11 +571,6 @@ export function createRelayContext(options) {
|
|
|
359
571
|
seq: current.seq,
|
|
360
572
|
turnSeq: current.turn_seq ?? undefined,
|
|
361
573
|
});
|
|
362
|
-
if (nextOrder.time !== currentOrder.time)
|
|
363
|
-
return nextOrder.time > currentOrder.time;
|
|
364
|
-
if (nextOrder.seq !== currentOrder.seq)
|
|
365
|
-
return nextOrder.seq > currentOrder.seq;
|
|
366
|
-
return nextOrder.id > currentOrder.id;
|
|
367
574
|
}
|
|
368
575
|
function logicalEventOrder(input) {
|
|
369
576
|
if (input.occurredAt !== undefined) {
|
|
@@ -421,7 +628,15 @@ export function createRelayContext(options) {
|
|
|
421
628
|
}
|
|
422
629
|
function setSessionStatus(sessionId, status) {
|
|
423
630
|
const ts = now();
|
|
631
|
+
const previous = options.db.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId);
|
|
424
632
|
options.db.prepare("UPDATE sessions SET status = ?, updated_at = ? WHERE id = ?").run(status, ts, sessionId);
|
|
633
|
+
if (status === "closed" && previous) {
|
|
634
|
+
markSessionRuntimeBindingsClosed(options.db, {
|
|
635
|
+
accountId: previous.account_id,
|
|
636
|
+
sessionId,
|
|
637
|
+
ts,
|
|
638
|
+
});
|
|
639
|
+
}
|
|
425
640
|
const row = options.db.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId);
|
|
426
641
|
return row ? sessionSnapshot(row) : undefined;
|
|
427
642
|
}
|
|
@@ -453,6 +668,7 @@ export function createRelayContext(options) {
|
|
|
453
668
|
closeRevokedControllerConnections,
|
|
454
669
|
closeRevokedMachineConnection,
|
|
455
670
|
connectedMachine,
|
|
671
|
+
controllerDeviceOnline,
|
|
456
672
|
controllersByAccount,
|
|
457
673
|
createPairingForAccount,
|
|
458
674
|
db: options.db,
|
|
@@ -462,21 +678,30 @@ export function createRelayContext(options) {
|
|
|
462
678
|
findUsableControllerInvite,
|
|
463
679
|
insertEvent,
|
|
464
680
|
aliasedRuntimeEventHasRequestEvents,
|
|
681
|
+
activeSessionClaim,
|
|
682
|
+
claimSessionTurn,
|
|
465
683
|
isCommandPending,
|
|
684
|
+
isSessionCommandPending,
|
|
466
685
|
isFullControllerToken,
|
|
467
686
|
machineCapabilities,
|
|
468
687
|
machineMessageProcessed,
|
|
469
688
|
machinesByKey,
|
|
470
689
|
markCommandPending,
|
|
471
690
|
markMachineMessageProcessed,
|
|
691
|
+
markTokenSeen,
|
|
472
692
|
now,
|
|
473
693
|
parseJson,
|
|
474
694
|
previousCommandResponse,
|
|
695
|
+
previousAdmissionAck,
|
|
475
696
|
recordTurnAlias,
|
|
476
697
|
rememberCommandResponse,
|
|
477
698
|
requireFullControllerToken,
|
|
478
699
|
requireHttpToken,
|
|
479
700
|
resumeOfflineSessionsForMachine,
|
|
701
|
+
deliverOutboxCommand,
|
|
702
|
+
deliverQueuedCommandsForMachine,
|
|
703
|
+
finishSessionClaim,
|
|
704
|
+
markAdmissionStarted,
|
|
480
705
|
scopedTokenPublic,
|
|
481
706
|
send,
|
|
482
707
|
sendAck,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
-
import type { MachineSnapshot, ServerMessage, SessionSnapshot } from "
|
|
2
|
+
import type { MachineSnapshot, ServerMessage, SessionSnapshot } from "../../../packages/shared/dist/index.js";
|
|
3
3
|
import type { EventRow, MachineConnection, MachineRow, SessionRow } from "./types.js";
|
|
4
4
|
export declare function createRelayRepositories(db: DatabaseSync, connectedMachine: (accountId: string, machineId: string) => MachineConnection | undefined, eventReplayLimit: number): {
|
|
5
|
-
eventSnapshot: (row: EventRow) => import("
|
|
5
|
+
eventSnapshot: (row: EventRow) => import("../../../packages/shared/dist/index.js").EncryptedSessionEvent;
|
|
6
6
|
machineCapabilities: (accountId: string, machineId: string) => MachineSnapshot["capabilities"] | undefined;
|
|
7
7
|
machineSnapshot: (row: MachineRow) => MachineSnapshot;
|
|
8
8
|
scopedSessionRow: (accountId: string, sessionId: string) => SessionRow | undefined;
|
|
@@ -28,8 +28,35 @@ export function createRelayRepositories(db, connectedMachine, eventReplayLimit)
|
|
|
28
28
|
const capabilities = machineCapabilities(accountId, machineId);
|
|
29
29
|
return capabilities?.agents.find((agent) => agent.id === agentId)?.historyModel;
|
|
30
30
|
}
|
|
31
|
+
function sessionStatusForProjection(row) {
|
|
32
|
+
if (row.status !== "failed")
|
|
33
|
+
return row.status;
|
|
34
|
+
const latestPromptAdmission = db
|
|
35
|
+
.prepare(`SELECT turn_id, terminal_status
|
|
36
|
+
FROM relay_admissions
|
|
37
|
+
WHERE account_id = ? AND session_id = ? AND kind = 'prompt' AND finished_at IS NOT NULL
|
|
38
|
+
ORDER BY finished_at DESC, updated_at DESC
|
|
39
|
+
LIMIT 1`)
|
|
40
|
+
.get(row.account_id, row.id);
|
|
41
|
+
if (latestPromptAdmission?.terminal_status !== "completed")
|
|
42
|
+
return row.status;
|
|
43
|
+
const terminalTurnId = latestPromptAdmission.turn_id;
|
|
44
|
+
if (!terminalTurnId)
|
|
45
|
+
return "completed";
|
|
46
|
+
if (terminalTurnId === row.last_turn_id || terminalTurnId === row.current_head)
|
|
47
|
+
return "completed";
|
|
48
|
+
const alias = db
|
|
49
|
+
.prepare(`SELECT 1 FROM session_turn_aliases
|
|
50
|
+
WHERE account_id = ? AND session_id = ? AND machine_id = ?
|
|
51
|
+
AND request_turn_id = ?
|
|
52
|
+
AND runtime_turn_id IN (?, ?)
|
|
53
|
+
LIMIT 1`)
|
|
54
|
+
.get(row.account_id, row.id, row.machine_id, terminalTurnId, row.last_turn_id ?? "", row.current_head ?? "");
|
|
55
|
+
return alias ? "completed" : row.status;
|
|
56
|
+
}
|
|
31
57
|
function sessionSnapshot(row) {
|
|
32
|
-
|
|
58
|
+
const status = sessionStatusForProjection(row);
|
|
59
|
+
return projectSessionSnapshot(status === row.status ? row : { ...row, status }, sessionCapabilitiesForMachine, sessionHistoryModelForMachine);
|
|
33
60
|
}
|
|
34
61
|
function machineSnapshot(row) {
|
|
35
62
|
return projectMachineSnapshot(row, (accountId, machineId) => connectedMachine(accountId, machineId) !== undefined);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import type { SessionRuntimeBindingRow, SessionRow } from "./types.js";
|
|
3
|
+
export declare function normalizeRuntimeSessionIds(values: readonly unknown[]): string[];
|
|
4
|
+
export declare function upsertSessionRuntimeBindings(db: DatabaseSync, input: {
|
|
5
|
+
accountId: string;
|
|
6
|
+
machineId: string;
|
|
7
|
+
agent: string;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
runtimeSessionIds: readonly unknown[];
|
|
10
|
+
status: "active" | "closed";
|
|
11
|
+
ts: number;
|
|
12
|
+
}): void;
|
|
13
|
+
export declare function findSessionRuntimeBinding(db: DatabaseSync, input: {
|
|
14
|
+
accountId: string;
|
|
15
|
+
machineId: string;
|
|
16
|
+
agent: string;
|
|
17
|
+
runtimeSessionId: string;
|
|
18
|
+
}): (SessionRuntimeBindingRow & {
|
|
19
|
+
session_status: SessionRow["status"] | null;
|
|
20
|
+
}) | undefined;
|
|
21
|
+
export declare function markSessionRuntimeBindingsClosed(db: DatabaseSync, input: {
|
|
22
|
+
accountId: string;
|
|
23
|
+
sessionId: string;
|
|
24
|
+
ts: number;
|
|
25
|
+
}): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export function normalizeRuntimeSessionIds(values) {
|
|
2
|
+
const ids = [];
|
|
3
|
+
const seen = new Set();
|
|
4
|
+
for (const value of values) {
|
|
5
|
+
if (typeof value !== "string")
|
|
6
|
+
continue;
|
|
7
|
+
const id = value.trim();
|
|
8
|
+
if (!id || id.startsWith("event:") || seen.has(id))
|
|
9
|
+
continue;
|
|
10
|
+
seen.add(id);
|
|
11
|
+
ids.push(id);
|
|
12
|
+
}
|
|
13
|
+
return ids;
|
|
14
|
+
}
|
|
15
|
+
export function upsertSessionRuntimeBindings(db, input) {
|
|
16
|
+
const ids = normalizeRuntimeSessionIds(input.runtimeSessionIds);
|
|
17
|
+
for (const runtimeSessionId of ids) {
|
|
18
|
+
db.prepare(`INSERT INTO session_runtime_bindings
|
|
19
|
+
(account_id, machine_id, agent, runtime_session_id, session_id, status, created_at, updated_at)
|
|
20
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
21
|
+
ON CONFLICT(account_id, machine_id, agent, runtime_session_id)
|
|
22
|
+
DO UPDATE SET
|
|
23
|
+
session_id = excluded.session_id,
|
|
24
|
+
status = excluded.status,
|
|
25
|
+
updated_at = excluded.updated_at`).run(input.accountId, input.machineId, input.agent, runtimeSessionId, input.sessionId, input.status, input.ts, input.ts);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function findSessionRuntimeBinding(db, input) {
|
|
29
|
+
const runtimeSessionId = input.runtimeSessionId.trim();
|
|
30
|
+
if (!runtimeSessionId)
|
|
31
|
+
return undefined;
|
|
32
|
+
return db.prepare(`SELECT bindings.*, sessions.status AS session_status
|
|
33
|
+
FROM session_runtime_bindings bindings
|
|
34
|
+
LEFT JOIN sessions
|
|
35
|
+
ON sessions.id = bindings.session_id
|
|
36
|
+
AND sessions.account_id = bindings.account_id
|
|
37
|
+
AND sessions.machine_id = bindings.machine_id
|
|
38
|
+
WHERE bindings.account_id = ?
|
|
39
|
+
AND bindings.machine_id = ?
|
|
40
|
+
AND bindings.agent = ?
|
|
41
|
+
AND bindings.runtime_session_id = ?
|
|
42
|
+
LIMIT 1`).get(input.accountId, input.machineId, input.agent, runtimeSessionId);
|
|
43
|
+
}
|
|
44
|
+
export function markSessionRuntimeBindingsClosed(db, input) {
|
|
45
|
+
db.prepare(`UPDATE session_runtime_bindings
|
|
46
|
+
SET status = 'closed', updated_at = ?
|
|
47
|
+
WHERE account_id = ? AND session_id = ?`).run(input.ts, input.accountId, input.sessionId);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=runtime-bindings.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ServerMessage } from "
|
|
1
|
+
import type { ServerMessage } from "../../../packages/shared/dist/index.js";
|
|
2
2
|
import type { ControllerConnection, ScopedTokenScope, TokenRecord } from "./types.js";
|
|
3
3
|
export declare function tokenScope(record: TokenRecord): ScopedTokenScope | null;
|
|
4
4
|
export declare function isFullControllerToken(record: TokenRecord): boolean;
|