@guildai/cli 0.9.0 → 0.10.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.d.ts +1 -0
- package/dist/commands/agent/chat.js +24 -1
- package/dist/commands/agent/fork.js +1 -0
- package/dist/commands/agent/init.js +2 -1
- package/dist/commands/agent/list.js +3 -2
- package/dist/commands/agent/pull.js +1 -1
- package/dist/commands/agent/save.js +4 -4
- package/dist/commands/agent/search.js +3 -2
- package/dist/commands/agent/test.d.ts +1 -0
- package/dist/commands/agent/test.js +92 -34
- package/dist/commands/agent/versions.js +3 -2
- package/dist/commands/agent/workspaces.js +3 -2
- package/dist/commands/chat.d.ts +10 -0
- package/dist/commands/chat.js +215 -50
- package/dist/commands/credentials/endpoint-list.js +3 -2
- package/dist/commands/credentials/list.js +3 -2
- package/dist/commands/credentials/policy-list.js +3 -2
- package/dist/commands/integration/connect.js +1 -1
- package/dist/commands/integration/create.js +36 -36
- package/dist/commands/integration/list.js +3 -2
- package/dist/commands/integration/operation/create.js +2 -1
- package/dist/commands/integration/operation/list.js +26 -17
- package/dist/commands/integration/version/list.js +3 -2
- package/dist/commands/mcp.js +1 -1
- package/dist/commands/session/create.js +1 -1
- package/dist/commands/session/events.js +19 -9
- package/dist/commands/session/list.js +3 -2
- package/dist/commands/session/send.js +1 -1
- package/dist/commands/session/tasks.js +3 -2
- package/dist/commands/trigger/list.js +3 -2
- package/dist/commands/trigger/sessions.js +3 -2
- package/dist/commands/workspace/agent/add.js +16 -3
- package/dist/commands/workspace/agent/list.js +17 -3
- package/dist/commands/workspace/agent/remove.js +14 -1
- package/dist/commands/workspace/clear.d.ts +3 -0
- package/dist/commands/workspace/clear.js +45 -0
- package/dist/commands/workspace/context/list.js +3 -2
- package/dist/commands/workspace/list.js +3 -2
- package/dist/commands/workspace/select.js +3 -1
- package/dist/index.js +53 -6
- package/dist/lib/api-types.d.ts +5 -0
- package/dist/lib/api-types.js +4 -0
- package/dist/lib/generated-types.d.ts +1 -1
- package/dist/lib/generated-types.js +1 -0
- package/dist/lib/guild-config.d.ts +13 -0
- package/dist/lib/guild-config.js +19 -0
- package/dist/lib/npmrc.js +6 -2
- package/dist/lib/output.js +4 -4
- package/dist/lib/owner-helpers.d.ts +3 -0
- package/dist/lib/owner-helpers.js +17 -10
- package/dist/lib/session-events.d.ts +32 -16
- package/dist/lib/session-events.js +22 -0
- package/dist/lib/session-polling.d.ts +4 -3
- package/dist/lib/session-polling.js +75 -17
- package/dist/lib/session-resume.js +4 -1
- package/dist/lib/stdin.d.ts +4 -0
- package/dist/lib/stdin.js +23 -0
- package/dist/lib/validate-input-schema.d.ts +19 -0
- package/dist/lib/validate-input-schema.js +208 -0
- package/dist/lib/workspace-helpers.d.ts +20 -0
- package/dist/lib/workspace-helpers.js +49 -0
- package/dist/mcp/tools.js +8 -52
- package/docs/skills/agent-dev.md +191 -128
- package/package.json +2 -1
package/dist/commands/chat.js
CHANGED
|
@@ -13,12 +13,12 @@ import chalk from 'chalk';
|
|
|
13
13
|
import { readFileSync } from 'fs';
|
|
14
14
|
import path from 'path';
|
|
15
15
|
import { fileURLToPath } from 'url';
|
|
16
|
-
import { isUnfulfilledAgentInstallRequest, isFilteredTaskName, getTaskDisplayName, getAgentName, } from '../lib/session-events.js';
|
|
16
|
+
import { isUnfulfilledAgentInstallRequest, isFilteredTaskName, getTaskDisplayName, getAgentName, getAgentNotificationText, isDoneResponseStreamEvent, isResponseStreamEvent, isRootTaskEvent, } from '../lib/session-events.js';
|
|
17
17
|
import { printResumeHint, fetchSession, fetchSessionEvents, eventsToDisplayMessages, } from '../lib/session-resume.js';
|
|
18
18
|
import { DEFAULT_EVENT_TYPES, parseEventFilter, shouldShowEvent, } from '../lib/event-filter.js';
|
|
19
19
|
import { fetchEvents, fetchTasks } from '../lib/session-events-fetch.js';
|
|
20
20
|
import { AgentInstallPrompt } from '../components/AgentInstallPrompt.js';
|
|
21
|
-
import { getWorkspaceId } from '../lib/guild-config.js';
|
|
21
|
+
import { getWorkspaceId, getWorkspaceSourceLabel } from '../lib/guild-config.js';
|
|
22
22
|
import { ensureInteractiveStdin } from '../lib/stdin.js';
|
|
23
23
|
import { brand, BRAND_COLOR, code as codeColor, hyperlink } from '../lib/colors.js';
|
|
24
24
|
import { SplashAnimation } from '../components/SplashAnimation.js';
|
|
@@ -31,6 +31,28 @@ import { getOutputMode, isQuietMode } from '../lib/output-mode.js';
|
|
|
31
31
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
32
32
|
// Read version from package.json
|
|
33
33
|
const packageJson = JSON.parse(readFileSync(path.join(__dirname, '../../package.json'), 'utf-8'));
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Workspace error types
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/** Thrown when no workspace is configured (no --workspace flag, no config). */
|
|
38
|
+
export class WorkspaceNotConfiguredError extends Error {
|
|
39
|
+
constructor() {
|
|
40
|
+
super('No workspace configured.');
|
|
41
|
+
this.name = 'WorkspaceNotConfiguredError';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Thrown when the specified workspace ID is not found in the backend. */
|
|
45
|
+
export class WorkspaceNotFoundError extends Error {
|
|
46
|
+
workspaceId;
|
|
47
|
+
constructor(workspaceId) {
|
|
48
|
+
super(`Workspace ${workspaceId} not found.`);
|
|
49
|
+
this.name = 'WorkspaceNotFoundError';
|
|
50
|
+
this.workspaceId = workspaceId;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** User-facing error messages for workspace resolution failures. */
|
|
54
|
+
const WORKSPACE_NOT_CONFIGURED_MSG = 'No workspace configured. Pass a --workspace <id_or_name> argument or run guild workspace select';
|
|
55
|
+
const WORKSPACE_NOT_FOUND_MSG = "The workspace doesn't exist.";
|
|
34
56
|
// Configure marked for terminal
|
|
35
57
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
58
|
marked.use(markedTerminal({}, { theme: {} }));
|
|
@@ -48,6 +70,48 @@ function fixListItemMarkdown(text) {
|
|
|
48
70
|
text = text.replace(/(?<![\\w])_([^_]+)_(?![\\w])/g, (_, content) => chalk.italic(content));
|
|
49
71
|
return text;
|
|
50
72
|
}
|
|
73
|
+
function extractMessageText(text) {
|
|
74
|
+
const trimmed = text.trim();
|
|
75
|
+
if (!trimmed.startsWith('{') || !trimmed.endsWith('}'))
|
|
76
|
+
return text;
|
|
77
|
+
try {
|
|
78
|
+
const parsed = JSON.parse(trimmed);
|
|
79
|
+
if (typeof parsed === 'object' && parsed !== null && 'message' in parsed) {
|
|
80
|
+
return typeof parsed.message === 'string' ? parsed.message : text;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// If parsing fails, use the content as-is.
|
|
85
|
+
}
|
|
86
|
+
return text;
|
|
87
|
+
}
|
|
88
|
+
function extractRuntimeDoneText(content) {
|
|
89
|
+
if (content === null || content === undefined)
|
|
90
|
+
return null;
|
|
91
|
+
if (typeof content === 'string')
|
|
92
|
+
return content.trim() ? content : null;
|
|
93
|
+
if (typeof content !== 'object' || Array.isArray(content)) {
|
|
94
|
+
return JSON.stringify(content);
|
|
95
|
+
}
|
|
96
|
+
const record = content;
|
|
97
|
+
if (Object.keys(record).length === 0)
|
|
98
|
+
return null;
|
|
99
|
+
if (record.type === 'text') {
|
|
100
|
+
if (typeof record.text === 'string')
|
|
101
|
+
return record.text;
|
|
102
|
+
if (typeof record.data === 'string')
|
|
103
|
+
return record.data;
|
|
104
|
+
}
|
|
105
|
+
if (typeof record.message === 'string')
|
|
106
|
+
return record.message;
|
|
107
|
+
// runtime_done content is agent output, not notification content. Preserve
|
|
108
|
+
// structured outputs rather than trying to render notification-only shapes.
|
|
109
|
+
return JSON.stringify(content);
|
|
110
|
+
}
|
|
111
|
+
function renderAssistantMessage(text, taskName) {
|
|
112
|
+
const rendered = fixListItemMarkdown(marked.parse(text));
|
|
113
|
+
return `${chalk.green('●')} ${chalk.bold(taskName)}\n${rendered.trim()}`;
|
|
114
|
+
}
|
|
51
115
|
/**
|
|
52
116
|
* Output the result of a --once mode session.
|
|
53
117
|
* Handles both JSON and human-readable output formats.
|
|
@@ -57,21 +121,29 @@ async function outputOnceResult(sessionId, events, mode) {
|
|
|
57
121
|
console.log(JSON.stringify({ session_id: sessionId, events }, null, 2));
|
|
58
122
|
}
|
|
59
123
|
else {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
124
|
+
const finalAgentMessages = events.filter((e) => e.type === 'agent_notification_message' &&
|
|
125
|
+
isRootTaskEvent(e) &&
|
|
126
|
+
!isResponseStreamEvent(e));
|
|
127
|
+
const streamFallbacks = events.filter((e) => e.type === 'agent_notification_message' &&
|
|
128
|
+
isRootTaskEvent(e) &&
|
|
129
|
+
isDoneResponseStreamEvent(e));
|
|
130
|
+
if (finalAgentMessages.length > 0) {
|
|
131
|
+
const messageContent = extractMessageText(getAgentNotificationText(finalAgentMessages[finalAgentMessages.length - 1]));
|
|
132
|
+
const rendered = fixListItemMarkdown(await marked(messageContent));
|
|
133
|
+
console.log(rendered.trim());
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const runtimeDoneEvents = events.filter((e) => e.type === 'runtime_done' && isRootTaskEvent(e) && e.content);
|
|
137
|
+
const runtimeDoneWithContent = runtimeDoneEvents[runtimeDoneEvents.length - 1];
|
|
138
|
+
if (runtimeDoneWithContent?.type === 'runtime_done') {
|
|
139
|
+
const runtimeDoneText = extractRuntimeDoneText(runtimeDoneWithContent.content);
|
|
140
|
+
if (runtimeDoneText) {
|
|
141
|
+
console.log(runtimeDoneText);
|
|
142
|
+
return;
|
|
74
143
|
}
|
|
144
|
+
}
|
|
145
|
+
if (streamFallbacks.length > 0) {
|
|
146
|
+
const messageContent = extractMessageText(getAgentNotificationText(streamFallbacks[streamFallbacks.length - 1]));
|
|
75
147
|
const rendered = fixListItemMarkdown(await marked(messageContent));
|
|
76
148
|
console.log(rendered.trim());
|
|
77
149
|
}
|
|
@@ -214,8 +286,11 @@ export function ChatApp({ initialPrompt, version, workspaceId, versionId, agentN
|
|
|
214
286
|
formattedError.code === ErrorCodes.AUTH_TOKEN_INVALID) {
|
|
215
287
|
format.error('Not authenticated. Run: guild auth login');
|
|
216
288
|
}
|
|
217
|
-
else if (
|
|
218
|
-
format.error(
|
|
289
|
+
else if (error instanceof WorkspaceNotConfiguredError) {
|
|
290
|
+
format.error(WORKSPACE_NOT_CONFIGURED_MSG);
|
|
291
|
+
}
|
|
292
|
+
else if (error instanceof WorkspaceNotFoundError) {
|
|
293
|
+
format.error(WORKSPACE_NOT_FOUND_MSG);
|
|
219
294
|
}
|
|
220
295
|
else if (details.includes('agent')) {
|
|
221
296
|
format.error('Agent not found in workspace.');
|
|
@@ -427,6 +502,83 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
427
502
|
const isPolling = useRef(false);
|
|
428
503
|
const receivedResponseSinceLastInput = useRef(false);
|
|
429
504
|
const firstMessageNotified = useRef(!!resumeEvents);
|
|
505
|
+
const responseStreamKeys = useRef(new Map());
|
|
506
|
+
const responseStreamTimestamps = useRef(new Map());
|
|
507
|
+
const responseStreamKeysByTask = useRef(new Map());
|
|
508
|
+
const clearResponseStreamsForTask = (taskId) => {
|
|
509
|
+
if (!taskId)
|
|
510
|
+
return;
|
|
511
|
+
const keys = responseStreamKeysByTask.current.get(taskId);
|
|
512
|
+
if (!keys?.size)
|
|
513
|
+
return;
|
|
514
|
+
for (const [streamId, key] of responseStreamKeys.current.entries()) {
|
|
515
|
+
if (keys.has(key)) {
|
|
516
|
+
responseStreamKeys.current.delete(streamId);
|
|
517
|
+
responseStreamTimestamps.current.delete(streamId);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
responseStreamKeysByTask.current.delete(taskId);
|
|
521
|
+
setMessages((prev) => prev.filter((message) => !keys.has(message.key)));
|
|
522
|
+
};
|
|
523
|
+
const upsertResponseStreamMessage = (event) => {
|
|
524
|
+
if (!isResponseStreamEvent(event))
|
|
525
|
+
return;
|
|
526
|
+
if (!isRootTaskEvent(event))
|
|
527
|
+
return;
|
|
528
|
+
const streamId = event.content.stream_id;
|
|
529
|
+
const taskId = event.task?.id;
|
|
530
|
+
const existingKey = responseStreamKeys.current.get(streamId);
|
|
531
|
+
if (event.content.status === 'aborted') {
|
|
532
|
+
if (existingKey) {
|
|
533
|
+
responseStreamKeys.current.delete(streamId);
|
|
534
|
+
responseStreamTimestamps.current.delete(streamId);
|
|
535
|
+
if (taskId) {
|
|
536
|
+
const keys = responseStreamKeysByTask.current.get(taskId);
|
|
537
|
+
keys?.delete(existingKey);
|
|
538
|
+
if (keys?.size === 0)
|
|
539
|
+
responseStreamKeysByTask.current.delete(taskId);
|
|
540
|
+
}
|
|
541
|
+
setMessages((prev) => prev.filter((message) => message.key !== existingKey));
|
|
542
|
+
}
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
const text = event.content.text;
|
|
546
|
+
if (!text.trim())
|
|
547
|
+
return;
|
|
548
|
+
const key = existingKey ?? `response-stream-${streamId}`;
|
|
549
|
+
responseStreamKeys.current.set(streamId, key);
|
|
550
|
+
if (taskId) {
|
|
551
|
+
const keys = responseStreamKeysByTask.current.get(taskId) ?? new Set();
|
|
552
|
+
keys.add(key);
|
|
553
|
+
responseStreamKeysByTask.current.set(taskId, keys);
|
|
554
|
+
}
|
|
555
|
+
const taskName = agentName || 'assistant';
|
|
556
|
+
const messageContent = renderAssistantMessage(text, taskName);
|
|
557
|
+
const timestamp = responseStreamTimestamps.current.get(streamId) ?? new Date().toLocaleTimeString();
|
|
558
|
+
responseStreamTimestamps.current.set(streamId, timestamp);
|
|
559
|
+
setMessages((prev) => {
|
|
560
|
+
const index = prev.findIndex((message) => message.key === key);
|
|
561
|
+
const message = {
|
|
562
|
+
key,
|
|
563
|
+
content: messageContent,
|
|
564
|
+
type: 'assistant',
|
|
565
|
+
timestamp,
|
|
566
|
+
};
|
|
567
|
+
if (index === -1)
|
|
568
|
+
return [...prev, message];
|
|
569
|
+
const next = [...prev];
|
|
570
|
+
next[index] = message;
|
|
571
|
+
return next;
|
|
572
|
+
});
|
|
573
|
+
if (!firstMessageNotified.current && onFirstMessage) {
|
|
574
|
+
firstMessageNotified.current = true;
|
|
575
|
+
onFirstMessage();
|
|
576
|
+
}
|
|
577
|
+
if (event.content.status === 'done') {
|
|
578
|
+
receivedResponseSinceLastInput.current = true;
|
|
579
|
+
setCurrentOperation('');
|
|
580
|
+
}
|
|
581
|
+
};
|
|
430
582
|
// Mark initial prompt as sent (skip for resume — we already have the events)
|
|
431
583
|
useEffect(() => {
|
|
432
584
|
if (!resumeEvents) {
|
|
@@ -526,6 +678,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
526
678
|
}
|
|
527
679
|
// Process events that affect the chat UI (task state comes from tasks poll)
|
|
528
680
|
if (event.type === 'runtime_error') {
|
|
681
|
+
clearResponseStreamsForTask(taskInfo?.id);
|
|
529
682
|
// Always clear the spinner on runtime errors so the UI doesn't get stuck
|
|
530
683
|
setCurrentOperation('');
|
|
531
684
|
// Show runtime errors in the chat (gated on --events filter)
|
|
@@ -639,32 +792,15 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
639
792
|
}
|
|
640
793
|
}
|
|
641
794
|
else if (event.type === 'agent_notification_message') {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
const
|
|
647
|
-
if (
|
|
648
|
-
|
|
649
|
-
if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
|
|
650
|
-
try {
|
|
651
|
-
const parsed = JSON.parse(trimmed);
|
|
652
|
-
// If JSON has a "message" field, extract it (some agents wrap responses this way)
|
|
653
|
-
if (typeof parsed === 'object' &&
|
|
654
|
-
parsed !== null &&
|
|
655
|
-
'message' in parsed) {
|
|
656
|
-
text = parsed.message;
|
|
657
|
-
}
|
|
658
|
-
// Otherwise use full JSON content as-is (legitimate JSON responses)
|
|
659
|
-
}
|
|
660
|
-
catch {
|
|
661
|
-
// If parsing fails, use the content as-is
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
const rendered = fixListItemMarkdown(marked.parse(text));
|
|
665
|
-
// Add attribution with task name
|
|
795
|
+
if (isResponseStreamEvent(event)) {
|
|
796
|
+
upsertResponseStreamMessage(event);
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
const text = extractMessageText(getAgentNotificationText(event));
|
|
800
|
+
if (text.trim()) {
|
|
801
|
+
clearResponseStreamsForTask(taskInfo?.id);
|
|
666
802
|
const taskName = agentName || 'assistant';
|
|
667
|
-
const messageContent =
|
|
803
|
+
const messageContent = renderAssistantMessage(text, taskName);
|
|
668
804
|
setMessages((prev) => [
|
|
669
805
|
...prev,
|
|
670
806
|
{
|
|
@@ -684,6 +820,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
684
820
|
setCurrentOperation('');
|
|
685
821
|
}
|
|
686
822
|
else if (event.type === 'agent_notification_error') {
|
|
823
|
+
clearResponseStreamsForTask(taskInfo?.id);
|
|
687
824
|
// Show error in chat (task status is updated via tasks poll)
|
|
688
825
|
const errorText = typeof event.content === 'string'
|
|
689
826
|
? event.content
|
|
@@ -730,6 +867,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
730
867
|
event.content !== undefined &&
|
|
731
868
|
taskInfo &&
|
|
732
869
|
'agent' in taskInfo) {
|
|
870
|
+
clearResponseStreamsForTask(taskInfo.id);
|
|
733
871
|
// One-shot agents may complete with runtime_done without sending
|
|
734
872
|
// agent_notification_message. Display the output if we haven't
|
|
735
873
|
// already shown a response for this input cycle.
|
|
@@ -759,6 +897,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
759
897
|
}
|
|
760
898
|
}
|
|
761
899
|
else if (event.type === 'interrupted') {
|
|
900
|
+
clearResponseStreamsForTask(taskInfo?.id);
|
|
762
901
|
// Session was interrupted — interrupted sessions are terminal on the backend
|
|
763
902
|
setMessages((prev) => [
|
|
764
903
|
...prev,
|
|
@@ -987,10 +1126,14 @@ export async function createSession(client, workspaceId, initialPrompt, versionI
|
|
|
987
1126
|
const resolved = await getWorkspaceId();
|
|
988
1127
|
if (resolved) {
|
|
989
1128
|
workspaceId = resolved.workspaceId;
|
|
1129
|
+
const sourceLabel = getWorkspaceSourceLabel(resolved.source);
|
|
1130
|
+
if (sourceLabel) {
|
|
1131
|
+
progress(`Using workspace from ${sourceLabel}`);
|
|
1132
|
+
}
|
|
990
1133
|
}
|
|
991
1134
|
}
|
|
992
1135
|
if (!workspaceId) {
|
|
993
|
-
throw new
|
|
1136
|
+
throw new WorkspaceNotConfiguredError();
|
|
994
1137
|
}
|
|
995
1138
|
progress('Creating session');
|
|
996
1139
|
const sessionData = {
|
|
@@ -1009,7 +1152,7 @@ export async function createSession(client, workspaceId, initialPrompt, versionI
|
|
|
1009
1152
|
catch (error) {
|
|
1010
1153
|
const err = handleAxiosError(error);
|
|
1011
1154
|
if (err.code === ErrorCodes.NOT_FOUND) {
|
|
1012
|
-
throw new
|
|
1155
|
+
throw new WorkspaceNotFoundError(workspaceId);
|
|
1013
1156
|
}
|
|
1014
1157
|
throw error;
|
|
1015
1158
|
}
|
|
@@ -1045,7 +1188,9 @@ export function createChatCommand() {
|
|
|
1045
1188
|
try {
|
|
1046
1189
|
await ensureAuthenticated();
|
|
1047
1190
|
const client = new GuildAPIClient();
|
|
1048
|
-
const session = await createSession(client, options.workspace, initialPrompt, options.agent)
|
|
1191
|
+
const session = await createSession(client, options.workspace, initialPrompt, options.agent, (status) => {
|
|
1192
|
+
spinner.text = status;
|
|
1193
|
+
});
|
|
1049
1194
|
spinner.succeed('Connected');
|
|
1050
1195
|
if (session.session_url) {
|
|
1051
1196
|
const sessionLink = hyperlink(session.id, session.session_url);
|
|
@@ -1084,12 +1229,18 @@ export function createChatCommand() {
|
|
|
1084
1229
|
else {
|
|
1085
1230
|
inactivityCounter++;
|
|
1086
1231
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1232
|
+
// Check if we got a completion response from the root agent.
|
|
1233
|
+
// Stream done events are only a rendering fallback; wait for the
|
|
1234
|
+
// final root message or runtime completion so child drafts cannot
|
|
1235
|
+
// terminate --once early.
|
|
1236
|
+
const hasRootTaskDone = allEvents.some((e) => e.type === 'runtime_done' && isRootTaskEvent(e));
|
|
1237
|
+
const hasAgentMessage = allEvents.some((e) => e.type === 'agent_notification_message' &&
|
|
1238
|
+
isRootTaskEvent(e) &&
|
|
1239
|
+
!isResponseStreamEvent(e));
|
|
1240
|
+
const hasRootTaskError = allEvents.some((e) => e.type === 'runtime_error' && isRootTaskEvent(e));
|
|
1091
1241
|
// Check for a ui_prompt request... that ends the game.
|
|
1092
1242
|
const hasUIPromptMessage = allEvents.some((e) => e.type === 'agent_notification_message' &&
|
|
1243
|
+
!isResponseStreamEvent(e) &&
|
|
1093
1244
|
e.task?.tool_name === 'ui_prompt');
|
|
1094
1245
|
if (hasRootTaskError) {
|
|
1095
1246
|
debug('Found error event from root agent, exiting --once mode');
|
|
@@ -1130,6 +1281,14 @@ export function createChatCommand() {
|
|
|
1130
1281
|
catch (error) {
|
|
1131
1282
|
spinner.fail('Connection failed');
|
|
1132
1283
|
console.error('');
|
|
1284
|
+
if (error instanceof WorkspaceNotConfiguredError) {
|
|
1285
|
+
format.error(WORKSPACE_NOT_CONFIGURED_MSG);
|
|
1286
|
+
process.exit(1);
|
|
1287
|
+
}
|
|
1288
|
+
if (error instanceof WorkspaceNotFoundError) {
|
|
1289
|
+
format.error(WORKSPACE_NOT_FOUND_MSG);
|
|
1290
|
+
process.exit(1);
|
|
1291
|
+
}
|
|
1133
1292
|
const formattedError = handleAxiosError(error);
|
|
1134
1293
|
console.error(`Error: ${formattedError.error}`);
|
|
1135
1294
|
console.error(formattedError.details);
|
|
@@ -1177,4 +1336,10 @@ export function createChatCommand() {
|
|
|
1177
1336
|
});
|
|
1178
1337
|
return cmd;
|
|
1179
1338
|
}
|
|
1339
|
+
// Thin wrapper for lazy-loading from index.ts (avoids importing React at startup)
|
|
1340
|
+
export async function handleChatAction(_promptArgs, _options) {
|
|
1341
|
+
const cmd = createChatCommand();
|
|
1342
|
+
// Re-parse the original argv so the command's own action handler runs
|
|
1343
|
+
await cmd.parseAsync(process.argv.slice(2), { from: 'user' });
|
|
1344
|
+
}
|
|
1180
1345
|
//# sourceMappingURL=chat.js.map
|
|
@@ -7,6 +7,7 @@ import { getAuthToken } from '../../lib/auth.js';
|
|
|
7
7
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
8
8
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
9
9
|
import { createOutputWriter } from '../../lib/output.js';
|
|
10
|
+
import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
|
|
10
11
|
import { Table } from '../../lib/table.js';
|
|
11
12
|
export function createCredentialsEndpointListCommand() {
|
|
12
13
|
const cmd = new Command('list');
|
|
@@ -15,8 +16,8 @@ export function createCredentialsEndpointListCommand() {
|
|
|
15
16
|
.argument('<credential-id>', 'Credential ID')
|
|
16
17
|
.option('--include-previous-versions', 'Include endpoints from previous versions')
|
|
17
18
|
.option('--search <query>', 'Search by operation name')
|
|
18
|
-
.option('--limit <number>',
|
|
19
|
-
.option('--offset <number>', 'Offset for pagination', '0')
|
|
19
|
+
.option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
|
|
20
|
+
.option('--offset <number>', 'Offset for pagination (default: 0)', '0')
|
|
20
21
|
.action(async (credentialId, options) => {
|
|
21
22
|
const output = createOutputWriter();
|
|
22
23
|
try {
|
|
@@ -6,14 +6,15 @@ import { getAuthToken } from '../../lib/auth.js';
|
|
|
6
6
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
7
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
8
8
|
import { createOutputWriter, formatCredentialsTable } from '../../lib/output.js';
|
|
9
|
+
import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
|
|
9
10
|
export function createCredentialsListCommand() {
|
|
10
11
|
const cmd = new Command('list');
|
|
11
12
|
cmd
|
|
12
13
|
.description('List credentials for an account')
|
|
13
14
|
.requiredOption('--owner <account>', 'Account name or ID')
|
|
14
15
|
.option('--search <query>', 'Filter by integration name')
|
|
15
|
-
.option('--limit <number>',
|
|
16
|
-
.option('--offset <number>', 'Offset for pagination', '0')
|
|
16
|
+
.option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
|
|
17
|
+
.option('--offset <number>', 'Offset for pagination (default: 0)', '0')
|
|
17
18
|
.action(async (options) => {
|
|
18
19
|
const output = createOutputWriter();
|
|
19
20
|
try {
|
|
@@ -6,13 +6,14 @@ import { getAuthToken } from '../../lib/auth.js';
|
|
|
6
6
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
7
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
8
8
|
import { createOutputWriter, formatPoliciesTable } from '../../lib/output.js';
|
|
9
|
+
import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
|
|
9
10
|
export function createCredentialsPolicyListCommand() {
|
|
10
11
|
const cmd = new Command('list');
|
|
11
12
|
cmd
|
|
12
13
|
.description('List policies for a credential')
|
|
13
14
|
.argument('<credential-id>', 'Credential ID')
|
|
14
|
-
.option('--limit <number>',
|
|
15
|
-
.option('--offset <number>', 'Offset for pagination', '0')
|
|
15
|
+
.option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
|
|
16
|
+
.option('--offset <number>', 'Offset for pagination (default: 0)', '0')
|
|
16
17
|
.action(async (credentialId, options) => {
|
|
17
18
|
const output = createOutputWriter();
|
|
18
19
|
try {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import inquirer from 'inquirer';
|
|
6
5
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
7
6
|
import { getAuthToken } from '../../lib/auth.js';
|
|
8
7
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
@@ -40,6 +39,7 @@ export function createIntegrationConnectCommand() {
|
|
|
40
39
|
}
|
|
41
40
|
let apiKey = options.token;
|
|
42
41
|
if (!apiKey) {
|
|
42
|
+
const { default: inquirer } = await import('inquirer');
|
|
43
43
|
const answer = await inquirer.prompt([
|
|
44
44
|
{
|
|
45
45
|
type: 'password',
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import inquirer from 'inquirer';
|
|
6
5
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
7
6
|
import { getAuthToken } from '../../lib/auth.js';
|
|
8
7
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
@@ -66,47 +65,44 @@ export function createIntegrationCreateCommand() {
|
|
|
66
65
|
});
|
|
67
66
|
// Resolve description
|
|
68
67
|
let description = options.description;
|
|
69
|
-
if (!description) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
68
|
+
if (!description && interactive) {
|
|
69
|
+
const { default: inquirer } = await import('inquirer');
|
|
70
|
+
const answer = await inquirer.prompt([
|
|
71
|
+
{ type: 'input', name: 'description', message: 'Description:' },
|
|
72
|
+
]);
|
|
73
|
+
description = answer.description;
|
|
76
74
|
}
|
|
77
75
|
// Resolve base URL
|
|
78
76
|
let baseUrl = options.baseUrl;
|
|
79
|
-
if (!baseUrl) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
77
|
+
if (!baseUrl && interactive) {
|
|
78
|
+
const { default: inquirer } = await import('inquirer');
|
|
79
|
+
const answer = await inquirer.prompt([
|
|
80
|
+
{ type: 'input', name: 'baseUrl', message: 'Base URL:' },
|
|
81
|
+
]);
|
|
82
|
+
baseUrl = answer.baseUrl;
|
|
86
83
|
}
|
|
87
84
|
// Resolve auth scheme
|
|
88
85
|
let authScheme = options.authScheme;
|
|
89
|
-
if (!authScheme) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
86
|
+
if (!authScheme && interactive) {
|
|
87
|
+
const { default: inquirer } = await import('inquirer');
|
|
88
|
+
const answer = await inquirer.prompt([
|
|
89
|
+
{
|
|
90
|
+
type: 'list',
|
|
91
|
+
name: 'authScheme',
|
|
92
|
+
message: 'Select authentication scheme:',
|
|
93
|
+
choices: [
|
|
94
|
+
{
|
|
95
|
+
name: 'API Key - Static token sent in request headers',
|
|
96
|
+
value: 'api-key',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'OAuth 2.0 - User grants access via authorization flow',
|
|
100
|
+
value: 'oauth',
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
]);
|
|
105
|
+
authScheme = answer.authScheme;
|
|
110
106
|
}
|
|
111
107
|
// Validate required fields in non-interactive mode
|
|
112
108
|
const missing = [];
|
|
@@ -126,6 +122,7 @@ export function createIntegrationCreateCommand() {
|
|
|
126
122
|
if (normalizedScheme === 'api-key') {
|
|
127
123
|
let headerTemplate = options.headerTemplate || 'X-API-Key: {token}';
|
|
128
124
|
if (interactive && !options.headerTemplate) {
|
|
125
|
+
const { default: inquirer } = await import('inquirer');
|
|
129
126
|
const answer = await inquirer.prompt([
|
|
130
127
|
{
|
|
131
128
|
type: 'input',
|
|
@@ -151,6 +148,7 @@ export function createIntegrationCreateCommand() {
|
|
|
151
148
|
let clientId = options.clientId;
|
|
152
149
|
let clientSecret = options.clientSecret;
|
|
153
150
|
if (interactive) {
|
|
151
|
+
const { default: inquirer } = await import('inquirer');
|
|
154
152
|
if (!installUrl) {
|
|
155
153
|
const a = await inquirer.prompt([
|
|
156
154
|
{ type: 'input', name: 'val', message: 'Install URL:' },
|
|
@@ -205,6 +203,7 @@ export function createIntegrationCreateCommand() {
|
|
|
205
203
|
authConfig.scopes = options.scopes.split(',').map((s) => s.trim());
|
|
206
204
|
}
|
|
207
205
|
else if (interactive) {
|
|
206
|
+
const { default: inquirer } = await import('inquirer');
|
|
208
207
|
const answer = await inquirer.prompt([
|
|
209
208
|
{
|
|
210
209
|
type: 'input',
|
|
@@ -237,6 +236,7 @@ export function createIntegrationCreateCommand() {
|
|
|
237
236
|
}
|
|
238
237
|
}
|
|
239
238
|
else if (interactive) {
|
|
239
|
+
const { default: inquirer } = await import('inquirer');
|
|
240
240
|
const answer = await inquirer.prompt([
|
|
241
241
|
{
|
|
242
242
|
type: 'confirm',
|
|
@@ -6,6 +6,7 @@ import { getAuthToken } from '../../lib/auth.js';
|
|
|
6
6
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
7
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
8
8
|
import { createOutputWriter, formatIntegrationTable } from '../../lib/output.js';
|
|
9
|
+
import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
|
|
9
10
|
const SORT_MAP = {
|
|
10
11
|
updated: 'updated_at',
|
|
11
12
|
newest: 'created_at',
|
|
@@ -18,8 +19,8 @@ export function createIntegrationListCommand() {
|
|
|
18
19
|
.option('--search <query>', 'Search integrations by name or description')
|
|
19
20
|
.option('--sort <field>', 'Sort by: updated, newest, name (default: updated)', 'updated')
|
|
20
21
|
.option('--published', 'Only show integrations with at least one published version')
|
|
21
|
-
.option('--limit <number>',
|
|
22
|
-
.option('--offset <number>', 'Offset for pagination', '0')
|
|
22
|
+
.option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
|
|
23
|
+
.option('--offset <number>', 'Offset for pagination (default: 0)', '0')
|
|
23
24
|
.action(async (options) => {
|
|
24
25
|
const output = createOutputWriter();
|
|
25
26
|
try {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import inquirer from 'inquirer';
|
|
6
5
|
import { readFileSync, existsSync } from 'fs';
|
|
7
6
|
import { GuildAPIClient } from '../../../lib/api-client.js';
|
|
8
7
|
import { getAuthToken } from '../../../lib/auth.js';
|
|
@@ -59,6 +58,7 @@ export function createIntegrationOperationCreateCommand() {
|
|
|
59
58
|
let method = options.method;
|
|
60
59
|
let operationPath = options.path;
|
|
61
60
|
if (isInteractive()) {
|
|
61
|
+
const { default: inquirer } = await import('inquirer');
|
|
62
62
|
if (!operation) {
|
|
63
63
|
const a = await inquirer.prompt([
|
|
64
64
|
{
|
|
@@ -110,6 +110,7 @@ export function createIntegrationOperationCreateCommand() {
|
|
|
110
110
|
};
|
|
111
111
|
let summary = options.summary;
|
|
112
112
|
if (!summary && isInteractive()) {
|
|
113
|
+
const { default: inquirer } = await import('inquirer');
|
|
113
114
|
const a = await inquirer.prompt([
|
|
114
115
|
{ type: 'input', name: 'val', message: 'Summary (optional):' },
|
|
115
116
|
]);
|