@cydm/happy-elves 0.1.0-beta.240 → 0.1.0-beta.241
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/lib/session-output.js +53 -1
- package/apps/cli/dist/commands/lib/usage.js +6 -0
- package/apps/cli/dist/commands/session.js +1 -1
- package/apps/cli/package.json +1 -1
- package/apps/daemon/dist/schedule/handler.d.ts +3 -1
- package/apps/daemon/dist/schedule/handler.js +15 -1
- package/apps/daemon/package.json +1 -1
- package/package.json +1 -1
|
@@ -311,6 +311,7 @@ export function structuredOutputForRunningTurn(sessionId, turnId) {
|
|
|
311
311
|
};
|
|
312
312
|
}
|
|
313
313
|
function foldAliasedRuntimeEvents(events) {
|
|
314
|
+
events = dedupeSyntheticHistoricalEvents(events);
|
|
314
315
|
const profiles = new Map();
|
|
315
316
|
const runtimeToRequest = new Map();
|
|
316
317
|
for (const event of events) {
|
|
@@ -349,6 +350,57 @@ function foldAliasedRuntimeEvents(events) {
|
|
|
349
350
|
runtimeToRequest: duplicateRuntimeToRequest,
|
|
350
351
|
};
|
|
351
352
|
}
|
|
353
|
+
function dedupeSyntheticHistoricalEvents(events) {
|
|
354
|
+
const groups = new Map();
|
|
355
|
+
for (const event of events) {
|
|
356
|
+
const key = historicalComparableEventKey(event);
|
|
357
|
+
if (!key)
|
|
358
|
+
continue;
|
|
359
|
+
groups.set(key, [...(groups.get(key) ?? []), event]);
|
|
360
|
+
}
|
|
361
|
+
const keepIds = new Set();
|
|
362
|
+
const dropIds = new Set();
|
|
363
|
+
for (const group of groups.values()) {
|
|
364
|
+
if (group.length < 2 || !group.some(isSyntheticHistoricalEvent))
|
|
365
|
+
continue;
|
|
366
|
+
const preferred = group.find((event) => !isSyntheticHistoricalEvent(event)) ?? group[0];
|
|
367
|
+
if (preferred)
|
|
368
|
+
keepIds.add(preferred.id);
|
|
369
|
+
for (const event of group) {
|
|
370
|
+
if (event.id !== preferred?.id)
|
|
371
|
+
dropIds.add(event.id);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return events.filter((event) => !dropIds.has(event.id) || keepIds.has(event.id));
|
|
375
|
+
}
|
|
376
|
+
function isSyntheticHistoricalEvent(event) {
|
|
377
|
+
const messageId = event.messageId ?? "";
|
|
378
|
+
return messageId.startsWith("hist_") || messageId.startsWith("tail_");
|
|
379
|
+
}
|
|
380
|
+
function historicalComparableEventKey(event) {
|
|
381
|
+
const payload = event.decoded;
|
|
382
|
+
if (!payload)
|
|
383
|
+
return undefined;
|
|
384
|
+
if (payload.type === "user_prompt")
|
|
385
|
+
return [event.turnId, "user_prompt", comparableOutput(payload.text)].join("\0");
|
|
386
|
+
if (payload.type === "text_delta" && payload.stream !== "thought") {
|
|
387
|
+
return [event.turnId, "text_delta", payload.stream, comparableOutput(payload.text)].join("\0");
|
|
388
|
+
}
|
|
389
|
+
if (payload.type === "done") {
|
|
390
|
+
return [
|
|
391
|
+
event.turnId,
|
|
392
|
+
"done",
|
|
393
|
+
payload.status,
|
|
394
|
+
payload.currentHead ?? "",
|
|
395
|
+
payload.lastTurnId ?? "",
|
|
396
|
+
comparableOutput(payload.error ?? payload.stopReason ?? ""),
|
|
397
|
+
].join("\0");
|
|
398
|
+
}
|
|
399
|
+
if (payload.type === "memory_used") {
|
|
400
|
+
return [event.turnId, "memory_used", payload.mode, payload.projectKey, JSON.stringify(payload.memories)].join("\0");
|
|
401
|
+
}
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
352
404
|
function isDuplicateRuntimeOutput(requestOutput, runtimeOutput) {
|
|
353
405
|
const request = comparableOutput(requestOutput);
|
|
354
406
|
if (!request)
|
|
@@ -384,7 +436,7 @@ export async function rebuildTurnOutput(client, sessionId, turnId) {
|
|
|
384
436
|
}
|
|
385
437
|
export function conciseEvents(events) {
|
|
386
438
|
const result = [];
|
|
387
|
-
for (const event of events) {
|
|
439
|
+
for (const event of dedupeSyntheticHistoricalEvents(events)) {
|
|
388
440
|
const payload = event.decoded;
|
|
389
441
|
if (!payload)
|
|
390
442
|
continue;
|
|
@@ -76,6 +76,8 @@ Session management:
|
|
|
76
76
|
happy-elves turn result <sessionId> [<turnId>] [--verbose] [--json]
|
|
77
77
|
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]
|
|
78
78
|
happy-elves turn wait <sessionId> <turnId> [--timeout 1000s] --json
|
|
79
|
+
happy-elves turn reconcile <sessionId> [turnId] --json
|
|
80
|
+
happy-elves turn recover <sessionId> [turnId] --text <continuation> --confirm-risk [--detach] --json
|
|
79
81
|
happy-elves turn cancel <sessionId> <turnId> [--reason <reason>] --json
|
|
80
82
|
happy-elves turn rewind <sessionId> <turn-or-checkpoint-id> --json
|
|
81
83
|
happy-elves turn fork <sessionId> <turn-or-checkpoint-id> --name <name> --json
|
|
@@ -84,6 +86,8 @@ Turn management:
|
|
|
84
86
|
run starts one agent execution. It waits by default; use --detach for
|
|
85
87
|
background execution.
|
|
86
88
|
wait/result inspect a specific turn.
|
|
89
|
+
reconcile checks provider state without starting, resuming, or cancelling work.
|
|
90
|
+
recover creates a risk-confirmed recovery session and only sends the new continuation.
|
|
87
91
|
rewind/fork operate on a turn or checkpoint id supplied by runtime history.
|
|
88
92
|
`,
|
|
89
93
|
collect: `Usage:
|
|
@@ -214,6 +218,8 @@ Core commands:
|
|
|
214
218
|
turn run <sessionId> --text <prompt> [--timeout 1000s] [--json]
|
|
215
219
|
turn wait <sessionId> <turnId> [--timeout 1000s] [--json]
|
|
216
220
|
turn result <sessionId> [<turnId>] [--json]
|
|
221
|
+
turn reconcile <sessionId> [turnId] --json
|
|
222
|
+
turn recover <sessionId> [turnId] --text <continuation> --confirm-risk [--json]
|
|
217
223
|
turn cancel <sessionId> <turnId> [--reason <reason>] --json
|
|
218
224
|
turn rewind <sessionId> <turn-or-checkpoint-id> --json
|
|
219
225
|
turn fork <sessionId> <turn-or-checkpoint-id> --name <name> --json
|
|
@@ -427,7 +427,7 @@ export async function handleSession({ domain, action, positional, flags }) {
|
|
|
427
427
|
const latestCompletedTurn = turns.find((turn) => turn.status === "completed");
|
|
428
428
|
const latestTerminalTurn = turns.find((turn) => turn.status !== "running");
|
|
429
429
|
const orchestration = deriveOrchestration(session, recentEvents);
|
|
430
|
-
const latestOutput = await readStoredTurnOutput(session.id).catch(() => undefined);
|
|
430
|
+
const latestOutput = await readStoredTurnOutput(session.id, latestCompletedTurn?.turnId).catch(async () => await readStoredTurnOutput(session.id).catch(() => undefined));
|
|
431
431
|
const terminalOutput = latestCompletedTurn?.output || latestCompletedTurn?.terminalText || latestTerminalTurn?.output || latestTerminalTurn?.terminalText || undefined;
|
|
432
432
|
const data = {
|
|
433
433
|
state: orchestration.state,
|
package/apps/cli/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { type MachineCommand } from "../../../../packages/shared/dist/index.js";
|
|
1
|
+
import { type MachineCommand, type ScheduleRecord } from "../../../../packages/shared/dist/index.js";
|
|
2
2
|
import type { DaemonConfig } from "../types.js";
|
|
3
3
|
type ScheduleCommand = Extract<MachineCommand, {
|
|
4
4
|
type: "machine:schedule";
|
|
5
5
|
}>;
|
|
6
6
|
export declare function handleScheduleCommand(ws: WebSocket, config: DaemonConfig, command: ScheduleCommand): Promise<void>;
|
|
7
|
+
declare function withSchedulePreview(schedule: ScheduleRecord): ScheduleRecord;
|
|
8
|
+
export declare const __testWithSchedulePreview: typeof withSchedulePreview;
|
|
7
9
|
export {};
|
|
@@ -55,10 +55,16 @@ async function executeScheduleCommand(config, command) {
|
|
|
55
55
|
}
|
|
56
56
|
if (command.action === "pause" || command.action === "resume" || command.action === "delete") {
|
|
57
57
|
const nextStatus = command.action === "pause" ? "paused" : command.action === "resume" ? "active" : "deleted";
|
|
58
|
+
const nowMs = Date.now();
|
|
58
59
|
const store = await updateScheduleStore((current) => ({
|
|
59
60
|
...current,
|
|
60
61
|
schedules: current.schedules.map((schedule) => schedule.id === command.scheduleId
|
|
61
|
-
? {
|
|
62
|
+
? {
|
|
63
|
+
...schedule,
|
|
64
|
+
status: nextStatus,
|
|
65
|
+
...(nextStatus === "active" ? { nextRunAt: nextRunAtForSchedule(schedule, nowMs) } : { nextRunAt: undefined }),
|
|
66
|
+
updatedAt: new Date(nowMs).toISOString(),
|
|
67
|
+
}
|
|
62
68
|
: schedule),
|
|
63
69
|
}));
|
|
64
70
|
return {
|
|
@@ -100,12 +106,20 @@ function requireSchedule(store, scheduleId) {
|
|
|
100
106
|
return schedule;
|
|
101
107
|
}
|
|
102
108
|
function withSchedulePreview(schedule) {
|
|
109
|
+
if (schedule.status !== "active") {
|
|
110
|
+
return {
|
|
111
|
+
...schedule,
|
|
112
|
+
nextRunAt: undefined,
|
|
113
|
+
previewRunAt: [],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
103
116
|
return {
|
|
104
117
|
...schedule,
|
|
105
118
|
nextRunAt: schedule.nextRunAt ?? nextRunAtForSchedule(schedule, Date.now()),
|
|
106
119
|
previewRunAt: nextRunPreviewForSchedule(schedule, 3, Date.now()),
|
|
107
120
|
};
|
|
108
121
|
}
|
|
122
|
+
export const __testWithSchedulePreview = withSchedulePreview;
|
|
109
123
|
function normalizeCreateInput(input) {
|
|
110
124
|
const prompt = input.prompt?.trim();
|
|
111
125
|
if (!prompt)
|
package/apps/daemon/package.json
CHANGED