@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
|
@@ -2,7 +2,7 @@ import { CliError } from "../../errors.js";
|
|
|
2
2
|
import { showMachine } from "./session-view.js";
|
|
3
3
|
export async function listWorkspaceHistoricalSessions(client, input) {
|
|
4
4
|
const snapshot = await client.snapshot();
|
|
5
|
-
const
|
|
5
|
+
const providerPageSize = Math.min(200, Math.max(Math.min(input.limit, 200), 50));
|
|
6
6
|
const selectedMachines = snapshot.machines.filter((machine) => {
|
|
7
7
|
if (input.machineId)
|
|
8
8
|
return machine.id === input.machineId;
|
|
@@ -17,13 +17,26 @@ export async function listWorkspaceHistoricalSessions(client, input) {
|
|
|
17
17
|
const rows = await Promise.all(machines.map(async ({ machine, projected }) => {
|
|
18
18
|
const machineName = projected.metadata.name ?? projected.metadata.hostname ?? machine.name;
|
|
19
19
|
try {
|
|
20
|
-
const sessions =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
const sessions = [];
|
|
21
|
+
let cursor;
|
|
22
|
+
const seenCursors = new Set();
|
|
23
|
+
while (sessions.length < input.limit) {
|
|
24
|
+
const page = await client.listHistoricalSessionsPage({
|
|
25
|
+
machineId: machine.id,
|
|
26
|
+
cwd: input.cwd,
|
|
27
|
+
agent: input.agent,
|
|
28
|
+
includeArchived: input.includeArchived,
|
|
29
|
+
limit: providerPageSize,
|
|
30
|
+
cursor,
|
|
31
|
+
});
|
|
32
|
+
sessions.push(...page.sessions);
|
|
33
|
+
if (!page.hasMore || !page.nextCursor)
|
|
34
|
+
break;
|
|
35
|
+
if (seenCursors.has(page.nextCursor))
|
|
36
|
+
break;
|
|
37
|
+
seenCursors.add(page.nextCursor);
|
|
38
|
+
cursor = page.nextCursor;
|
|
39
|
+
}
|
|
27
40
|
return {
|
|
28
41
|
sessions: sessions
|
|
29
42
|
.filter((session) => input.includeArchived === true || session.runtimeState !== "archived")
|
|
@@ -47,12 +60,52 @@ export async function listWorkspaceHistoricalSessions(client, input) {
|
|
|
47
60
|
}
|
|
48
61
|
}));
|
|
49
62
|
return {
|
|
50
|
-
sessions: rows
|
|
63
|
+
sessions: await enrichHistoricalLoadedSessionIds(client, rows
|
|
51
64
|
.flatMap((row) => row.sessions)
|
|
52
65
|
.sort((left, right) => right.updatedAt - left.updatedAt || left.runtimeSessionId.localeCompare(right.runtimeSessionId))
|
|
53
|
-
.slice(0, input.limit),
|
|
66
|
+
.slice(0, input.limit)),
|
|
54
67
|
errors: rows.flatMap((row) => row.error ? [row.error] : []),
|
|
55
68
|
machines: rows.map((row) => row.machine),
|
|
56
69
|
};
|
|
57
70
|
}
|
|
71
|
+
async function enrichHistoricalLoadedSessionIds(client, sessions) {
|
|
72
|
+
const snapshot = await client.snapshot();
|
|
73
|
+
const runtimeIdToSession = new Map();
|
|
74
|
+
for (const session of snapshot.sessions) {
|
|
75
|
+
if (session.status === "closed")
|
|
76
|
+
continue;
|
|
77
|
+
const metadata = await client.decodeSessionMetadata(session);
|
|
78
|
+
for (const runtimeSessionId of metadataRuntimeSessionIds(metadata)) {
|
|
79
|
+
const key = `${session.machineId}:${session.agent}:${runtimeSessionId}`;
|
|
80
|
+
const existing = runtimeIdToSession.get(key);
|
|
81
|
+
if (!existing || session.createdAt < existing.createdAt || (session.createdAt === existing.createdAt && session.id < existing.id)) {
|
|
82
|
+
runtimeIdToSession.set(key, session);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return sessions.map((historical) => {
|
|
87
|
+
const loaded = runtimeIdToSession.get(`${historical.machineId}:${historical.agent}:${historical.runtimeSessionId}`);
|
|
88
|
+
return loaded ? { ...historical, loadedSessionId: loaded.id } : historical;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function metadataRuntimeSessionIds(metadata) {
|
|
92
|
+
const ids = new Set();
|
|
93
|
+
addRuntimeSessionId(ids, metadata.importedFromRuntimeSessionId);
|
|
94
|
+
const runtime = metadata.runtime;
|
|
95
|
+
if (runtime && typeof runtime === "object" && !Array.isArray(runtime)) {
|
|
96
|
+
const record = runtime;
|
|
97
|
+
addRuntimeSessionId(ids, record.backendSessionId);
|
|
98
|
+
addRuntimeSessionId(ids, record.agentSessionId);
|
|
99
|
+
addRuntimeSessionId(ids, record.acpxRecordId);
|
|
100
|
+
const externalHandle = record.externalHandle;
|
|
101
|
+
if (externalHandle && typeof externalHandle === "object" && !Array.isArray(externalHandle)) {
|
|
102
|
+
addRuntimeSessionId(ids, externalHandle.sessionId);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return ids;
|
|
106
|
+
}
|
|
107
|
+
function addRuntimeSessionId(ids, value) {
|
|
108
|
+
if (typeof value === "string" && value.trim())
|
|
109
|
+
ids.add(value.trim());
|
|
110
|
+
}
|
|
58
111
|
//# sourceMappingURL=workspace.js.map
|
|
@@ -1,14 +1,50 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { CliError, ControllerClient, compactText, machineSessionOverview, ok, readConfig, requirePositional, showMachine, wantsJson, wantsVerbose } from "./lib/index.js";
|
|
3
|
+
function machineDisplayName(machine) {
|
|
4
|
+
return machine.metadata.name ?? machine.name;
|
|
5
|
+
}
|
|
6
|
+
function duplicateNameKey(value) {
|
|
7
|
+
return value.trim().toLocaleLowerCase();
|
|
8
|
+
}
|
|
9
|
+
function annotateStaleDuplicateMachines(machines) {
|
|
10
|
+
const byName = new Map();
|
|
11
|
+
for (const machine of machines) {
|
|
12
|
+
const displayName = machineDisplayName(machine);
|
|
13
|
+
const key = duplicateNameKey(displayName);
|
|
14
|
+
if (!key)
|
|
15
|
+
continue;
|
|
16
|
+
const group = byName.get(key) ?? { displayName, machines: [] };
|
|
17
|
+
group.machines.push(machine);
|
|
18
|
+
byName.set(key, group);
|
|
19
|
+
}
|
|
20
|
+
return machines.map((machine) => {
|
|
21
|
+
if (machine.online)
|
|
22
|
+
return machine;
|
|
23
|
+
const displayName = machineDisplayName(machine);
|
|
24
|
+
const group = byName.get(duplicateNameKey(displayName));
|
|
25
|
+
const onlinePeerIds = group?.machines.filter((peer) => peer.online && peer.id !== machine.id).map((peer) => peer.id) ?? [];
|
|
26
|
+
if (onlinePeerIds.length === 0)
|
|
27
|
+
return machine;
|
|
28
|
+
return {
|
|
29
|
+
...machine,
|
|
30
|
+
staleDuplicate: {
|
|
31
|
+
reason: "offline-same-name",
|
|
32
|
+
displayName,
|
|
33
|
+
onlinePeerIds,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
3
38
|
function structuredMachineSummary(machine) {
|
|
4
39
|
const summary = machine.summary;
|
|
5
40
|
return {
|
|
6
41
|
machineId: machine.id,
|
|
7
|
-
name: machine
|
|
42
|
+
name: machineDisplayName(machine),
|
|
8
43
|
online: machine.online,
|
|
9
44
|
sessionCount: summary.sessionCount,
|
|
10
45
|
runningCount: summary.runningSessionCount,
|
|
11
46
|
blockedCount: summary.blockedSessionCount,
|
|
47
|
+
...(machine.staleDuplicate ? { staleDuplicate: machine.staleDuplicate } : {}),
|
|
12
48
|
};
|
|
13
49
|
}
|
|
14
50
|
function structuredMachineVerbose(machine) {
|
|
@@ -16,26 +52,30 @@ function structuredMachineVerbose(machine) {
|
|
|
16
52
|
machineId: machine.id,
|
|
17
53
|
online: machine.online,
|
|
18
54
|
lastSeen: machine.lastSeen,
|
|
19
|
-
name: machine
|
|
55
|
+
name: machineDisplayName(machine),
|
|
20
56
|
defaultCwd: machine.defaultCwd,
|
|
21
57
|
capabilities: machine.capabilities,
|
|
22
58
|
metadata: machine.metadata,
|
|
23
59
|
summary: machine.summary,
|
|
24
60
|
sessions: machine.sessions,
|
|
25
61
|
encryptedMetadata: machine.encryptedMetadata,
|
|
62
|
+
...(machine.staleDuplicate ? { staleDuplicate: machine.staleDuplicate } : {}),
|
|
26
63
|
};
|
|
27
64
|
}
|
|
28
65
|
function printMachineLine(machine) {
|
|
29
|
-
const name = machine
|
|
66
|
+
const name = machineDisplayName(machine);
|
|
30
67
|
const summary = machine.summary;
|
|
31
|
-
|
|
68
|
+
const duplicate = machine.staleDuplicate ? ` stale-duplicate-of:${machine.staleDuplicate.onlinePeerIds.join(",")}` : "";
|
|
69
|
+
console.log(`${machine.id} ${machine.online ? "online" : "offline"} ${compactText(name, 32)} sessions:${summary.sessionCount} running:${summary.runningSessionCount} blocked:${summary.blockedSessionCount}${duplicate}`);
|
|
32
70
|
}
|
|
33
71
|
function printMachineDetails(machine) {
|
|
34
|
-
const name = machine
|
|
72
|
+
const name = machineDisplayName(machine);
|
|
35
73
|
const agents = machine.capabilities.agents.map((agent) => agent.id).join(", ") || "-";
|
|
36
74
|
const summary = machine.summary;
|
|
37
75
|
console.log(`${name} (${machine.id})`);
|
|
38
76
|
console.log(` status: ${machine.online ? "online" : "offline"} agents: ${agents}`);
|
|
77
|
+
if (machine.staleDuplicate)
|
|
78
|
+
console.log(` stale duplicate: offline machine with online peer ${machine.staleDuplicate.onlinePeerIds.join(", ")}`);
|
|
39
79
|
console.log(` cwd: ${machine.defaultCwd ?? "-"}`);
|
|
40
80
|
console.log(` sessions: ${summary.sessionCount} total, ${summary.runningSessionCount} running, ${summary.readySessionCount} ready, ${summary.needsUserSessionCount} needs user`);
|
|
41
81
|
console.log(` sessions: happy-elves session list --machine ${machine.id} --limit 20`);
|
|
@@ -176,19 +216,20 @@ export async function handleMachine({ domain, action, positional, flags }) {
|
|
|
176
216
|
...(await showMachine(client, machine)),
|
|
177
217
|
...(await machineSessionOverview(client, snapshot.sessions, machine.id)),
|
|
178
218
|
})));
|
|
219
|
+
const annotatedMachines = annotateStaleDuplicateMachines(machines);
|
|
179
220
|
if (!wantsJson(flags)) {
|
|
180
|
-
if (
|
|
221
|
+
if (annotatedMachines.length === 0) {
|
|
181
222
|
console.log("No machines.");
|
|
182
223
|
return true;
|
|
183
224
|
}
|
|
184
|
-
for (const machine of
|
|
225
|
+
for (const machine of annotatedMachines) {
|
|
185
226
|
printMachineLine(machine);
|
|
186
227
|
}
|
|
187
228
|
return true;
|
|
188
229
|
}
|
|
189
230
|
ok("machine.list", {
|
|
190
|
-
machines:
|
|
191
|
-
page: { returned:
|
|
231
|
+
machines: annotatedMachines.map((machine) => (wantsVerbose(flags) ? structuredMachineVerbose(machine) : structuredMachineSummary(machine))),
|
|
232
|
+
page: { returned: annotatedMachines.length },
|
|
192
233
|
});
|
|
193
234
|
return true;
|
|
194
235
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { CliError, ControllerClient, ok, readConfig, readPromptTextFile, requirePositional, requireString, wantsJson, wantsVerbose } from "./lib/index.js";
|
|
2
|
+
export async function handleMemory({ domain, action, positional, flags }) {
|
|
3
|
+
if (domain !== "memory")
|
|
4
|
+
return false;
|
|
5
|
+
const config = await readConfig(flags);
|
|
6
|
+
const client = new ControllerClient(config);
|
|
7
|
+
if (action === "overview" || action === "status" || action === "list") {
|
|
8
|
+
const machineId = await resolveMemoryMachineId(client, flags);
|
|
9
|
+
const projectKey = await resolveMemoryProjectKey(client, flags, machineId);
|
|
10
|
+
const result = await client.memory({ machineId, action: "overview", projectKey, mode: parseMemoryMode(flags.mode) ?? "readonly" });
|
|
11
|
+
if (!wantsJson(flags)) {
|
|
12
|
+
const files = result.overview?.files ?? [];
|
|
13
|
+
if (files.length === 0)
|
|
14
|
+
console.log("No memory files.");
|
|
15
|
+
else
|
|
16
|
+
for (const file of files)
|
|
17
|
+
console.log(`${file.layer} ${file.path} ${file.lineCount} lines ${file.updatedAt}`);
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
ok(`memory.${action}`, result);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (action === "save" || action === "write") {
|
|
24
|
+
const machineId = await resolveMemoryMachineId(client, flags);
|
|
25
|
+
const projectKey = await resolveMemoryProjectKey(client, flags, machineId);
|
|
26
|
+
const text = typeof flags.text === "string"
|
|
27
|
+
? flags.text
|
|
28
|
+
: typeof flags["text-file"] === "string"
|
|
29
|
+
? await readPromptTextFile(flags["text-file"])
|
|
30
|
+
: "";
|
|
31
|
+
if (!text.trim())
|
|
32
|
+
throw new CliError("Missing --text or --text-file", "MISSING_ARGUMENT");
|
|
33
|
+
const layer = parseMemoryLayer(flags.layer) ?? "curated";
|
|
34
|
+
const result = await client.memory({
|
|
35
|
+
machineId,
|
|
36
|
+
action: "write",
|
|
37
|
+
projectKey,
|
|
38
|
+
write: {
|
|
39
|
+
projectKey,
|
|
40
|
+
layer,
|
|
41
|
+
text,
|
|
42
|
+
...(typeof flags.title === "string" ? { title: flags.title } : {}),
|
|
43
|
+
...(typeof flags.date === "string" ? { date: flags.date } : {}),
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
ok("memory.save", result);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
if (action === "read") {
|
|
50
|
+
const machineId = await resolveMemoryMachineId(client, flags);
|
|
51
|
+
const projectKey = await resolveMemoryProjectKey(client, flags, machineId);
|
|
52
|
+
const path = typeof flags.path === "string" ? flags.path : requirePositional(positional[0], "path");
|
|
53
|
+
const result = await client.memory({ machineId, action: "read", projectKey, path });
|
|
54
|
+
if (!wantsJson(flags)) {
|
|
55
|
+
console.log(result.content ?? "");
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
ok("memory.read", result);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
if (action === "search") {
|
|
62
|
+
const machineId = await resolveMemoryMachineId(client, flags);
|
|
63
|
+
const projectKey = await resolveMemoryProjectKey(client, flags, machineId);
|
|
64
|
+
const query = requireString(flags, "query");
|
|
65
|
+
const limit = typeof flags.limit === "string" ? Number(flags.limit) : 5;
|
|
66
|
+
if (!Number.isInteger(limit) || limit <= 0)
|
|
67
|
+
throw new CliError("Invalid --limit", "INVALID_ARGUMENT");
|
|
68
|
+
const result = await client.memory({ machineId, action: "search", projectKey, query, limit });
|
|
69
|
+
if (!wantsJson(flags)) {
|
|
70
|
+
const results = result.results ?? [];
|
|
71
|
+
if (results.length === 0)
|
|
72
|
+
console.log("No matching memory.");
|
|
73
|
+
else
|
|
74
|
+
for (const item of results) {
|
|
75
|
+
const hash = item.citation.contentHash ? ` hash=${item.citation.contentHash.slice(0, 10)}` : "";
|
|
76
|
+
const stale = item.citation.stale ? " stale" : "";
|
|
77
|
+
console.log(`${item.path}:${item.citation.startLine}-${item.citation.endLine}${hash}${stale} ${item.snippet}`);
|
|
78
|
+
if (wantsVerbose(flags))
|
|
79
|
+
console.log(` score=${item.score}`);
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
ok("memory.search", result);
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
if (action === "promote") {
|
|
87
|
+
const machineId = await resolveMemoryMachineId(client, flags);
|
|
88
|
+
const projectKey = await resolveMemoryProjectKey(client, flags, machineId);
|
|
89
|
+
const source = typeof flags.source === "string" ? parseMemoryCitation(flags.source) : undefined;
|
|
90
|
+
if (!source)
|
|
91
|
+
throw new CliError("Missing --source <path:start-end>", "MISSING_ARGUMENT");
|
|
92
|
+
const targetLayer = parsePromotionLayer(flags.layer) ?? "curated";
|
|
93
|
+
const result = await client.memory({
|
|
94
|
+
machineId,
|
|
95
|
+
action: "promote",
|
|
96
|
+
projectKey,
|
|
97
|
+
promote: {
|
|
98
|
+
projectKey,
|
|
99
|
+
source,
|
|
100
|
+
targetLayer,
|
|
101
|
+
...(typeof flags.title === "string" ? { title: flags.title } : {}),
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
ok("memory.promote", result);
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
if (action === "reindex" || action === "sync") {
|
|
108
|
+
const machineId = await resolveMemoryMachineId(client, flags);
|
|
109
|
+
const projectKey = await resolveMemoryProjectKey(client, flags, machineId);
|
|
110
|
+
ok(`memory.${action}`, await client.memory({ machineId, action, projectKey, mode: parseMemoryMode(flags.mode) ?? "readonly" }));
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
async function resolveMemoryMachineId(client, flags) {
|
|
116
|
+
if (typeof flags.machine === "string" && flags.machine.length > 0)
|
|
117
|
+
return flags.machine;
|
|
118
|
+
if (typeof flags.session === "string" && flags.session.length > 0) {
|
|
119
|
+
const session = await client.getSession(flags.session);
|
|
120
|
+
if (session)
|
|
121
|
+
return session.machineId;
|
|
122
|
+
}
|
|
123
|
+
const snapshot = await client.snapshot();
|
|
124
|
+
const machine = snapshot.machines.find((item) => item.online) ?? snapshot.machines[0];
|
|
125
|
+
if (!machine)
|
|
126
|
+
throw new CliError("No daemon machine is available; pass --machine <machineId>", "MACHINE_NOT_FOUND");
|
|
127
|
+
return machine.id;
|
|
128
|
+
}
|
|
129
|
+
async function resolveMemoryProjectKey(client, flags, machineId) {
|
|
130
|
+
if (typeof flags.project === "string" && flags.project.trim())
|
|
131
|
+
return flags.project.trim();
|
|
132
|
+
if (typeof flags.session === "string" && flags.session.trim()) {
|
|
133
|
+
const session = await client.getSession(flags.session.trim());
|
|
134
|
+
if (session)
|
|
135
|
+
return `${session.machineId}:${session.cwd}`;
|
|
136
|
+
}
|
|
137
|
+
const cwd = typeof flags.cwd === "string" && flags.cwd.trim() ? flags.cwd.trim() : process.cwd();
|
|
138
|
+
return `${machineId}:${cwd}`;
|
|
139
|
+
}
|
|
140
|
+
function parseMemoryLayer(value) {
|
|
141
|
+
if (typeof value !== "string" || !value.trim())
|
|
142
|
+
return undefined;
|
|
143
|
+
if (value === "user" || value === "curated" || value === "daily")
|
|
144
|
+
return value;
|
|
145
|
+
throw new CliError("Invalid --layer; expected user|curated|daily", "INVALID_ARGUMENT");
|
|
146
|
+
}
|
|
147
|
+
function parseMemoryMode(value) {
|
|
148
|
+
if (typeof value !== "string" || !value.trim())
|
|
149
|
+
return undefined;
|
|
150
|
+
const normalized = value.trim().toLowerCase().replace(/-/g, "");
|
|
151
|
+
if (normalized === "off" || normalized === "readonly" || normalized === "readwrite")
|
|
152
|
+
return normalized;
|
|
153
|
+
throw new CliError("Invalid --mode; expected off|readonly|readwrite|read-only|read-write", "INVALID_ARGUMENT");
|
|
154
|
+
}
|
|
155
|
+
function parsePromotionLayer(value) {
|
|
156
|
+
const layer = parseMemoryLayer(value);
|
|
157
|
+
if (!layer)
|
|
158
|
+
return undefined;
|
|
159
|
+
if (layer === "user" || layer === "curated")
|
|
160
|
+
return layer;
|
|
161
|
+
throw new CliError("Invalid --layer for promotion; expected user|curated", "INVALID_ARGUMENT");
|
|
162
|
+
}
|
|
163
|
+
function parseMemoryCitation(value) {
|
|
164
|
+
const match = value.match(/^(.+):(\d+)-(\d+)(?:@([A-Za-z0-9._-]+))?$/);
|
|
165
|
+
if (!match)
|
|
166
|
+
throw new CliError("Invalid --source; expected path:start-end or path:start-end@contentHash", "INVALID_ARGUMENT");
|
|
167
|
+
const startLine = Number(match[2]);
|
|
168
|
+
const endLine = Number(match[3]);
|
|
169
|
+
if (!Number.isInteger(startLine) || !Number.isInteger(endLine) || startLine < 1 || endLine < startLine) {
|
|
170
|
+
throw new CliError("Invalid --source line range", "INVALID_ARGUMENT");
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
path: match[1],
|
|
174
|
+
startLine,
|
|
175
|
+
endLine,
|
|
176
|
+
...(match[4] ? { contentHash: match[4] } : {}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -1,5 +1,28 @@
|
|
|
1
|
-
import { CliError, ok, relayHealth, requireRelayUrl, wantsJson } from "./lib/index.js";
|
|
1
|
+
import { CliError, auditRelayDb, ok, relayHealth, requireRelayUrl, wantsJson } from "./lib/index.js";
|
|
2
2
|
export async function handleRelay({ domain, action, flags }) {
|
|
3
|
+
if (domain === "relay" && action === "audit-db") {
|
|
4
|
+
const dbPath = typeof flags.path === "string" ? flags.path : process.env.HAPPY_ELVES_DB;
|
|
5
|
+
if (!dbPath)
|
|
6
|
+
throw new CliError("relay audit-db requires --path <relay.db> or HAPPY_ELVES_DB.", "MISSING_ARGUMENT");
|
|
7
|
+
const result = await auditRelayDb({
|
|
8
|
+
dbPath,
|
|
9
|
+
outputDir: typeof flags.output === "string" ? flags.output : undefined,
|
|
10
|
+
});
|
|
11
|
+
if (wantsJson(flags)) {
|
|
12
|
+
ok("relay.audit-db", result);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
console.log(`Relay DB audit: ${result.ok ? "ok" : "failed"}`);
|
|
16
|
+
console.log(`source: ${result.sourceDbPath}`);
|
|
17
|
+
console.log(`backup: ${result.backupPath}`);
|
|
18
|
+
console.log(`manifest: ${result.manifestPath}`);
|
|
19
|
+
if (result.unknownTables.length > 0)
|
|
20
|
+
console.log(`unknown tables preserved: ${result.unknownTables.join(", ")}`);
|
|
21
|
+
for (const mismatch of result.backupVerification.mismatches)
|
|
22
|
+
console.log(`mismatch: ${mismatch}`);
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
3
26
|
if (domain === "relay" && action === "serve") {
|
|
4
27
|
const host = typeof flags.host === "string" ? flags.host : "0.0.0.0";
|
|
5
28
|
const relayPort = typeof flags.port === "string" ? Number(flags.port) : 8787;
|
|
@@ -45,7 +68,9 @@ export async function handleRelay({ domain, action, flags }) {
|
|
|
45
68
|
}
|
|
46
69
|
const allOk = checks.every((check) => check.ok);
|
|
47
70
|
if (wantsJson(flags)) {
|
|
48
|
-
|
|
71
|
+
if (!allOk)
|
|
72
|
+
process.exitCode = 1;
|
|
73
|
+
ok("relay.doctor", { ok: allOk, relayUrl, checks }, {}, allOk);
|
|
49
74
|
}
|
|
50
75
|
else {
|
|
51
76
|
console.log(`Relay doctor: ${allOk ? "ok" : "issues found"}`);
|
|
@@ -53,6 +78,8 @@ export async function handleRelay({ domain, action, flags }) {
|
|
|
53
78
|
for (const check of checks) {
|
|
54
79
|
console.log(`${check.ok ? "ok" : "fail"} ${check.name}: ${check.message}`);
|
|
55
80
|
}
|
|
81
|
+
if (!allOk)
|
|
82
|
+
process.exitCode = 1;
|
|
56
83
|
}
|
|
57
84
|
return true;
|
|
58
85
|
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { normalizeSessionTags, sessionTagsMatch } from "../../../../packages/shared/dist/index.js";
|
|
4
|
+
import { CliError, ControllerClient, DEFAULT_COMMAND_TIMEOUT_MS, compactText, ok, parseDurationMs, readConfig, releaseProfilesPath, wantsJson, } from "./lib/index.js";
|
|
5
|
+
const defaultReleaseProfile = {
|
|
6
|
+
name: "happy-elves",
|
|
7
|
+
releaseSessionTags: ["Happy Elves", "Release Session"],
|
|
8
|
+
reviewerSessionTags: ["Happy Elves", "Reviewer"],
|
|
9
|
+
dogfoodSessionTags: ["Happy Elves", "Dogfood"],
|
|
10
|
+
};
|
|
11
|
+
export async function handleRelease({ domain, action, positional, flags }) {
|
|
12
|
+
if (domain !== "release")
|
|
13
|
+
return false;
|
|
14
|
+
if (action === "profile") {
|
|
15
|
+
const subaction = positional[0];
|
|
16
|
+
if (subaction === "list") {
|
|
17
|
+
const store = await readReleaseProfileStore();
|
|
18
|
+
printReleaseOutput("release.profile.list", { profiles: store.profiles, defaultProfile: defaultReleaseProfile.name }, flags);
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
if (subaction === "show") {
|
|
22
|
+
const { profile } = await loadProfile(profileNameFromFlags(flags));
|
|
23
|
+
printReleaseOutput("release.profile.show", { profile }, flags);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (subaction === "set") {
|
|
27
|
+
const name = positional[1] || profileNameFromFlags(flags);
|
|
28
|
+
const profile = profileFromFlags(name, flags);
|
|
29
|
+
const store = await readReleaseProfileStore();
|
|
30
|
+
const profiles = store.profiles.filter((item) => item.name !== profile.name);
|
|
31
|
+
profiles.push(profile);
|
|
32
|
+
await writeReleaseProfileStore({ version: 1, profiles: profiles.sort((left, right) => left.name.localeCompare(right.name)) });
|
|
33
|
+
printReleaseOutput("release.profile.set", { profile }, flags);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
throw new CliError(`Unsupported release profile action: ${subaction ?? ""}`, "USAGE");
|
|
37
|
+
}
|
|
38
|
+
if (action === "resolve") {
|
|
39
|
+
const config = await readConfig(flags);
|
|
40
|
+
const client = new ControllerClient(config);
|
|
41
|
+
const { profile } = await loadProfile(profileNameFromFlags(flags));
|
|
42
|
+
const resolved = await resolveReleaseTargets(client, profile);
|
|
43
|
+
printReleaseOutput("release.resolve", resolved, flags, resolved.errors.length === 0);
|
|
44
|
+
if (resolved.errors.length > 0)
|
|
45
|
+
process.exit(1);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
if (action === "notify") {
|
|
49
|
+
const config = await readConfig(flags);
|
|
50
|
+
const client = new ControllerClient(config);
|
|
51
|
+
const { profile } = await loadProfile(profileNameFromFlags(flags));
|
|
52
|
+
const releaseTarget = await resolveRequiredReleaseTarget(client, profile);
|
|
53
|
+
const text = releaseNotifyText(flags);
|
|
54
|
+
const wait = flags.detach !== true && flags["no-wait"] !== true;
|
|
55
|
+
const result = await client.run(releaseTarget.sessionId, text, {
|
|
56
|
+
wait,
|
|
57
|
+
permissionMode: "approve-all",
|
|
58
|
+
memoryMode: "off",
|
|
59
|
+
memoryProjectKey: `${releaseTarget.machineId}:${releaseTarget.cwd}`,
|
|
60
|
+
waitTimeoutMs: parseDurationMs(flags.timeout, DEFAULT_COMMAND_TIMEOUT_MS),
|
|
61
|
+
ackTimeoutMs: parseDurationMs(flags["ack-timeout"], 15_000),
|
|
62
|
+
inactivityTimeoutMs: parseDurationMs(flags["inactivity-timeout"] ?? flags["runtime-timeout"], DEFAULT_COMMAND_TIMEOUT_MS),
|
|
63
|
+
});
|
|
64
|
+
printReleaseOutput("release.notify", {
|
|
65
|
+
profile: profile.name,
|
|
66
|
+
releaseTarget,
|
|
67
|
+
prompt: text,
|
|
68
|
+
promptPreview: compactText(text, 80),
|
|
69
|
+
permissionMode: "approve-all",
|
|
70
|
+
memoryMode: "off",
|
|
71
|
+
wait,
|
|
72
|
+
...result,
|
|
73
|
+
}, flags);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
function profileNameFromFlags(flags) {
|
|
79
|
+
return typeof flags.profile === "string" && flags.profile.trim() ? flags.profile.trim() : defaultReleaseProfile.name;
|
|
80
|
+
}
|
|
81
|
+
function releaseNotifyText(flags) {
|
|
82
|
+
const value = typeof flags.text === "string" ? flags.text.trim() : "";
|
|
83
|
+
return value || "发布";
|
|
84
|
+
}
|
|
85
|
+
function tagsFromFlagValue(value) {
|
|
86
|
+
if (typeof value !== "string")
|
|
87
|
+
return [];
|
|
88
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
89
|
+
}
|
|
90
|
+
function profileFromFlags(name, flags) {
|
|
91
|
+
const releaseSessionTags = normalizeSessionTags(tagsFromFlagValue(flags["release-tag"]));
|
|
92
|
+
if (releaseSessionTags.length === 0)
|
|
93
|
+
throw new CliError("Missing --release-tag", "MISSING_ARGUMENT");
|
|
94
|
+
const reviewerSessionTags = normalizeSessionTags(tagsFromFlagValue(flags["reviewer-tag"]));
|
|
95
|
+
const dogfoodSessionTags = normalizeSessionTags(tagsFromFlagValue(flags["dogfood-tag"]));
|
|
96
|
+
return {
|
|
97
|
+
name,
|
|
98
|
+
releaseSessionTags,
|
|
99
|
+
...(reviewerSessionTags.length > 0 ? { reviewerSessionTags } : {}),
|
|
100
|
+
...(dogfoodSessionTags.length > 0 ? { dogfoodSessionTags } : {}),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function loadProfile(name) {
|
|
104
|
+
const store = await readReleaseProfileStore();
|
|
105
|
+
return { profile: store.profiles.find((profile) => profile.name === name) ?? defaultReleaseProfile, store };
|
|
106
|
+
}
|
|
107
|
+
async function readReleaseProfileStore() {
|
|
108
|
+
try {
|
|
109
|
+
const parsed = JSON.parse(await fs.readFile(releaseProfilesPath, "utf8"));
|
|
110
|
+
const profiles = Array.isArray(parsed.profiles) ? parsed.profiles.filter(isReleaseProfile) : [];
|
|
111
|
+
const hasDefault = profiles.some((profile) => profile.name === defaultReleaseProfile.name);
|
|
112
|
+
return { version: 1, profiles: hasDefault ? profiles : [defaultReleaseProfile, ...profiles] };
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (error.code !== "ENOENT")
|
|
116
|
+
throw error;
|
|
117
|
+
return { version: 1, profiles: [defaultReleaseProfile] };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function isReleaseProfile(value) {
|
|
121
|
+
if (!value || typeof value !== "object")
|
|
122
|
+
return false;
|
|
123
|
+
const candidate = value;
|
|
124
|
+
return typeof candidate.name === "string" && Array.isArray(candidate.releaseSessionTags);
|
|
125
|
+
}
|
|
126
|
+
async function writeReleaseProfileStore(store) {
|
|
127
|
+
await fs.mkdir(path.dirname(releaseProfilesPath), { recursive: true });
|
|
128
|
+
const tempPath = `${releaseProfilesPath}.${process.pid}.${Date.now()}.tmp`;
|
|
129
|
+
await fs.writeFile(tempPath, `${JSON.stringify(store, null, 2)}\n`, { mode: 0o600 });
|
|
130
|
+
await fs.rename(tempPath, releaseProfilesPath);
|
|
131
|
+
}
|
|
132
|
+
async function resolveReleaseTargets(client, profile) {
|
|
133
|
+
const warnings = [];
|
|
134
|
+
const errors = [];
|
|
135
|
+
const release = await resolveTaggedSession(client, profile.releaseSessionTags);
|
|
136
|
+
if (release.kind === "missing")
|
|
137
|
+
errors.push({ code: "TAG_TARGET_NOT_FOUND", message: `No release session matches tags: ${profile.releaseSessionTags.join(", ")}` });
|
|
138
|
+
if (release.kind === "ambiguous")
|
|
139
|
+
errors.push({ code: "TAG_TARGET_AMBIGUOUS", message: `Multiple release sessions match tags: ${profile.releaseSessionTags.join(", ")}`, candidates: release.candidates });
|
|
140
|
+
const reviewer = profile.reviewerSessionTags?.length ? await resolveTaggedSession(client, profile.reviewerSessionTags) : { kind: "skipped" };
|
|
141
|
+
if (reviewer.kind === "ambiguous")
|
|
142
|
+
errors.push({ code: "TAG_TARGET_AMBIGUOUS", message: `Multiple reviewer sessions match tags: ${profile.reviewerSessionTags?.join(", ")}`, candidates: reviewer.candidates });
|
|
143
|
+
if (reviewer.kind === "missing")
|
|
144
|
+
warnings.push({ code: "TAG_TARGET_NOT_FOUND", message: `No reviewer session matches tags: ${profile.reviewerSessionTags?.join(", ")}` });
|
|
145
|
+
const dogfood = profile.dogfoodSessionTags?.length ? await resolveTaggedSession(client, profile.dogfoodSessionTags) : { kind: "skipped" };
|
|
146
|
+
if (dogfood.kind === "ambiguous")
|
|
147
|
+
errors.push({ code: "TAG_TARGET_AMBIGUOUS", message: `Multiple dogfood sessions match tags: ${profile.dogfoodSessionTags?.join(", ")}`, candidates: dogfood.candidates });
|
|
148
|
+
if (dogfood.kind === "missing")
|
|
149
|
+
warnings.push({ code: "TAG_TARGET_NOT_FOUND", message: `No dogfood session matches tags: ${profile.dogfoodSessionTags?.join(", ")}` });
|
|
150
|
+
return {
|
|
151
|
+
profile,
|
|
152
|
+
...(release.kind === "found" ? { releaseTarget: release.session } : {}),
|
|
153
|
+
...(reviewer.kind === "found" ? { reviewerTarget: reviewer.session } : {}),
|
|
154
|
+
...(dogfood.kind === "found" ? { dogfoodTarget: dogfood.session } : {}),
|
|
155
|
+
warnings,
|
|
156
|
+
errors,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
async function resolveRequiredReleaseTarget(client, profile) {
|
|
160
|
+
const resolved = await resolveReleaseTargets(client, profile);
|
|
161
|
+
if (resolved.errors.length > 0 || !resolved.releaseTarget) {
|
|
162
|
+
const error = resolved.errors[0];
|
|
163
|
+
throw new CliError(error?.message ?? "Release target not found", error?.code ?? "TAG_TARGET_NOT_FOUND");
|
|
164
|
+
}
|
|
165
|
+
return resolved.releaseTarget;
|
|
166
|
+
}
|
|
167
|
+
async function resolveTaggedSession(client, tags) {
|
|
168
|
+
const sessions = await client.listSessions({ tags });
|
|
169
|
+
const candidates = [];
|
|
170
|
+
for (const session of sessions.filter((session) => session.status !== "closed")) {
|
|
171
|
+
const metadata = await client.decodeSessionMetadata(session);
|
|
172
|
+
const sessionTags = normalizeSessionTags(metadata.tags);
|
|
173
|
+
if (!sessionTagsMatch(sessionTags, tags))
|
|
174
|
+
continue;
|
|
175
|
+
candidates.push({
|
|
176
|
+
sessionId: session.id,
|
|
177
|
+
machineId: session.machineId,
|
|
178
|
+
agent: metadata.agent ?? session.agent,
|
|
179
|
+
cwd: metadata.cwd ?? session.cwd,
|
|
180
|
+
name: metadata.name ?? session.name,
|
|
181
|
+
tags: sessionTags,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (candidates.length === 0)
|
|
185
|
+
return { kind: "missing" };
|
|
186
|
+
if (candidates.length > 1)
|
|
187
|
+
return { kind: "ambiguous", candidates };
|
|
188
|
+
return { kind: "found", session: candidates[0] };
|
|
189
|
+
}
|
|
190
|
+
function printReleaseOutput(type, data, flags, success = true) {
|
|
191
|
+
if (wantsJson(flags)) {
|
|
192
|
+
ok(type, data, {}, success);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
console.log(JSON.stringify(data, null, 2));
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=release.js.map
|