@guildai/cli 0.9.1 → 0.11.0
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/dist/commands/agent/chat.js +10 -7
- package/dist/commands/agent/clone.js +2 -0
- package/dist/commands/agent/fork.js +3 -0
- package/dist/commands/agent/init.js +58 -44
- package/dist/commands/agent/list.js +5 -4
- package/dist/commands/agent/logs.d.ts +3 -0
- package/dist/commands/agent/logs.js +62 -0
- package/dist/commands/agent/owners.js +3 -3
- package/dist/commands/agent/pull.js +8 -12
- package/dist/commands/agent/save.js +5 -6
- package/dist/commands/agent/search.js +5 -4
- package/dist/commands/agent/test.js +9 -6
- package/dist/commands/agent/update.js +9 -1
- package/dist/commands/agent/versions.js +5 -4
- package/dist/commands/agent/workspaces.js +5 -4
- package/dist/commands/auth/login.js +1 -3
- package/dist/commands/chat.d.ts +9 -0
- package/dist/commands/chat.js +136 -32
- package/dist/commands/config/get.js +4 -4
- package/dist/commands/config/list.js +2 -3
- package/dist/commands/config/path.js +2 -3
- package/dist/commands/config/set.js +12 -12
- package/dist/commands/credentials/endpoint-list.js +5 -4
- package/dist/commands/credentials/list.js +5 -4
- package/dist/commands/credentials/policy-list.js +5 -4
- package/dist/commands/doctor.js +5 -5
- package/dist/commands/integration/connect.js +2 -2
- package/dist/commands/integration/create.js +2 -2
- package/dist/commands/integration/get.js +2 -2
- package/dist/commands/integration/list.js +5 -4
- package/dist/commands/integration/operation/create.js +4 -4
- package/dist/commands/integration/operation/list.js +5 -4
- package/dist/commands/integration/update.js +2 -2
- package/dist/commands/integration/version/build.js +2 -2
- package/dist/commands/integration/version/create.js +2 -2
- package/dist/commands/integration/version/get.js +2 -2
- package/dist/commands/integration/version/list.js +5 -4
- package/dist/commands/integration/version/publish.js +2 -2
- package/dist/commands/integration/version/test.js +2 -2
- package/dist/commands/job/get.js +2 -2
- package/dist/commands/session/create.js +1 -1
- package/dist/commands/session/events.js +3 -2
- package/dist/commands/session/list.js +5 -4
- package/dist/commands/session/tasks.js +5 -4
- package/dist/commands/setup.d.ts +16 -0
- package/dist/commands/setup.js +76 -46
- package/dist/commands/trigger/list.js +5 -4
- package/dist/commands/trigger/sessions.js +3 -2
- package/dist/commands/workspace/agent/list.js +5 -4
- package/dist/commands/workspace/context/list.js +5 -4
- package/dist/commands/workspace/list.js +5 -4
- package/dist/index.js +15 -4
- package/dist/lib/api-types.d.ts +4 -0
- package/dist/lib/api-types.js +4 -0
- package/dist/lib/auth.d.ts +1 -1
- package/dist/lib/auth.js +2 -2
- package/dist/lib/output-mode.d.ts +9 -2
- package/dist/lib/output-mode.js +23 -2
- package/dist/lib/output.d.ts +7 -1
- package/dist/lib/output.js +36 -5
- package/dist/lib/owner-helpers.d.ts +3 -0
- package/dist/lib/owner-helpers.js +17 -10
- package/dist/lib/session-events.d.ts +13 -2
- package/dist/lib/session-events.js +15 -1
- package/dist/lib/session-polling.js +9 -3
- package/dist/lib/session-resume.d.ts +15 -1
- package/dist/lib/session-resume.js +149 -16
- package/dist/lib/splash.js +3 -2
- package/dist/lib/stdin.d.ts +5 -1
- package/dist/lib/stdin.js +8 -1
- package/dist/lib/version-helpers.js +24 -8
- package/package.json +1 -1
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
* 2. GUILD_OWNER_ID environment variable
|
|
12
12
|
* 3. default_owner from ~/.guild/config.json
|
|
13
13
|
* 4. Fetch user + orgs from API:
|
|
14
|
-
* - No orgs → use current user
|
|
15
|
-
* -
|
|
16
|
-
* - Has orgs +
|
|
14
|
+
* - No orgs + non-interactive → use current user (single-account, stated explicitly)
|
|
15
|
+
* - No orgs + interactive → prompt with personal account as only choice
|
|
16
|
+
* - Has orgs + interactive → prompt to select from all accounts
|
|
17
|
+
* - Has orgs + non-interactive → error: require --owner flag
|
|
17
18
|
*/
|
|
18
19
|
import inquirer from 'inquirer';
|
|
19
20
|
import { loadGlobalConfig } from './guild-config.js';
|
|
@@ -35,7 +36,7 @@ export async function lookupOwner(client, val) {
|
|
|
35
36
|
return undefined;
|
|
36
37
|
}
|
|
37
38
|
export async function resolveOwnerId(options) {
|
|
38
|
-
const { ownerFlag, client, interactive } = options;
|
|
39
|
+
const { ownerFlag, client, interactive, requireExplicitOwner = false } = options;
|
|
39
40
|
// Priority 1: --owner flag
|
|
40
41
|
if (ownerFlag) {
|
|
41
42
|
debug('Using owner from --owner flag: %s', ownerFlag);
|
|
@@ -71,17 +72,23 @@ export async function resolveOwnerId(options) {
|
|
|
71
72
|
// Priority 4: Fetch user + orgs
|
|
72
73
|
const me = await client.get('/me');
|
|
73
74
|
const orgs = await client.fetchAll('/me/organizations');
|
|
74
|
-
// No orgs → use current user
|
|
75
|
-
if (orgs.length === 0) {
|
|
75
|
+
// No orgs + non-interactive → use current user (single account, stated explicitly by caller)
|
|
76
|
+
if (orgs.length === 0 && !interactive) {
|
|
76
77
|
debug('No organizations found, using current user as owner');
|
|
77
78
|
return { id: me.id, name: me.name, type: 'user' };
|
|
78
79
|
}
|
|
79
|
-
// Has orgs + non-interactive
|
|
80
|
-
if (!interactive) {
|
|
81
|
-
|
|
80
|
+
// Has orgs + non-interactive
|
|
81
|
+
if (orgs.length > 0 && !interactive) {
|
|
82
|
+
if (requireExplicitOwner) {
|
|
83
|
+
debug('Non-interactive mode with multiple accounts available, requiring --owner');
|
|
84
|
+
throw new Error('Owner is required in non-interactive mode when multiple accounts are available.\n\n' +
|
|
85
|
+
'Use --owner <name-or-id> to specify an owner, or set a default:\n' +
|
|
86
|
+
' guild config set default_owner <name-or-id>');
|
|
87
|
+
}
|
|
88
|
+
debug('Multiple accounts available, defaulting to current user');
|
|
82
89
|
return { id: me.id, name: me.name, type: 'user' };
|
|
83
90
|
}
|
|
84
|
-
//
|
|
91
|
+
// Interactive → prompt (always, even with single account)
|
|
85
92
|
const choices = [
|
|
86
93
|
{
|
|
87
94
|
name: `${me.name} (personal)`,
|
|
@@ -97,14 +97,23 @@ export interface TextContent {
|
|
|
97
97
|
type: 'text';
|
|
98
98
|
data: string;
|
|
99
99
|
}
|
|
100
|
+
export interface UnknownContent {
|
|
101
|
+
type: string;
|
|
102
|
+
data?: unknown;
|
|
103
|
+
}
|
|
104
|
+
export interface MultipartContent {
|
|
105
|
+
type: 'multipart/mixed';
|
|
106
|
+
parts: UnknownContent[];
|
|
107
|
+
}
|
|
100
108
|
export interface ResponseStreamContent {
|
|
101
109
|
type: 'application/guild-response-stream';
|
|
102
110
|
stream_id: string;
|
|
103
111
|
sequence: number;
|
|
104
|
-
status: 'streaming' | 'done' | 'aborted';
|
|
112
|
+
status: 'streaming' | 'done' | 'continued' | 'aborted';
|
|
105
113
|
text: string;
|
|
114
|
+
is_delta?: boolean;
|
|
106
115
|
}
|
|
107
|
-
export type AgentNotificationMessageContent = TextContent | ResponseStreamContent;
|
|
116
|
+
export type AgentNotificationMessageContent = TextContent | MultipartContent | ResponseStreamContent;
|
|
108
117
|
export interface AgentNotificationMessageEvent extends BaseEvent {
|
|
109
118
|
type: 'agent_notification_message';
|
|
110
119
|
content: AgentNotificationMessageContent;
|
|
@@ -181,6 +190,8 @@ export declare function isDoneResponseStreamEvent(event: SessionEvent): event is
|
|
|
181
190
|
status: 'done';
|
|
182
191
|
};
|
|
183
192
|
};
|
|
193
|
+
/** Apply a response-stream payload to the accumulated display text. */
|
|
194
|
+
export declare function applyResponseStreamText(currentText: string, content: ResponseStreamContent): string;
|
|
184
195
|
/** Extract display text from notification content. */
|
|
185
196
|
export declare function getAgentNotificationText(event: AgentNotificationMessageEvent): string;
|
|
186
197
|
/** Check if an event belongs to the root task or has no task context. */
|
|
@@ -96,9 +96,23 @@ export function isResponseStreamEvent(event) {
|
|
|
96
96
|
export function isDoneResponseStreamEvent(event) {
|
|
97
97
|
return isResponseStreamEvent(event) && event.content.status === 'done';
|
|
98
98
|
}
|
|
99
|
+
/** Apply a response-stream payload to the accumulated display text. */
|
|
100
|
+
export function applyResponseStreamText(currentText, content) {
|
|
101
|
+
return content.is_delta ? currentText + content.text : content.text;
|
|
102
|
+
}
|
|
99
103
|
/** Extract display text from notification content. */
|
|
100
104
|
export function getAgentNotificationText(event) {
|
|
101
|
-
|
|
105
|
+
if (event.content.type === 'text') {
|
|
106
|
+
return event.content.data;
|
|
107
|
+
}
|
|
108
|
+
if (event.content.type === 'application/guild-response-stream') {
|
|
109
|
+
return event.content.text;
|
|
110
|
+
}
|
|
111
|
+
if (event.content.type === 'multipart/mixed' && event.content.parts.length === 1) {
|
|
112
|
+
const part = event.content.parts[0];
|
|
113
|
+
return part.type === 'text' && typeof part.data === 'string' ? part.data : '';
|
|
114
|
+
}
|
|
115
|
+
return '';
|
|
102
116
|
}
|
|
103
117
|
/** Check if an event belongs to the root task or has no task context. */
|
|
104
118
|
export function isRootTaskEvent(event) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { debug, isDebugMode } from './errors.js';
|
|
4
4
|
import { shouldShowEvent } from './event-filter.js';
|
|
5
5
|
import { fetchEvents } from './session-events-fetch.js';
|
|
6
|
-
import { getAgentNotificationText, isDoneResponseStreamEvent, isResponseStreamEvent, isRootTaskEvent, } from './session-events.js';
|
|
6
|
+
import { applyResponseStreamText, getAgentNotificationText, isDoneResponseStreamEvent, isResponseStreamEvent, isRootTaskEvent, } from './session-events.js';
|
|
7
7
|
/**
|
|
8
8
|
* Poll for agent response using from_id cursor.
|
|
9
9
|
*
|
|
@@ -20,6 +20,7 @@ export async function pollForResponse(client, sessionId, afterEventId, maxWaitTi
|
|
|
20
20
|
const startTime = Date.now();
|
|
21
21
|
let fromId = afterEventId;
|
|
22
22
|
let responseStreamDone = null;
|
|
23
|
+
const responseStreamTexts = new Map();
|
|
23
24
|
while (Date.now() - startTime < maxWaitTime) {
|
|
24
25
|
const events = await fetchEvents(client, sessionId, { fromId });
|
|
25
26
|
let lastAgentRuntimeDone = null;
|
|
@@ -28,9 +29,11 @@ export async function pollForResponse(client, sessionId, afterEventId, maxWaitTi
|
|
|
28
29
|
debug(`pollForResponse event: ${event.type}`);
|
|
29
30
|
if (event.type === 'agent_notification_message') {
|
|
30
31
|
if (isResponseStreamEvent(event)) {
|
|
32
|
+
const streamText = applyResponseStreamText(responseStreamTexts.get(event.content.stream_id) ?? '', event.content);
|
|
33
|
+
responseStreamTexts.set(event.content.stream_id, streamText);
|
|
31
34
|
if (isRootTaskEvent(event) && isDoneResponseStreamEvent(event)) {
|
|
32
35
|
responseStreamDone = {
|
|
33
|
-
response:
|
|
36
|
+
response: streamText,
|
|
34
37
|
lastEventId: event.id,
|
|
35
38
|
};
|
|
36
39
|
}
|
|
@@ -91,6 +94,7 @@ export async function pollForResponseWithEvents(client, sessionId, eventFilter,
|
|
|
91
94
|
const startTime = Date.now();
|
|
92
95
|
let fromId = afterEventId;
|
|
93
96
|
let responseStreamDone = null;
|
|
97
|
+
const responseStreamTexts = new Map();
|
|
94
98
|
while (Date.now() - startTime < maxWaitTime) {
|
|
95
99
|
const events = await fetchEvents(client, sessionId, { fromId });
|
|
96
100
|
let lastAgentRuntimeDone = null;
|
|
@@ -105,9 +109,11 @@ export async function pollForResponseWithEvents(client, sessionId, eventFilter,
|
|
|
105
109
|
}
|
|
106
110
|
if (event.type === 'agent_notification_message') {
|
|
107
111
|
if (isResponseStreamEvent(event)) {
|
|
112
|
+
const streamText = applyResponseStreamText(responseStreamTexts.get(event.content.stream_id) ?? '', event.content);
|
|
113
|
+
responseStreamTexts.set(event.content.stream_id, streamText);
|
|
108
114
|
if (isRootTaskEvent(event) && isDoneResponseStreamEvent(event)) {
|
|
109
115
|
responseStreamDone = {
|
|
110
|
-
response:
|
|
116
|
+
response: streamText,
|
|
111
117
|
lastEventId: event.id,
|
|
112
118
|
};
|
|
113
119
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GuildAPIClient } from './api-client.js';
|
|
2
|
-
import { SessionEvent, Session } from './session-events.js';
|
|
2
|
+
import { type ResponseStreamContent, SessionEvent, Session } from './session-events.js';
|
|
3
3
|
/**
|
|
4
4
|
* Print a dimmed resume hint to stderr on session exit.
|
|
5
5
|
* Only call when a session ID is available.
|
|
@@ -19,6 +19,20 @@ export interface DisplayMessage {
|
|
|
19
19
|
type: 'user' | 'assistant' | 'progress';
|
|
20
20
|
timestamp?: string;
|
|
21
21
|
}
|
|
22
|
+
export interface ResponseStreamResumeState {
|
|
23
|
+
keys: Map<string, string>;
|
|
24
|
+
contents: Map<string, ResponseStreamContent[]>;
|
|
25
|
+
texts: Map<string, string>;
|
|
26
|
+
timestamps: Map<string, string>;
|
|
27
|
+
statuses: Map<string, ResponseStreamContent['status']>;
|
|
28
|
+
keysByTask: Map<string, Set<string>>;
|
|
29
|
+
}
|
|
30
|
+
export interface SessionResumeDisplay {
|
|
31
|
+
displayMessages: DisplayMessage[];
|
|
32
|
+
responseStreamState: ResponseStreamResumeState;
|
|
33
|
+
}
|
|
34
|
+
export declare function responseStreamResumeStateFromEvents(events: SessionEvent[]): ResponseStreamResumeState;
|
|
35
|
+
export declare function prepareSessionResumeDisplay(events: SessionEvent[]): SessionResumeDisplay;
|
|
22
36
|
/**
|
|
23
37
|
* Convert session events to display messages for resume.
|
|
24
38
|
* Maps user_message, agent_notification_message, and agent_notification_error
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import { marked } from 'marked';
|
|
9
9
|
import { markedTerminal } from 'marked-terminal';
|
|
10
|
-
import { getAgentNotificationText, isResponseStreamEvent, } from './session-events.js';
|
|
10
|
+
import { applyResponseStreamText, getAgentNotificationText, isResponseStreamEvent, isRootTaskEvent, } from './session-events.js';
|
|
11
11
|
import { fetchEvents } from './session-events-fetch.js';
|
|
12
12
|
import { brand, code as codeColor } from './colors.js';
|
|
13
13
|
// Configure marked for terminal rendering (same config as chat.tsx)
|
|
@@ -48,13 +48,127 @@ export async function fetchSession(client, sessionId) {
|
|
|
48
48
|
const session = (await client.get(`/sessions/${sessionId}`));
|
|
49
49
|
return session;
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
function renderAssistantText(key, text, timestamp) {
|
|
52
|
+
const rendered = renderMarkdown(text);
|
|
53
|
+
const messageContent = `${chalk.green('●')} ${chalk.bold('assistant')}\n${rendered.trim()}`;
|
|
54
|
+
return {
|
|
55
|
+
key,
|
|
56
|
+
content: messageContent,
|
|
57
|
+
type: 'assistant',
|
|
58
|
+
timestamp,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function textMatches(left, right) {
|
|
62
|
+
return left === right;
|
|
63
|
+
}
|
|
64
|
+
function formatDisplayTimestamp(timestamp) {
|
|
65
|
+
if (timestamp === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
const date = new Date(timestamp);
|
|
68
|
+
if (Number.isNaN(date.getTime()))
|
|
69
|
+
return timestamp;
|
|
70
|
+
return date.toLocaleTimeString();
|
|
71
|
+
}
|
|
72
|
+
function upsertResponseStreamEvent(events, event) {
|
|
73
|
+
const existingIndex = events.findIndex((existing) => existing.content.sequence === event.content.sequence);
|
|
74
|
+
if (existingIndex === -1) {
|
|
75
|
+
events.push(event);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
events[existingIndex] = event;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function collectResponseStreamResumeEntries(events) {
|
|
82
|
+
const responseStreamGroups = new Map();
|
|
83
|
+
const finalMessagesByTask = new Map();
|
|
84
|
+
for (const [index, event] of events.entries()) {
|
|
85
|
+
if (event.type !== 'agent_notification_message')
|
|
86
|
+
continue;
|
|
87
|
+
if (!isRootTaskEvent(event))
|
|
88
|
+
continue;
|
|
89
|
+
if (isResponseStreamEvent(event)) {
|
|
90
|
+
const streamId = event.content.stream_id;
|
|
91
|
+
const current = responseStreamGroups.get(streamId);
|
|
92
|
+
if (current) {
|
|
93
|
+
upsertResponseStreamEvent(current.events, event);
|
|
94
|
+
// Insertion order and sequence can diverge if backfilled events arrive out
|
|
95
|
+
// of order; use insertion index only for "later final message" dedupe.
|
|
96
|
+
current.lastIndex = Math.max(current.lastIndex, index);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
responseStreamGroups.set(streamId, {
|
|
100
|
+
events: [event],
|
|
101
|
+
lastIndex: index,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const taskId = event.task?.id;
|
|
107
|
+
if (!taskId)
|
|
108
|
+
continue;
|
|
109
|
+
const text = getAgentNotificationText(event);
|
|
110
|
+
if (!text.trim())
|
|
111
|
+
continue;
|
|
112
|
+
const finalMessages = finalMessagesByTask.get(taskId) ?? [];
|
|
113
|
+
finalMessages.push({ index, text });
|
|
114
|
+
finalMessagesByTask.set(taskId, finalMessages);
|
|
115
|
+
}
|
|
116
|
+
const entries = [];
|
|
117
|
+
for (const [streamId, streamGroup] of responseStreamGroups.entries()) {
|
|
118
|
+
const streamEvents = [...streamGroup.events].sort((left, right) => left.content.sequence - right.content.sequence);
|
|
119
|
+
const latest = streamEvents[streamEvents.length - 1];
|
|
120
|
+
const text = streamEvents.reduce((currentText, streamEvent) => applyResponseStreamText(currentText, streamEvent.content), '');
|
|
121
|
+
const taskId = latest.task?.id;
|
|
122
|
+
const matchingLaterFinalMessage = taskId !== undefined &&
|
|
123
|
+
(finalMessagesByTask.get(taskId) ?? []).some((message) => message.index > streamGroup.lastIndex && textMatches(text, message.text));
|
|
124
|
+
if (latest.content.status !== 'aborted' &&
|
|
125
|
+
!matchingLaterFinalMessage &&
|
|
126
|
+
text.trim()) {
|
|
127
|
+
entries.push({
|
|
128
|
+
streamId,
|
|
129
|
+
key: `response-stream-${streamId}`,
|
|
130
|
+
contents: streamEvents.map((event) => event.content),
|
|
131
|
+
text,
|
|
132
|
+
status: latest.content.status,
|
|
133
|
+
timestamp: formatDisplayTimestamp(latest.created_at),
|
|
134
|
+
taskId,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return entries;
|
|
139
|
+
}
|
|
140
|
+
function responseStreamResumeStateFromEntries(entries) {
|
|
141
|
+
const state = {
|
|
142
|
+
keys: new Map(),
|
|
143
|
+
contents: new Map(),
|
|
144
|
+
texts: new Map(),
|
|
145
|
+
timestamps: new Map(),
|
|
146
|
+
statuses: new Map(),
|
|
147
|
+
keysByTask: new Map(),
|
|
148
|
+
};
|
|
149
|
+
for (const entry of entries) {
|
|
150
|
+
state.keys.set(entry.streamId, entry.key);
|
|
151
|
+
state.contents.set(entry.streamId, entry.contents);
|
|
152
|
+
state.texts.set(entry.streamId, entry.text);
|
|
153
|
+
state.statuses.set(entry.streamId, entry.status);
|
|
154
|
+
if (entry.timestamp !== undefined) {
|
|
155
|
+
state.timestamps.set(entry.streamId, entry.timestamp);
|
|
156
|
+
}
|
|
157
|
+
if (entry.taskId !== undefined) {
|
|
158
|
+
const keys = state.keysByTask.get(entry.taskId) ?? new Set();
|
|
159
|
+
keys.add(entry.key);
|
|
160
|
+
state.keysByTask.set(entry.taskId, keys);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return state;
|
|
164
|
+
}
|
|
165
|
+
export function responseStreamResumeStateFromEvents(events) {
|
|
166
|
+
return responseStreamResumeStateFromEntries(collectResponseStreamResumeEntries(events));
|
|
167
|
+
}
|
|
168
|
+
function eventsToDisplayMessagesWithResponseStreamEntries(events, responseStreamEntries) {
|
|
57
169
|
const messages = [];
|
|
170
|
+
const responseStreamEntriesById = new Map(responseStreamEntries.map((entry) => [entry.streamId, entry]));
|
|
171
|
+
const renderedResponseStreamIds = new Set();
|
|
58
172
|
for (const event of events) {
|
|
59
173
|
if (event.type === 'user_message') {
|
|
60
174
|
messages.push({
|
|
@@ -65,18 +179,22 @@ export function eventsToDisplayMessages(events) {
|
|
|
65
179
|
});
|
|
66
180
|
}
|
|
67
181
|
else if (event.type === 'agent_notification_message') {
|
|
68
|
-
if (isResponseStreamEvent(event))
|
|
182
|
+
if (isResponseStreamEvent(event)) {
|
|
183
|
+
if (!isRootTaskEvent(event))
|
|
184
|
+
continue;
|
|
185
|
+
const streamId = event.content.stream_id;
|
|
186
|
+
if (renderedResponseStreamIds.has(streamId))
|
|
187
|
+
continue;
|
|
188
|
+
const streamEntry = responseStreamEntriesById.get(streamId);
|
|
189
|
+
if (!streamEntry)
|
|
190
|
+
continue;
|
|
191
|
+
renderedResponseStreamIds.add(streamId);
|
|
192
|
+
messages.push(renderAssistantText(streamEntry.key, streamEntry.text, streamEntry.timestamp));
|
|
69
193
|
continue;
|
|
194
|
+
}
|
|
70
195
|
const text = getAgentNotificationText(event);
|
|
71
196
|
if (text.trim()) {
|
|
72
|
-
|
|
73
|
-
const messageContent = `${chalk.green('●')} ${chalk.bold('assistant')}\n${rendered.trim()}`;
|
|
74
|
-
messages.push({
|
|
75
|
-
key: event.id,
|
|
76
|
-
content: messageContent,
|
|
77
|
-
type: 'assistant',
|
|
78
|
-
timestamp: event.created_at,
|
|
79
|
-
});
|
|
197
|
+
messages.push(renderAssistantText(event.id, text, event.created_at));
|
|
80
198
|
}
|
|
81
199
|
}
|
|
82
200
|
else if (event.type === 'agent_notification_error') {
|
|
@@ -93,4 +211,19 @@ export function eventsToDisplayMessages(events) {
|
|
|
93
211
|
}
|
|
94
212
|
return messages;
|
|
95
213
|
}
|
|
214
|
+
export function prepareSessionResumeDisplay(events) {
|
|
215
|
+
const responseStreamEntries = collectResponseStreamResumeEntries(events);
|
|
216
|
+
return {
|
|
217
|
+
displayMessages: eventsToDisplayMessagesWithResponseStreamEntries(events, responseStreamEntries),
|
|
218
|
+
responseStreamState: responseStreamResumeStateFromEntries(responseStreamEntries),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Convert session events to display messages for resume.
|
|
223
|
+
* Maps user_message, agent_notification_message, and agent_notification_error
|
|
224
|
+
* to DisplayMessage objects. Skips progress, console, runtime events.
|
|
225
|
+
*/
|
|
226
|
+
export function eventsToDisplayMessages(events) {
|
|
227
|
+
return prepareSessionResumeDisplay(events).displayMessages;
|
|
228
|
+
}
|
|
96
229
|
//# sourceMappingURL=session-resume.js.map
|
package/dist/lib/splash.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import LOGO from './logo.js';
|
|
5
5
|
import { brand } from './colors.js';
|
|
6
|
+
import { isMachineReadable } from './output-mode.js';
|
|
6
7
|
/**
|
|
7
8
|
* Show splash screen with logo
|
|
8
9
|
*/
|
|
@@ -21,8 +22,8 @@ export function showSplashScreen(options) {
|
|
|
21
22
|
* Never for: --json, data commands, action commands
|
|
22
23
|
*/
|
|
23
24
|
export function shouldShowSplash() {
|
|
24
|
-
// Never in
|
|
25
|
-
if (
|
|
25
|
+
// Never in machine-readable mode (--mode json, --mode jsonl, --json)
|
|
26
|
+
if (isMachineReadable()) {
|
|
26
27
|
return false;
|
|
27
28
|
}
|
|
28
29
|
const args = process.argv.slice(2);
|
package/dist/lib/stdin.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Check if
|
|
2
|
+
* Check if the CLI is running in interactive mode.
|
|
3
|
+
*
|
|
4
|
+
* Returns false when:
|
|
5
|
+
* - stdin is not a TTY (piped input, CI, cron)
|
|
6
|
+
* - the global --non-interactive flag is set
|
|
3
7
|
*/
|
|
4
8
|
export declare function isInteractive(): boolean;
|
|
5
9
|
/**
|
package/dist/lib/stdin.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
// Copyright 2026 Guild.ai
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
/**
|
|
4
|
-
* Check if
|
|
4
|
+
* Check if the CLI is running in interactive mode.
|
|
5
|
+
*
|
|
6
|
+
* Returns false when:
|
|
7
|
+
* - stdin is not a TTY (piped input, CI, cron)
|
|
8
|
+
* - the global --non-interactive flag is set
|
|
5
9
|
*/
|
|
6
10
|
export function isInteractive() {
|
|
11
|
+
if (process.argv.includes('--non-interactive')) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
7
14
|
return process.stdin.isTTY === true;
|
|
8
15
|
}
|
|
9
16
|
/**
|
|
@@ -66,22 +66,38 @@ export async function waitForValidation(versionId, output) {
|
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
68
|
* Fetch validation step details for a failed version.
|
|
69
|
+
* Shows content from all steps (not just failed) so the full build output is visible.
|
|
69
70
|
*/
|
|
70
71
|
async function fetchValidationFailureDetails(versionId) {
|
|
71
72
|
const client = new GuildAPIClient();
|
|
72
73
|
let failureDetails = '';
|
|
73
74
|
try {
|
|
74
75
|
const stepsResponse = await client.get(`/versions/${versionId}/validation/steps`);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
if (stepsResponse.steps.length > 0) {
|
|
77
|
+
failureDetails = stepsResponse.steps
|
|
78
|
+
.map((step) => {
|
|
79
|
+
let icon;
|
|
80
|
+
switch (step.status) {
|
|
81
|
+
case 'SUCCEEDED':
|
|
82
|
+
icon = '✓';
|
|
83
|
+
break;
|
|
84
|
+
case 'FAILED':
|
|
85
|
+
case 'ERRORED':
|
|
86
|
+
icon = '✗';
|
|
87
|
+
break;
|
|
88
|
+
case 'RUNNING':
|
|
89
|
+
icon = '⟳';
|
|
90
|
+
break;
|
|
91
|
+
default:
|
|
92
|
+
icon = '○';
|
|
93
|
+
}
|
|
94
|
+
const header = `${icon} ${step.name} [${step.status}]`;
|
|
95
|
+
return step.content ? `${header}\n${step.content}` : header;
|
|
96
|
+
})
|
|
97
|
+
.join('\n\n');
|
|
82
98
|
}
|
|
83
99
|
else {
|
|
84
|
-
failureDetails = 'No
|
|
100
|
+
failureDetails = 'No steps found. Check validation logs for details.';
|
|
85
101
|
}
|
|
86
102
|
}
|
|
87
103
|
catch {
|