@cydm/happy-elves 0.1.0-beta.296 → 0.1.0-beta.298

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.
Files changed (67) hide show
  1. package/apps/cli/dist/commands/lib/args.js +7 -17
  2. package/apps/cli/dist/commands/lib/session-output.d.ts +1 -1
  3. package/apps/cli/dist/commands/lib/session-output.js +3 -66
  4. package/apps/cli/dist/commands/lib/session-view.d.ts +0 -3
  5. package/apps/cli/dist/commands/lib/session-view.js +1 -15
  6. package/apps/cli/dist/commands/lib/types.d.ts +1 -1
  7. package/apps/cli/dist/commands/lib/usage.js +20 -47
  8. package/apps/cli/dist/commands/lib/workspace.js +42 -2
  9. package/apps/cli/dist/commands/memory.js +6 -26
  10. package/apps/cli/dist/commands/release.js +45 -199
  11. package/apps/cli/dist/commands/remote.js +1 -134
  12. package/apps/cli/dist/commands/session.js +37 -98
  13. package/apps/cli/dist/commands/turn.js +1 -4
  14. package/apps/cli/package.json +1 -1
  15. package/apps/daemon/dist/paths.d.ts +0 -3
  16. package/apps/daemon/dist/paths.js +0 -3
  17. package/apps/daemon/dist/relay/connection.js +0 -10
  18. package/apps/daemon/dist/relay/register.js +0 -3
  19. package/apps/daemon/dist/runtime/external-provider.js +1 -32
  20. package/apps/daemon/dist/session/lifecycle.js +19 -7
  21. package/apps/daemon/dist/session/metadata.d.ts +1 -2
  22. package/apps/daemon/dist/session/metadata.js +12 -10
  23. package/apps/daemon/dist/session/primitives.js +16 -8
  24. package/apps/daemon/dist/session/prompt.d.ts +1 -1
  25. package/apps/daemon/dist/session/prompt.js +9 -86
  26. package/apps/daemon/dist/session/reconcile.js +0 -21
  27. package/apps/daemon/dist/types.d.ts +3 -4
  28. package/apps/daemon/package.json +1 -1
  29. package/apps/relay/dist/connections.d.ts +0 -1
  30. package/apps/relay/dist/controller-handlers.js +34 -111
  31. package/apps/relay/dist/db.js +0 -2
  32. package/apps/relay/dist/http-routes.js +50 -33
  33. package/apps/relay/dist/http-schemas.d.ts +15 -13
  34. package/apps/relay/dist/http-schemas.js +3 -1
  35. package/apps/relay/dist/machine-handlers.js +25 -183
  36. package/apps/relay/dist/projections.js +1 -64
  37. package/apps/relay/dist/relay-context.js +44 -104
  38. package/apps/relay/dist/types.d.ts +0 -1
  39. package/package.json +1 -1
  40. package/packages/agent-sdk/dist/index.d.ts +0 -9
  41. package/packages/client/dist/client.d.ts +9 -10
  42. package/packages/client/dist/client.js +75 -132
  43. package/packages/client/dist/index.d.ts +1 -1
  44. package/packages/client/dist/transport.d.ts +0 -10
  45. package/packages/client/dist/transport.js +0 -14
  46. package/packages/client/dist/types.d.ts +3 -40
  47. package/packages/runtime/dist/index.d.ts +0 -9
  48. package/packages/runtime-cli/dist/codex-app-server.d.ts +1 -15
  49. package/packages/runtime-cli/dist/codex-app-server.js +3 -167
  50. package/packages/runtime-cli/dist/codex-protocol.d.ts +1 -4
  51. package/packages/runtime-cli/dist/codex-protocol.js +2 -7
  52. package/packages/runtime-cli/dist/index.d.ts +1 -6
  53. package/packages/runtime-cli/dist/index.js +5 -163
  54. package/packages/shared/dist/args.js +4 -16
  55. package/packages/shared/dist/index.d.ts +1 -1
  56. package/packages/shared/dist/index.js +1 -1
  57. package/packages/shared/dist/protocol-schemas.d.ts +2 -216
  58. package/packages/shared/dist/protocol-schemas.js +1 -97
  59. package/packages/shared/dist/protocol-types.d.ts +1 -101
  60. package/packages/shared/dist/protocol.d.ts +2 -67
  61. package/packages/shared/dist/protocol.js +1 -75
  62. package/packages/shared/dist/session-state.d.ts +1 -1
  63. package/packages/shared/dist/session-state.js +1 -4
  64. package/apps/daemon/dist/relay/lifecycle.d.ts +0 -7
  65. package/apps/daemon/dist/relay/lifecycle.js +0 -545
  66. package/apps/daemon/dist/relay/release.d.ts +0 -7
  67. package/apps/daemon/dist/relay/release.js +0 -378
@@ -32,7 +32,6 @@ const valueFlags = new Set([
32
32
  "memory-project",
33
33
  "memory-top-n",
34
34
  "name",
35
- "package-url",
36
35
  "model",
37
36
  "mode",
38
37
  "output",
@@ -40,12 +39,14 @@ const valueFlags = new Set([
40
39
  "port",
41
40
  "permission",
42
41
  "permission-mode",
42
+ "profile",
43
43
  "project",
44
44
  "query",
45
45
  "prompt",
46
46
  "prompt-file",
47
47
  "every",
48
48
  "reason",
49
+ "release-tag",
49
50
  "reaction-emoji",
50
51
  "relay",
51
52
  "root",
@@ -53,6 +54,7 @@ const valueFlags = new Set([
53
54
  "runtime-session",
54
55
  "shell",
55
56
  "actions",
57
+ "ack-timeout",
56
58
  "allow-chat",
57
59
  "allow-sender",
58
60
  "expires-in",
@@ -62,23 +64,12 @@ const valueFlags = new Set([
62
64
  "sessions",
63
65
  "session",
64
66
  "secret",
65
- "sha256",
66
67
  "since",
67
68
  "source",
68
69
  "stop-on",
69
70
  "tail",
70
71
  "tag",
71
72
  "tags",
72
- "release-tag",
73
- "release-tags",
74
- "reviewer-tag",
75
- "reviewer-tags",
76
- "dogfood-tag",
77
- "dogfood-tags",
78
- "target-machine",
79
- "target-machines",
80
- "expected-commit",
81
- "profile",
82
73
  "text",
83
74
  "text-file",
84
75
  "timeout",
@@ -94,17 +85,19 @@ const valueFlags = new Set([
94
85
  "url",
95
86
  "turn",
96
87
  "until",
97
- "version",
98
- "wait-timeout",
88
+ "reviewer-tag",
89
+ "dogfood-tag",
99
90
  ]);
100
91
  const booleanFlags = new Set([
101
92
  "all",
102
93
  "allow-any-sender",
103
94
  "app-secret-stdin",
104
95
  "confirm-risk",
96
+ "copy-tags",
105
97
  "detach",
106
98
  "disable-reaction",
107
99
  "help",
100
+ "hidden",
108
101
  "h",
109
102
  "include-archived",
110
103
  "include-debug",
@@ -119,10 +112,7 @@ const booleanFlags = new Set([
119
112
  "summary",
120
113
  "verbose",
121
114
  "wait",
122
- "hidden",
123
115
  "manual",
124
- "copy-tags",
125
- "no-daemon-update",
126
116
  ]);
127
117
  const knownFlags = new Set([...valueFlags, ...booleanFlags]);
128
118
  const dashPrefixedValueFlags = new Set(["secret"]);
@@ -29,7 +29,7 @@ export type TurnSummary = {
29
29
  checkpointId?: string;
30
30
  runtimeTurnId?: string;
31
31
  turnSeq?: number;
32
- status: "running" | "completed" | "failed" | "cancelled" | "unknown";
32
+ status: "running" | "completed" | "failed" | "cancelled";
33
33
  prompt: string;
34
34
  output: string;
35
35
  terminalText: string;
@@ -243,13 +243,6 @@ export function summarizeTurns(events) {
243
243
  current.checkpointId = payload.currentHead;
244
244
  current.runtimeTurnId = payload.lastTurnId;
245
245
  }
246
- else if (payload?.type === "status" && isReconcileUnknownTag(payload.tag)) {
247
- if (current.status === "running") {
248
- current.status = "unknown";
249
- current.completedAt = event.createdAt;
250
- current.terminalText = payload.text.trim();
251
- }
252
- }
253
246
  else if (payload?.type === "memory_used") {
254
247
  current.usedMemories = dedupeUsedMemories([...current.usedMemories, ...payload.memories]);
255
248
  }
@@ -322,7 +315,7 @@ function foldAliasedRuntimeEvents(events) {
322
315
  const profiles = new Map();
323
316
  const runtimeToRequest = new Map();
324
317
  for (const event of events) {
325
- const profile = profiles.get(event.turnId) ?? { output: "", status: "running" };
318
+ const profile = profiles.get(event.turnId) ?? { output: "" };
326
319
  const payload = event.decoded;
327
320
  if (payload?.type === "user_prompt" && profile.prompt === undefined) {
328
321
  profile.prompt = payload.text.trim();
@@ -335,7 +328,6 @@ function foldAliasedRuntimeEvents(events) {
335
328
  if (runtimeTurnId && runtimeTurnId !== event.turnId && !runtimeTurnId.startsWith("event:")) {
336
329
  runtimeToRequest.set(runtimeTurnId, event.turnId);
337
330
  }
338
- profile.status = payload.status;
339
331
  }
340
332
  profiles.set(event.turnId, profile);
341
333
  }
@@ -353,46 +345,11 @@ function foldAliasedRuntimeEvents(events) {
353
345
  duplicateRuntimeToRequest.set(runtimeTurnId, requestTurnId);
354
346
  }
355
347
  }
356
- const inferredRuntimeToRequest = inferRuntimeCompletionAliases(profiles);
357
- const inferredRequestTurns = new Set(inferredRuntimeToRequest.values());
358
- const foldedRuntimeToRequest = new Map([...duplicateRuntimeToRequest, ...inferredRuntimeToRequest]);
359
- const foldedEvents = [];
360
- for (const event of events) {
361
- if (duplicateRuntimeTurns.has(event.turnId))
362
- continue;
363
- const inferredRequestTurnId = inferredRuntimeToRequest.get(event.turnId);
364
- if (inferredRequestTurnId) {
365
- if (event.decoded?.type === "user_prompt" && profiles.get(inferredRequestTurnId)?.prompt)
366
- continue;
367
- foldedEvents.push({ ...event, turnId: inferredRequestTurnId });
368
- continue;
369
- }
370
- if (inferredRequestTurns.has(event.turnId) &&
371
- event.decoded?.type === "text_delta" &&
372
- event.decoded.stream !== "thought") {
373
- continue;
374
- }
375
- foldedEvents.push(event);
376
- }
377
348
  return {
378
- events: foldedEvents,
379
- runtimeToRequest: foldedRuntimeToRequest,
349
+ events: duplicateRuntimeTurns.size === 0 ? events : events.filter((event) => !duplicateRuntimeTurns.has(event.turnId)),
350
+ runtimeToRequest: duplicateRuntimeToRequest,
380
351
  };
381
352
  }
382
- function inferRuntimeCompletionAliases(profiles) {
383
- const requestTurns = [...profiles.entries()].filter(([turnId, profile]) => turnId.startsWith("turn_") && profile.status === "running" && Boolean(profile.prompt?.trim()));
384
- const runtimeTurns = [...profiles.entries()].filter(([turnId, profile]) => !turnId.startsWith("turn_") && profile.status !== "running" && Boolean(profile.prompt?.trim()));
385
- const result = new Map();
386
- for (const [runtimeTurnId, runtime] of runtimeTurns) {
387
- const candidates = requestTurns.filter(([, request]) => promptCompatible(request.prompt ?? "", runtime.prompt ?? "") &&
388
- outputCompatibleForInferredAlias(request.output, runtime.output, request.prompt ?? "", runtime.prompt ?? ""));
389
- if (candidates.length !== 1)
390
- continue;
391
- const [requestTurnId] = candidates[0];
392
- result.set(runtimeTurnId, requestTurnId);
393
- }
394
- return result;
395
- }
396
353
  function dedupeSyntheticHistoricalEvents(events) {
397
354
  const groups = new Map();
398
355
  for (const event of events) {
@@ -451,23 +408,6 @@ function isDuplicateRuntimeOutput(requestOutput, runtimeOutput) {
451
408
  const runtime = comparableOutput(runtimeOutput);
452
409
  return !runtime || request === runtime || request.includes(runtime);
453
410
  }
454
- function promptCompatible(requestPrompt, runtimePrompt) {
455
- const request = comparableOutput(requestPrompt);
456
- const runtime = comparableOutput(runtimePrompt);
457
- if (!request || !runtime)
458
- return false;
459
- if (request === runtime)
460
- return true;
461
- return (request.length >= 40 && runtime.includes(request)) ||
462
- (runtime.length >= 40 && request.includes(runtime));
463
- }
464
- function outputCompatibleForInferredAlias(requestOutput, runtimeOutput, requestPrompt, runtimePrompt) {
465
- const request = comparableOutput(requestOutput);
466
- const runtime = comparableOutput(runtimeOutput);
467
- if (request && runtime)
468
- return request.includes(runtime) || runtime.includes(request);
469
- return comparableOutput(requestPrompt) === comparableOutput(runtimePrompt) && Boolean(request || runtime);
470
- }
471
411
  function comparableOutput(value) {
472
412
  return value.replace(/\s+/g, " ").trim();
473
413
  }
@@ -479,9 +419,6 @@ function turnInProgressError(sessionId, turn, latestCompleted) {
479
419
  latestCompletedTurnId: latestCompleted?.turnId,
480
420
  });
481
421
  }
482
- function isReconcileUnknownTag(tag) {
483
- return tag === "reconcile:unknown" || tag === "reconcile:not_found" || tag === "reconcile:uninspectable";
484
- }
485
422
  export async function rebuildTurnOutput(client, sessionId, turnId) {
486
423
  const events = await client.history(sessionId, 1000);
487
424
  const folded = foldAliasedRuntimeEvents(events);
@@ -25,7 +25,6 @@ export declare function structuredSessionProjection(client: ControllerClient, se
25
25
  sourceSessionId?: string;
26
26
  sourceCheckpointId?: string;
27
27
  capabilities: SessionSnapshot["capabilities"];
28
- tags: string[];
29
28
  orchestration: OrchestrationSummary;
30
29
  }>;
31
30
  export declare function compactSessionListItem(client: ControllerClient, session: SessionSnapshot, options?: {
@@ -41,7 +40,6 @@ export declare function compactSessionListItem(client: ControllerClient, session
41
40
  machineId?: string;
42
41
  machineName?: string;
43
42
  cwdName?: string;
44
- tags: string[];
45
43
  }>;
46
44
  export declare function conciseSessionSummary(client: ControllerClient, session: SessionSnapshot): Promise<{
47
45
  sessionId: string;
@@ -52,7 +50,6 @@ export declare function conciseSessionSummary(client: ControllerClient, session:
52
50
  status: SessionSnapshot["status"];
53
51
  state: OrchestrationState;
54
52
  updatedAt: number;
55
- tags: string[];
56
53
  }>;
57
54
  export declare function requireProjectedSession(client: ControllerClient, sessionId: string, action: string): Promise<SessionSnapshot>;
58
55
  export declare function machineSessionOverview(client: ControllerClient, sessions: SessionSnapshot[], machineId: string): Promise<{
@@ -34,7 +34,7 @@ function orchestrationStateFromStatus(status) {
34
34
  return "idle";
35
35
  if (status === "completed")
36
36
  return "completed";
37
- if (status === "failed" || status === "offline" || status === "unknown")
37
+ if (status === "failed" || status === "offline")
38
38
  return "blocked";
39
39
  return "closed";
40
40
  }
@@ -70,17 +70,6 @@ export function deriveOrchestration(session, events = []) {
70
70
  completed: false,
71
71
  };
72
72
  }
73
- if (latestTerminalTurn?.status === "unknown") {
74
- return {
75
- state: "blocked",
76
- rawStatus: session.status,
77
- needsUser: false,
78
- blocked: true,
79
- completed: false,
80
- reason: "execution-unknown",
81
- lastEventId: latestTerminalTurn.lastEventId,
82
- };
83
- }
84
73
  const state = orchestrationStateFromStatus(session.status);
85
74
  return {
86
75
  state,
@@ -128,7 +117,6 @@ export async function structuredSessionProjection(client, session, events = [])
128
117
  sourceSessionId: session.sourceSessionId,
129
118
  sourceCheckpointId: session.sourceCheckpointId,
130
119
  capabilities: session.capabilities,
131
- tags: Array.isArray(metadata.tags) ? metadata.tags.filter((tag) => typeof tag === "string") : [],
132
120
  orchestration,
133
121
  };
134
122
  }
@@ -147,7 +135,6 @@ export async function compactSessionListItem(client, session, options = {}) {
147
135
  state: orchestration.state,
148
136
  agent: metadata.agent ?? session.agent,
149
137
  updatedAt: session.updatedAt,
150
- tags: Array.isArray(metadata.tags) ? metadata.tags.filter((tag) => typeof tag === "string") : [],
151
138
  ...(options.includeMachine ? { machineId: session.machineId, machineName: options.machineName } : {}),
152
139
  ...(options.includeCwd ? { cwdName: cwdDisplayName(metadata.cwd ?? session.cwd) } : {}),
153
140
  };
@@ -164,7 +151,6 @@ export async function conciseSessionSummary(client, session) {
164
151
  status: session.status,
165
152
  state: orchestration.state,
166
153
  updatedAt: session.updatedAt,
167
- tags: Array.isArray(metadata.tags) ? metadata.tags.filter((tag) => typeof tag === "string") : [],
168
154
  };
169
155
  }
170
156
  export async function requireProjectedSession(client, sessionId, action) {
@@ -29,9 +29,9 @@ export type SessionMetadata = {
29
29
  cwd?: string;
30
30
  name?: string;
31
31
  requestedRuntimeName?: string;
32
+ runtime?: unknown;
32
33
  tags?: string[];
33
34
  tagKeys?: string[];
34
- runtime?: unknown;
35
35
  };
36
36
  export declare const idleSessionStatuses: SessionSnapshot["status"][];
37
37
  export type OrchestrationState = "pending" | "active" | "idle" | "completed" | "blocked" | "needs-user" | "closed";
@@ -30,10 +30,6 @@ Check local controller config, relay reachability, and daemon state.
30
30
  happy-elves remote add-controller [--device-id <id>] [--device-name <name>] --json
31
31
  happy-elves remote rename <deviceId> --name <name> --json
32
32
  happy-elves remote revoke <deviceId> --json
33
- happy-elves remote daemon-status <machineId> [--json]
34
- happy-elves remote daemon-restart <machineId> [--wait] [--timeout 2m] [--json]
35
- happy-elves remote daemon-update <machineId> [--version latest|0.1.0-beta.N] [--package-url <url> --sha256 <hex>] [--wait] [--timeout 10m] [--json]
36
- happy-elves remote daemon-logs <machineId> [--tail 100] [--json]
37
33
  `,
38
34
  machine: `Usage:
39
35
  happy-elves machine list [--verbose] [--json]
@@ -50,7 +46,7 @@ Check local controller config, relay reachability, and daemon state.
50
46
  file preview is read-only and limited to files inside --root.
51
47
  `,
52
48
  session: `Usage:
53
- happy-elves session create --machine <machineId> [--agent codex] [--cwd <path>] [--name <name>] [--permission-mode <mode>] [--hidden] [--source dogfood] [--tag <tag>] --json
49
+ happy-elves session create --machine <machineId> [--agent codex] [--cwd <path>] [--name <name>] [--permission-mode <mode>] [--tag <tag>] [--hidden --source dogfood] --json
54
50
  happy-elves session list [--machine <machineId>] [--agent <agent>] [--cwd <cwd>] [--name <name>] [--tag <tag>] [--limit n] [--all] [--verbose] [--json]
55
51
  happy-elves session tag add <sessionId> --tag <tag> --json
56
52
  happy-elves session tag remove <sessionId> --tag <tag> --json
@@ -76,7 +72,6 @@ Session management:
76
72
  repair-binding imports the matching runtime history row as a new loaded
77
73
  session and closes the empty/stale source session unless --keep-source is set.
78
74
  close archives a loaded session. There is no separate archive command.
79
- tags are encrypted session metadata used for release/reviewer/dogfood routing.
80
75
  `,
81
76
  turn: `Usage:
82
77
  happy-elves turn list <sessionId> [--limit 10] [--verbose] [--json]
@@ -85,7 +80,7 @@ Session management:
85
80
  happy-elves turn run <sessionId> (--text <prompt> | --text-file <path>) [--detach] [--timeout 1000s] [--inactivity-timeout 1000s] [--permission-mode approve-reads|approve-all|deny-all] [--memory off|readonly|readwrite] [--memory-project <key>] [--memory-top-n 3] [--json]
86
81
  happy-elves turn wait <sessionId> <turnId> [--timeout 1000s] --json
87
82
  happy-elves turn reconcile <sessionId> [turnId] --json
88
- happy-elves turn recover <sessionId> [turnId] --text <continuation> --confirm-risk [--copy-tags] [--detach] --json
83
+ happy-elves turn recover <sessionId> [turnId] --text <continuation> --confirm-risk [--detach] --json
89
84
  happy-elves turn cancel <sessionId> <turnId> [--reason <reason>] --json
90
85
  happy-elves turn rewind <sessionId> <turn-or-checkpoint-id> --json
91
86
  happy-elves turn fork <sessionId> <turn-or-checkpoint-id> --name <name> [--copy-tags] --json
@@ -117,22 +112,6 @@ Turn management:
117
112
 
118
113
  Workspace sync records account-level UI/library state shared across devices:
119
114
  session stars, recent sessions, pinned workspaces, and current project defaults.
120
- `,
121
- release: `Usage:
122
- happy-elves release profile list --json
123
- happy-elves release profile show [--profile <name>] --json
124
- happy-elves release profile set <name> --release-tag <tag> [--release-tag <tag>] [--reviewer-tag <tag>] [--dogfood-tag <tag>] [--no-daemon-update] --json
125
- happy-elves release resolve [--profile happy-elves] --json
126
- happy-elves release notify [--profile happy-elves] [--text 发布] [--detach] [--timeout 1000s] --json
127
- happy-elves release start [--profile happy-elves] [--expected-commit <sha>] [--target-machine <machineId>] [--no-daemon-update] [--wait] --json
128
- happy-elves release status [jobId] [--machine <machineId>] --json
129
- happy-elves release logs [jobId] [--machine <machineId>] [--tail 200] --json
130
-
131
- Release profiles resolve target sessions by encrypted session tags. The built-in
132
- happy-elves profile uses Happy Elves + Release Session for the release target.
133
- Release notify sends the short release prompt to that target with approve-all
134
- permissions and memory off, so agents do not have to reconstruct release flags.
135
- Release start runs a fixed daemon-local runner; it does not accept arbitrary shell.
136
115
  `,
137
116
  gateway: `Usage:
138
117
  happy-elves gateway enable [<channelId>] --channel lark --machine <machineId> (--cwd <cwd> | --session <sessionId>) [--agent codex] [--model <model>] --json
@@ -175,6 +154,16 @@ Schedule v1 is daemon-local repeat automation. Runs use normal Relay admission
175
154
  with deterministic requestId/turnId per occurrence. Offline due times are marked
176
155
  missed and are never auto-caught-up. Commands that take a scheduleId auto-locate
177
156
  the owning online daemon when --machine is omitted.
157
+ `,
158
+ release: `Usage:
159
+ happy-elves release profile list --json
160
+ happy-elves release profile show [--profile happy-elves] --json
161
+ happy-elves release profile set <name> --release-tag <tag[,tag]> [--reviewer-tag <tag[,tag]>] [--dogfood-tag <tag[,tag]>] --json
162
+ happy-elves release resolve --profile happy-elves --json
163
+ happy-elves release notify --profile happy-elves [--text 发布] [--detach] [--timeout 30m] --json
164
+
165
+ Release routing uses session tags. notify only sends a short prompt to the
166
+ resolved Release Session; it does not run a release runner or arbitrary shell.
178
167
  `,
179
168
  loop: `Usage:
180
169
  happy-elves loop create <sessionId> [--every 15m] (--prompt <text> | --prompt-file <path>) [--stop-on blocked] --json
@@ -230,15 +219,16 @@ Core commands:
230
219
  machine directory <machineId> [--path <path>] [--json]
231
220
 
232
221
  session list [--machine <machineId>] [--cwd <path>] [--limit 20] [--json]
233
- session create --machine <machineId> [--agent codex] [--cwd <path>] [--name <name>] [--hidden] [--tag <tag>] --json
234
- session tag add <sessionId> --tag <tag> --json
235
- session tag remove <sessionId> --tag <tag> --json
222
+ session create --machine <machineId> [--agent codex] [--cwd <path>] [--name <name>] --json
236
223
  session history --machine <machineId> [--cwd <path>] [--limit 20] --json
237
224
  session continue <runtimeSessionId> --machine <machineId> --json
238
225
  session repair-binding <sessionId> [--runtime-session <runtimeSessionId>] --json
239
226
  session status <sessionId> [--verbose] [--json]
240
227
  session diagnose <sessionId> [--limit 200] [--runtime-limit 500] [--repair-head] [--json]
241
228
  session close <sessionId> [--reason <reason>] --json
229
+ session tag add <sessionId> --tag <tag> --json
230
+ release resolve --profile happy-elves --json
231
+ release notify --profile happy-elves --json
242
232
 
243
233
  turn list <sessionId> [--limit 10] [--json]
244
234
  turn status <sessionId> <turnId> [--json]
@@ -246,7 +236,7 @@ Core commands:
246
236
  turn wait <sessionId> <turnId> [--timeout 1000s] [--json]
247
237
  turn result <sessionId> [<turnId>] [--json]
248
238
  turn reconcile <sessionId> [turnId] --json
249
- turn recover <sessionId> [turnId] --text <continuation> --confirm-risk [--copy-tags] [--json]
239
+ turn recover <sessionId> [turnId] --text <continuation> --confirm-risk [--json]
250
240
  turn cancel <sessionId> <turnId> [--reason <reason>] --json
251
241
  turn rewind <sessionId> <turn-or-checkpoint-id> --json
252
242
  turn fork <sessionId> <turn-or-checkpoint-id> --name <name> [--copy-tags] --json
@@ -260,12 +250,8 @@ Core commands:
260
250
  workspace star <sessionId> --json
261
251
  workspace pin-cwd --machine <machineId> --cwd <cwd> --json
262
252
 
263
- release resolve --profile happy-elves --json
264
- release notify --profile happy-elves --json
265
- release start --profile happy-elves --json
266
-
267
253
  gateway status --json
268
- gateway enable --channel lark --machine <machineId> --cwd <cwd> --json
254
+ gateway enable --channel fake --machine <machineId> --cwd <cwd> --json # debug only
269
255
  gateway test --conversation <id> --message-id <id> --text <prompt> --json
270
256
 
271
257
  memory save --project <key> --text <fact> --json
@@ -287,12 +273,12 @@ Common flows:
287
273
  Discover: machine list --json; session list --machine <machineId> --json
288
274
  Continue: session history --machine <machineId> --json; session continue <runtimeSessionId> --machine <machineId> --json
289
275
  Execute: turn run <sessionId> --text <prompt> --json; turn result <sessionId> <turnId> --json
290
- Branch: turn rewind <sessionId> <turnId> --json; turn fork <sessionId> <turnId> --name <name> [--copy-tags] --json
276
+ Branch: turn rewind <sessionId> <turnId> --json; turn fork <sessionId> <turnId> --name <name> --json
291
277
 
292
278
  More:
293
279
  happy-elves --skill
294
280
  happy-elves <domain> --help
295
- start, status, doctor, collect, config, account, daemon, relay, token, workspace, release, gateway, memory, schedule, loop.
281
+ start, status, doctor, collect, config, account, daemon, relay, token, workspace, gateway, memory, schedule, loop.
296
282
  `;
297
283
  }
298
284
  export function skillText() {
@@ -318,19 +304,6 @@ Recommended agent workflow:
318
304
  6. turn wait <sessionId> <turnId> --json
319
305
  7. turn result <sessionId> <turnId> --json
320
306
 
321
- Release / reviewer / dogfood workflow:
322
- 1. Tag the release session once:
323
- session tag add <sessionId> --tag "Happy Elves" --json
324
- session tag add <sessionId> --tag "Release Session" --json
325
- 2. Resolve before acting:
326
- release resolve --profile happy-elves --json
327
- 3. Notify release with the standard short prompt and release permissions:
328
- release notify --profile happy-elves --json
329
- 4. Start the structured release runner only when explicitly needed:
330
- release start --profile happy-elves --json
331
- 5. Use hidden sessions for temporary dogfood:
332
- session create --hidden --source dogfood --tag "Happy Elves" --tag "Dogfood" ...
333
-
334
307
  Concepts:
335
308
  Loaded session: a Happy Elves control-plane session that can be operated by
336
309
  this CLI.
@@ -60,12 +60,52 @@ export async function listWorkspaceHistoricalSessions(client, input) {
60
60
  }
61
61
  }));
62
62
  return {
63
- sessions: rows
63
+ sessions: await enrichHistoricalLoadedSessionIds(client, rows
64
64
  .flatMap((row) => row.sessions)
65
65
  .sort((left, right) => right.updatedAt - left.updatedAt || left.runtimeSessionId.localeCompare(right.runtimeSessionId))
66
- .slice(0, input.limit),
66
+ .slice(0, input.limit)),
67
67
  errors: rows.flatMap((row) => row.error ? [row.error] : []),
68
68
  machines: rows.map((row) => row.machine),
69
69
  };
70
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
+ }
71
111
  //# sourceMappingURL=workspace.js.map
@@ -9,7 +9,6 @@ export async function handleMemory({ domain, action, positional, flags }) {
9
9
  const projectKey = await resolveMemoryProjectKey(client, flags, machineId);
10
10
  const result = await client.memory({ machineId, action: "overview", projectKey, mode: parseMemoryMode(flags.mode) ?? "readonly" });
11
11
  if (!wantsJson(flags)) {
12
- printMemoryProject(projectKey);
13
12
  const files = result.overview?.files ?? [];
14
13
  if (files.length === 0)
15
14
  console.log("No memory files.");
@@ -18,7 +17,7 @@ export async function handleMemory({ domain, action, positional, flags }) {
18
17
  console.log(`${file.layer} ${file.path} ${file.lineCount} lines ${file.updatedAt}`);
19
18
  return true;
20
19
  }
21
- ok(`memory.${action}`, withMemoryProject(result, projectKey));
20
+ ok(`memory.${action}`, result);
22
21
  return true;
23
22
  }
24
23
  if (action === "save" || action === "write") {
@@ -44,8 +43,7 @@ export async function handleMemory({ domain, action, positional, flags }) {
44
43
  ...(typeof flags.date === "string" ? { date: flags.date } : {}),
45
44
  },
46
45
  });
47
- printMemoryProjectIfHuman(flags, projectKey);
48
- ok("memory.save", withMemoryProject(result, projectKey));
46
+ ok("memory.save", result);
49
47
  return true;
50
48
  }
51
49
  if (action === "read") {
@@ -54,11 +52,10 @@ export async function handleMemory({ domain, action, positional, flags }) {
54
52
  const path = typeof flags.path === "string" ? flags.path : requirePositional(positional[0], "path");
55
53
  const result = await client.memory({ machineId, action: "read", projectKey, path });
56
54
  if (!wantsJson(flags)) {
57
- printMemoryProject(projectKey);
58
55
  console.log(result.content ?? "");
59
56
  return true;
60
57
  }
61
- ok("memory.read", withMemoryProject(result, projectKey));
58
+ ok("memory.read", result);
62
59
  return true;
63
60
  }
64
61
  if (action === "search") {
@@ -70,7 +67,6 @@ export async function handleMemory({ domain, action, positional, flags }) {
70
67
  throw new CliError("Invalid --limit", "INVALID_ARGUMENT");
71
68
  const result = await client.memory({ machineId, action: "search", projectKey, query, limit });
72
69
  if (!wantsJson(flags)) {
73
- printMemoryProject(projectKey);
74
70
  const results = result.results ?? [];
75
71
  if (results.length === 0)
76
72
  console.log("No matching memory.");
@@ -84,7 +80,7 @@ export async function handleMemory({ domain, action, positional, flags }) {
84
80
  }
85
81
  return true;
86
82
  }
87
- ok("memory.search", withMemoryProject(result, projectKey));
83
+ ok("memory.search", result);
88
84
  return true;
89
85
  }
90
86
  if (action === "promote") {
@@ -105,33 +101,17 @@ export async function handleMemory({ domain, action, positional, flags }) {
105
101
  ...(typeof flags.title === "string" ? { title: flags.title } : {}),
106
102
  },
107
103
  });
108
- printMemoryProjectIfHuman(flags, projectKey);
109
- ok("memory.promote", withMemoryProject(result, projectKey));
104
+ ok("memory.promote", result);
110
105
  return true;
111
106
  }
112
107
  if (action === "reindex" || action === "sync") {
113
108
  const machineId = await resolveMemoryMachineId(client, flags);
114
109
  const projectKey = await resolveMemoryProjectKey(client, flags, machineId);
115
- const result = await client.memory({ machineId, action, projectKey, mode: parseMemoryMode(flags.mode) ?? "readonly" });
116
- printMemoryProjectIfHuman(flags, projectKey);
117
- ok(`memory.${action}`, withMemoryProject(result, projectKey));
110
+ ok(`memory.${action}`, await client.memory({ machineId, action, projectKey, mode: parseMemoryMode(flags.mode) ?? "readonly" }));
118
111
  return true;
119
112
  }
120
113
  return false;
121
114
  }
122
- function withMemoryProject(result, projectKey) {
123
- if (result && typeof result === "object" && !Array.isArray(result)) {
124
- return { ...result, projectKey };
125
- }
126
- return { result, projectKey };
127
- }
128
- function printMemoryProjectIfHuman(flags, projectKey) {
129
- if (!wantsJson(flags))
130
- printMemoryProject(projectKey);
131
- }
132
- function printMemoryProject(projectKey) {
133
- console.error(`Memory project: ${projectKey}`);
134
- }
135
115
  async function resolveMemoryMachineId(client, flags) {
136
116
  if (typeof flags.machine === "string" && flags.machine.length > 0)
137
117
  return flags.machine;