@cydm/happy-elves 0.1.0-beta.310 → 0.1.0-beta.312
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/args.js +8 -1
- package/apps/cli/dist/commands/lib/status.js +15 -3
- package/apps/cli/dist/commands/release.js +30 -3
- package/apps/cli/dist/commands/session.js +1 -1
- package/apps/cli/package.json +1 -1
- package/apps/daemon/dist/session/lifecycle.js +21 -3
- package/apps/daemon/dist/session/metadata.d.ts +1 -1
- package/apps/daemon/dist/session/metadata.js +4 -0
- package/apps/daemon/dist/session/prompt.js +8 -0
- package/apps/daemon/dist/types.d.ts +6 -0
- package/apps/daemon/package.json +1 -1
- package/package.json +1 -1
- package/packages/shared/dist/args.d.ts +1 -0
- package/packages/shared/dist/args.js +8 -2
|
@@ -116,8 +116,15 @@ const booleanFlags = new Set([
|
|
|
116
116
|
]);
|
|
117
117
|
const knownFlags = new Set([...valueFlags, ...booleanFlags]);
|
|
118
118
|
const dashPrefixedValueFlags = new Set(["secret"]);
|
|
119
|
+
const repeatableValueFlags = new Set([
|
|
120
|
+
"tag",
|
|
121
|
+
"tags",
|
|
122
|
+
"release-tag",
|
|
123
|
+
"reviewer-tag",
|
|
124
|
+
"dogfood-tag",
|
|
125
|
+
]);
|
|
119
126
|
export function parseCliFlags(argv) {
|
|
120
|
-
const parsed = parseSharedFlags(argv, { valueFlags, dashPrefixedValueFlags });
|
|
127
|
+
const parsed = parseSharedFlags(argv, { valueFlags, dashPrefixedValueFlags, repeatableValueFlags });
|
|
121
128
|
const unknown = Object.keys(parsed.flags).filter((flag) => !knownFlags.has(flag));
|
|
122
129
|
if (unknown.length > 0) {
|
|
123
130
|
throw new CliError(`Unknown flag: --${unknown[0]}`, "UNKNOWN_FLAG");
|
|
@@ -14,7 +14,10 @@ export async function topLevelStatus(flags) {
|
|
|
14
14
|
const relayError = snapshotResult.status === "rejected"
|
|
15
15
|
? snapshotResult.reason instanceof Error ? snapshotResult.reason.message : String(snapshotResult.reason)
|
|
16
16
|
: undefined;
|
|
17
|
-
const
|
|
17
|
+
const visibleSessions = snapshot
|
|
18
|
+
? await visibleStatusSessions(client, snapshot.sessions)
|
|
19
|
+
: [];
|
|
20
|
+
const latestSession = [...visibleSessions].sort((left, right) => right.updatedAt - left.updatedAt)[0];
|
|
18
21
|
const latestOutput = latestSession ? await readStoredTurnOutput(latestSession.id).catch(() => undefined) : undefined;
|
|
19
22
|
const latestRelayOutput = latestSession && !latestOutput
|
|
20
23
|
? lastAssistantOutput(await client.history(latestSession.id, 200).catch(() => []))
|
|
@@ -31,8 +34,8 @@ export async function topLevelStatus(flags) {
|
|
|
31
34
|
onlineCount: snapshot?.machines.filter((machine) => machine.online).length ?? 0,
|
|
32
35
|
},
|
|
33
36
|
sessions: {
|
|
34
|
-
count:
|
|
35
|
-
runningCount:
|
|
37
|
+
count: visibleSessions.length,
|
|
38
|
+
runningCount: visibleSessions.filter((session) => session.status === "running").length,
|
|
36
39
|
},
|
|
37
40
|
latestSession: latestSession ? {
|
|
38
41
|
sessionId: latestSession.id,
|
|
@@ -64,4 +67,13 @@ export async function topLevelStatus(flags) {
|
|
|
64
67
|
if (!data.relay.ok)
|
|
65
68
|
process.exitCode = 1;
|
|
66
69
|
}
|
|
70
|
+
async function visibleStatusSessions(client, sessions) {
|
|
71
|
+
const projected = await Promise.all(sessions.map(async (session) => ({
|
|
72
|
+
session,
|
|
73
|
+
metadata: await client.decodeSessionMetadata(session).catch(() => ({})),
|
|
74
|
+
})));
|
|
75
|
+
return projected
|
|
76
|
+
.filter(({ session, metadata }) => session.status !== "closed" && metadata.hiddenFromWorkspace !== true && metadata.source !== "dogfood")
|
|
77
|
+
.map(({ session }) => session);
|
|
78
|
+
}
|
|
67
79
|
//# sourceMappingURL=status.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
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";
|
|
4
|
+
import { CliError, ControllerClient, DEFAULT_COMMAND_TIMEOUT_MS, compactText, ok, parseDurationMs, readConfig, releaseProfilesPath, wantsJson, wantsVerbose, } from "./lib/index.js";
|
|
5
5
|
const defaultReleaseProfile = {
|
|
6
6
|
name: "happy-elves",
|
|
7
7
|
releaseSessionTags: ["Happy Elves", "Release Session"],
|
|
@@ -61,7 +61,7 @@ export async function handleRelease({ domain, action, positional, flags }) {
|
|
|
61
61
|
ackTimeoutMs: parseDurationMs(flags["ack-timeout"], 15_000),
|
|
62
62
|
inactivityTimeoutMs: parseDurationMs(flags["inactivity-timeout"] ?? flags["runtime-timeout"], DEFAULT_COMMAND_TIMEOUT_MS),
|
|
63
63
|
});
|
|
64
|
-
printReleaseOutput("release.notify", {
|
|
64
|
+
printReleaseOutput("release.notify", await releaseNotifyOutput(client, {
|
|
65
65
|
profile: profile.name,
|
|
66
66
|
releaseTarget,
|
|
67
67
|
prompt: text,
|
|
@@ -70,7 +70,7 @@ export async function handleRelease({ domain, action, positional, flags }) {
|
|
|
70
70
|
memoryMode: "off",
|
|
71
71
|
wait,
|
|
72
72
|
...result,
|
|
73
|
-
}, flags);
|
|
73
|
+
}, flags), flags);
|
|
74
74
|
return true;
|
|
75
75
|
}
|
|
76
76
|
return false;
|
|
@@ -82,6 +82,33 @@ function releaseNotifyText(flags) {
|
|
|
82
82
|
const value = typeof flags.text === "string" ? flags.text.trim() : "";
|
|
83
83
|
return value || "发布";
|
|
84
84
|
}
|
|
85
|
+
async function releaseNotifyOutput(client, data, flags) {
|
|
86
|
+
if (wantsVerbose(flags))
|
|
87
|
+
return data;
|
|
88
|
+
const decoded = await client.decodeEvents(data.events).catch(() => []);
|
|
89
|
+
const turnEvents = data.turnId ? decoded.filter((event) => event.turnId === data.turnId) : decoded;
|
|
90
|
+
const done = [...turnEvents].reverse().find((event) => event.decoded?.type === "done")?.decoded;
|
|
91
|
+
const finalOutput = turnEvents
|
|
92
|
+
.filter((event) => event.decoded?.type === "text_delta" && event.decoded.stream !== "thought")
|
|
93
|
+
.map((event) => event.decoded?.type === "text_delta" ? event.decoded.text : "")
|
|
94
|
+
.join("");
|
|
95
|
+
return {
|
|
96
|
+
profile: data.profile,
|
|
97
|
+
releaseTarget: data.releaseTarget,
|
|
98
|
+
promptPreview: data.promptPreview,
|
|
99
|
+
permissionMode: data.permissionMode,
|
|
100
|
+
memoryMode: data.memoryMode,
|
|
101
|
+
wait: data.wait,
|
|
102
|
+
requestId: data.requestId,
|
|
103
|
+
sessionId: data.sessionId,
|
|
104
|
+
turnId: data.turnId,
|
|
105
|
+
admission: data.admission,
|
|
106
|
+
dispatch: data.dispatch,
|
|
107
|
+
eventCount: data.events.length,
|
|
108
|
+
...(done && typeof done === "object" && "status" in done ? { status: done.status } : {}),
|
|
109
|
+
...(finalOutput ? { finalOutputPreview: compactText(finalOutput, 1200) } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
85
112
|
function tagsFromFlagValue(value) {
|
|
86
113
|
if (typeof value !== "string")
|
|
87
114
|
return [];
|
|
@@ -406,7 +406,7 @@ export async function handleSession({ domain, action, positional, flags }) {
|
|
|
406
406
|
const visibleSessions = flags.all === true
|
|
407
407
|
? allSessions
|
|
408
408
|
: (await Promise.all(allSessions.map(async (session) => ({ session, metadata: await client.decodeSessionMetadata(session) }))))
|
|
409
|
-
.filter(({ session, metadata }) => session.status !== "closed" && metadata.hiddenFromWorkspace !== true)
|
|
409
|
+
.filter(({ session, metadata }) => session.status !== "closed" && metadata.hiddenFromWorkspace !== true && metadata.source !== "dogfood")
|
|
410
410
|
.map(({ session }) => session);
|
|
411
411
|
const { items: sessions, page } = selectWindow(visibleSessions, flags, 20);
|
|
412
412
|
if (wantsJson(flags) || wantsVerbose(flags)) {
|
package/apps/cli/package.json
CHANGED
|
@@ -17,6 +17,8 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
17
17
|
const metadata = await commandSessionMetadata(config, command.encryptedMetadata);
|
|
18
18
|
const model = modelFromCommand(command.model ?? metadata?.model);
|
|
19
19
|
const tags = normalizeSessionTags(metadata?.tags);
|
|
20
|
+
const hiddenFromWorkspace = metadata?.hiddenFromWorkspace === true;
|
|
21
|
+
const source = typeof metadata?.source === "string" && metadata.source.trim() ? metadata.source.trim() : undefined;
|
|
20
22
|
const runtime = getRuntime(cwd);
|
|
21
23
|
let handle = await runtime.ensureSession({
|
|
22
24
|
sessionKey: command.sessionId,
|
|
@@ -44,6 +46,8 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
44
46
|
name: providerName ?? command.name,
|
|
45
47
|
...(model ? { model } : {}),
|
|
46
48
|
...(tags.length > 0 ? { tags } : {}),
|
|
49
|
+
...(hiddenFromWorkspace ? { hiddenFromWorkspace: true } : {}),
|
|
50
|
+
...(source ? { source } : {}),
|
|
47
51
|
handle,
|
|
48
52
|
};
|
|
49
53
|
sessions.set(command.sessionId, state);
|
|
@@ -111,6 +115,15 @@ export async function handleImportHistoricalSession(ws, config, command) {
|
|
|
111
115
|
handle,
|
|
112
116
|
};
|
|
113
117
|
const importedMetadata = await commandSessionMetadata(config, command.encryptedMetadata);
|
|
118
|
+
const importedTags = normalizeSessionTags(importedMetadata?.tags);
|
|
119
|
+
const importedHiddenFromWorkspace = importedMetadata?.hiddenFromWorkspace === true;
|
|
120
|
+
const importedSource = typeof importedMetadata?.source === "string" && importedMetadata.source.trim() ? importedMetadata.source.trim() : undefined;
|
|
121
|
+
if (importedTags.length > 0)
|
|
122
|
+
state.tags = importedTags;
|
|
123
|
+
if (importedHiddenFromWorkspace)
|
|
124
|
+
state.hiddenFromWorkspace = true;
|
|
125
|
+
if (importedSource)
|
|
126
|
+
state.source = importedSource;
|
|
114
127
|
sessions.set(command.sessionId, state);
|
|
115
128
|
const importedAt = new Date().toISOString();
|
|
116
129
|
const importedMetadataBase = {
|
|
@@ -261,9 +274,12 @@ function historicalSessionPage(value) {
|
|
|
261
274
|
export async function resumeSession(ws, config, sessionId, requestId, fallback, announceSuccess = true, syncDirection = "auto") {
|
|
262
275
|
const existing = sessions.get(sessionId);
|
|
263
276
|
if (existing) {
|
|
264
|
-
const hydratedExisting =
|
|
265
|
-
|
|
266
|
-
:
|
|
277
|
+
const hydratedExisting = {
|
|
278
|
+
...existing,
|
|
279
|
+
...(fallback?.tags && fallback.tags.length > 0 ? { tags: fallback.tags } : {}),
|
|
280
|
+
...(fallback?.hiddenFromWorkspace === true ? { hiddenFromWorkspace: true } : {}),
|
|
281
|
+
...(fallback?.source ? { source: fallback.source } : {}),
|
|
282
|
+
};
|
|
267
283
|
if (hydratedExisting !== existing)
|
|
268
284
|
sessions.set(sessionId, hydratedExisting);
|
|
269
285
|
const refreshed = await refreshRuntimeSessionName(hydratedExisting);
|
|
@@ -324,6 +340,8 @@ export async function resumeSession(ws, config, sessionId, requestId, fallback,
|
|
|
324
340
|
cwd,
|
|
325
341
|
name,
|
|
326
342
|
...(fallback?.tags && fallback.tags.length > 0 ? { tags: fallback.tags } : {}),
|
|
343
|
+
...(fallback?.hiddenFromWorkspace === true ? { hiddenFromWorkspace: true } : {}),
|
|
344
|
+
...(fallback?.source ? { source: fallback.source } : {}),
|
|
327
345
|
handle,
|
|
328
346
|
});
|
|
329
347
|
sessions.set(sessionId, state);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type EncryptedEnvelope, type MachineCommand } from "../../../../packages/shared/dist/index.js";
|
|
2
2
|
import type { DaemonConfig, SessionFallback, SessionMetadata, SessionState } from "../types.js";
|
|
3
|
-
export declare function encryptedSessionMetadata(config: DaemonConfig, sessionId: string, state: Pick<SessionState, "agent" | "cwd" | "name" | "handle" | "model" | "tags">, extra: Record<string, unknown>): Promise<EncryptedEnvelope>;
|
|
3
|
+
export declare function encryptedSessionMetadata(config: DaemonConfig, sessionId: string, state: Pick<SessionState, "agent" | "cwd" | "name" | "handle" | "model" | "tags" | "hiddenFromWorkspace" | "source">, extra: Record<string, unknown>): Promise<EncryptedEnvelope>;
|
|
4
4
|
export declare function commandSessionMetadata(config: DaemonConfig, encryptedMetadata?: EncryptedEnvelope): Promise<SessionMetadata | undefined>;
|
|
5
5
|
export declare function sessionFallbackFromCommand(config: DaemonConfig, command: Extract<MachineCommand, {
|
|
6
6
|
type: "machine:prompt" | "machine:resume" | "machine:rewind" | "machine:fork" | "machine:renameSession" | "machine:close";
|
|
@@ -6,6 +6,8 @@ export function encryptedSessionMetadata(config, sessionId, state, extra) {
|
|
|
6
6
|
name: state.name,
|
|
7
7
|
...(state.model ? { model: state.model } : {}),
|
|
8
8
|
...(state.tags && state.tags.length > 0 ? { tags: state.tags, tagKeys: sessionTagKeys(state.tags) } : {}),
|
|
9
|
+
...(state.hiddenFromWorkspace ? { hiddenFromWorkspace: true } : {}),
|
|
10
|
+
...(state.source ? { source: state.source } : {}),
|
|
9
11
|
runtime: {
|
|
10
12
|
backend: state.handle.backend,
|
|
11
13
|
runtimeSessionName: state.handle.runtimeSessionName,
|
|
@@ -41,6 +43,8 @@ export async function sessionFallbackFromCommand(config, command) {
|
|
|
41
43
|
name: metadata.name ?? command.sessionId,
|
|
42
44
|
...(typeof metadata.model === "string" && metadata.model.trim() ? { model: metadata.model.trim() } : {}),
|
|
43
45
|
...(tags.length > 0 ? { tags } : {}),
|
|
46
|
+
...(metadata.hiddenFromWorkspace === true ? { hiddenFromWorkspace: true } : {}),
|
|
47
|
+
...(typeof metadata.source === "string" && metadata.source.trim() ? { source: metadata.source.trim() } : {}),
|
|
44
48
|
emptyRuntimeSession: metadata.emptyRuntimeSession === true,
|
|
45
49
|
historicalBackfill: historicalBackfillStateFromMetadata(metadata),
|
|
46
50
|
runtime: metadata.runtime,
|
|
@@ -36,6 +36,14 @@ export async function handlePrompt(ws, config, command) {
|
|
|
36
36
|
}
|
|
37
37
|
if (fallback?.tags && fallback.tags.length > 0) {
|
|
38
38
|
session = { ...session, tags: fallback.tags };
|
|
39
|
+
}
|
|
40
|
+
if (fallback?.hiddenFromWorkspace === true) {
|
|
41
|
+
session = { ...session, hiddenFromWorkspace: true };
|
|
42
|
+
}
|
|
43
|
+
if (fallback?.source) {
|
|
44
|
+
session = { ...session, source: fallback.source };
|
|
45
|
+
}
|
|
46
|
+
if (session !== sessions.get(command.sessionId)) {
|
|
39
47
|
sessions.set(command.sessionId, session);
|
|
40
48
|
}
|
|
41
49
|
if (!claimSessionTurn(command.sessionId, command.requestId, command.turnId, "prompt")) {
|
|
@@ -33,6 +33,8 @@ export type SessionState = {
|
|
|
33
33
|
name: string;
|
|
34
34
|
model?: string;
|
|
35
35
|
tags?: string[];
|
|
36
|
+
hiddenFromWorkspace?: boolean;
|
|
37
|
+
source?: string;
|
|
36
38
|
handle: RuntimeHandle;
|
|
37
39
|
historicalBackfill?: HistoricalBackfillState;
|
|
38
40
|
};
|
|
@@ -58,6 +60,8 @@ export type SessionMetadata = {
|
|
|
58
60
|
model?: string;
|
|
59
61
|
tags?: string[];
|
|
60
62
|
tagKeys?: string[];
|
|
63
|
+
hiddenFromWorkspace?: boolean;
|
|
64
|
+
source?: string;
|
|
61
65
|
requestedRuntimeName?: string;
|
|
62
66
|
permissionMode?: PermissionMode;
|
|
63
67
|
importedFromRuntimeSessionId?: string;
|
|
@@ -90,6 +94,8 @@ export type SessionMetadata = {
|
|
|
90
94
|
export type SessionFallback = Pick<SessionState, "agent" | "cwd" | "name"> & {
|
|
91
95
|
model?: string;
|
|
92
96
|
tags?: string[];
|
|
97
|
+
hiddenFromWorkspace?: boolean;
|
|
98
|
+
source?: string;
|
|
93
99
|
emptyRuntimeSession?: boolean;
|
|
94
100
|
historicalBackfill?: HistoricalBackfillState;
|
|
95
101
|
runtime?: SessionMetadata["runtime"];
|
package/apps/daemon/package.json
CHANGED
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ export type ParsedArgs = {
|
|
|
5
5
|
export type ParseFlagsOptions = {
|
|
6
6
|
valueFlags?: Iterable<string>;
|
|
7
7
|
dashPrefixedValueFlags?: Iterable<string>;
|
|
8
|
+
repeatableValueFlags?: Iterable<string>;
|
|
8
9
|
};
|
|
9
10
|
export declare function parseFlags(argv: string[], options?: ParseFlagsOptions): ParsedArgs;
|
|
10
11
|
//# sourceMappingURL=args.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export function parseFlags(argv, options = {}) {
|
|
2
2
|
const valueFlags = new Set(options.valueFlags ?? []);
|
|
3
3
|
const dashPrefixedValueFlags = new Set(options.dashPrefixedValueFlags ?? []);
|
|
4
|
+
const repeatableValueFlags = new Set(options.repeatableValueFlags ?? []);
|
|
4
5
|
const positional = [];
|
|
5
6
|
const flags = {};
|
|
6
7
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -19,17 +20,22 @@ export function parseFlags(argv, options = {}) {
|
|
|
19
20
|
flags[key] = true;
|
|
20
21
|
}
|
|
21
22
|
else if (valueFlags.has(key) && (!next.startsWith("--") || dashPrefixedValueFlags.has(key))) {
|
|
22
|
-
flags[key] = next;
|
|
23
|
+
flags[key] = appendFlagValue(flags[key], next, repeatableValueFlags.has(key));
|
|
23
24
|
i++;
|
|
24
25
|
}
|
|
25
26
|
else if (next.startsWith("--")) {
|
|
26
27
|
flags[key] = true;
|
|
27
28
|
}
|
|
28
29
|
else {
|
|
29
|
-
flags[key] = next;
|
|
30
|
+
flags[key] = appendFlagValue(flags[key], next, repeatableValueFlags.has(key));
|
|
30
31
|
i++;
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
return { positional, flags };
|
|
34
35
|
}
|
|
36
|
+
function appendFlagValue(previous, next, repeatable) {
|
|
37
|
+
if (!repeatable || previous === undefined || previous === true || previous === false)
|
|
38
|
+
return next;
|
|
39
|
+
return `${previous},${next}`;
|
|
40
|
+
}
|
|
35
41
|
//# sourceMappingURL=args.js.map
|