@guildai/cli 0.10.0 → 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 +2 -0
- package/dist/commands/agent/init.js +57 -44
- package/dist/commands/agent/list.js +2 -2
- 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 +2 -3
- package/dist/commands/agent/search.js +2 -2
- package/dist/commands/agent/test.js +9 -6
- package/dist/commands/agent/update.js +9 -1
- package/dist/commands/agent/versions.js +2 -2
- package/dist/commands/agent/workspaces.js +2 -2
- package/dist/commands/auth/login.js +1 -3
- package/dist/commands/chat.js +99 -28
- 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 +2 -2
- package/dist/commands/credentials/list.js +2 -2
- package/dist/commands/credentials/policy-list.js +2 -2
- 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 +2 -2
- package/dist/commands/integration/operation/create.js +4 -4
- package/dist/commands/integration/operation/list.js +2 -2
- 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 +2 -2
- 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/list.js +2 -2
- package/dist/commands/session/tasks.js +2 -2
- package/dist/commands/setup.d.ts +16 -0
- package/dist/commands/setup.js +76 -46
- package/dist/commands/trigger/list.js +2 -2
- package/dist/commands/workspace/agent/list.js +2 -2
- package/dist/commands/workspace/context/list.js +2 -2
- package/dist/commands/workspace/list.js +2 -2
- package/dist/index.js +15 -4
- 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 +32 -1
- 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
package/dist/commands/chat.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import React, { useState, useEffect, useRef } from 'react';
|
|
4
4
|
import { Box, Text, Static, render, useInput, useApp } from 'ink';
|
|
5
|
-
import { Command } from 'commander';
|
|
5
|
+
import { Command, Option } from 'commander';
|
|
6
6
|
import { getAuthToken } from '../lib/auth.js';
|
|
7
7
|
import { GuildAPIClient } from '../lib/api-client.js';
|
|
8
8
|
import { handleAxiosError, ErrorCodes, debug, isDebugMode, retry, } from '../lib/errors.js';
|
|
@@ -13,8 +13,8 @@ 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, getAgentNotificationText, isDoneResponseStreamEvent, isResponseStreamEvent, isRootTaskEvent, } from '../lib/session-events.js';
|
|
17
|
-
import { printResumeHint, fetchSession, fetchSessionEvents,
|
|
16
|
+
import { isUnfulfilledAgentInstallRequest, isFilteredTaskName, getTaskDisplayName, getAgentName, getAgentNotificationText, applyResponseStreamText, isDoneResponseStreamEvent, isResponseStreamEvent, isRootTaskEvent, } from '../lib/session-events.js';
|
|
17
|
+
import { printResumeHint, fetchSession, fetchSessionEvents, prepareSessionResumeDisplay, } 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';
|
|
@@ -112,6 +112,11 @@ function renderAssistantMessage(text, taskName) {
|
|
|
112
112
|
const rendered = fixListItemMarkdown(marked.parse(text));
|
|
113
113
|
return `${chalk.green('●')} ${chalk.bold(taskName)}\n${rendered.trim()}`;
|
|
114
114
|
}
|
|
115
|
+
function applyResponseStreamContentsInSequence(contents) {
|
|
116
|
+
return [...contents]
|
|
117
|
+
.sort((left, right) => left.sequence - right.sequence)
|
|
118
|
+
.reduce((currentText, content) => applyResponseStreamText(currentText, content), '');
|
|
119
|
+
}
|
|
115
120
|
/**
|
|
116
121
|
* Output the result of a --once mode session.
|
|
117
122
|
* Handles both JSON and human-readable output formats.
|
|
@@ -124,9 +129,18 @@ async function outputOnceResult(sessionId, events, mode) {
|
|
|
124
129
|
const finalAgentMessages = events.filter((e) => e.type === 'agent_notification_message' &&
|
|
125
130
|
isRootTaskEvent(e) &&
|
|
126
131
|
!isResponseStreamEvent(e));
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
const responseStreamContents = new Map();
|
|
133
|
+
const doneStreamIds = [];
|
|
134
|
+
for (const event of events) {
|
|
135
|
+
if (!isResponseStreamEvent(event) || !isRootTaskEvent(event))
|
|
136
|
+
continue;
|
|
137
|
+
const streamContents = responseStreamContents.get(event.content.stream_id) ?? [];
|
|
138
|
+
streamContents.push(event.content);
|
|
139
|
+
responseStreamContents.set(event.content.stream_id, streamContents);
|
|
140
|
+
if (isDoneResponseStreamEvent(event)) {
|
|
141
|
+
doneStreamIds.push(event.content.stream_id);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
130
144
|
if (finalAgentMessages.length > 0) {
|
|
131
145
|
const messageContent = extractMessageText(getAgentNotificationText(finalAgentMessages[finalAgentMessages.length - 1]));
|
|
132
146
|
const rendered = fixListItemMarkdown(await marked(messageContent));
|
|
@@ -142,9 +156,12 @@ async function outputOnceResult(sessionId, events, mode) {
|
|
|
142
156
|
return;
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
159
|
+
const lastDoneStreamId = doneStreamIds[doneStreamIds.length - 1];
|
|
160
|
+
const streamFallbackText = lastDoneStreamId !== undefined
|
|
161
|
+
? applyResponseStreamContentsInSequence(responseStreamContents.get(lastDoneStreamId) ?? [])
|
|
162
|
+
: null;
|
|
163
|
+
if (streamFallbackText !== null) {
|
|
164
|
+
const rendered = fixListItemMarkdown(await marked(streamFallbackText));
|
|
148
165
|
console.log(rendered.trim());
|
|
149
166
|
}
|
|
150
167
|
}
|
|
@@ -303,6 +320,7 @@ export function ChatApp({ initialPrompt, version, workspaceId, versionId, agentN
|
|
|
303
320
|
};
|
|
304
321
|
connect();
|
|
305
322
|
}, [workspaceId, initialPrompt, versionId]);
|
|
323
|
+
const chatInstanceKey = `${connectedSession?.id ?? 'pending'}:${resumeEvents?.[resumeEvents.length - 1]?.id ?? 'live'}`;
|
|
306
324
|
// Render both splash and chat, but only show one at a time
|
|
307
325
|
// ChatUIWithConnection is always mounted (when connected) so it can stream events in background
|
|
308
326
|
return (React.createElement(React.Fragment, null,
|
|
@@ -316,7 +334,7 @@ export function ChatApp({ initialPrompt, version, workspaceId, versionId, agentN
|
|
|
316
334
|
}
|
|
317
335
|
// If not connected yet, ignore escape (let connection complete)
|
|
318
336
|
} })),
|
|
319
|
-
phase === 'chat' && (React.createElement(ChatUIWithConnection, { initialPrompt: initialPrompt, version: version, versionId: versionId, agentName: agentName, client: connectedClient, session: connectedSession, onFirstMessage: () => setFirstMessageReceived(true), resumeEvents: resumeEvents, resumeCommand: resumeCommand, eventFilter: eventFilter })),
|
|
337
|
+
phase === 'chat' && (React.createElement(ChatUIWithConnection, { key: chatInstanceKey, initialPrompt: initialPrompt, version: version, versionId: versionId, agentName: agentName, client: connectedClient, session: connectedSession, onFirstMessage: () => setFirstMessageReceived(true), resumeEvents: resumeEvents, resumeCommand: resumeCommand, eventFilter: eventFilter })),
|
|
320
338
|
(phase === 'splash' || phase === 'finalizing') &&
|
|
321
339
|
connectedSession &&
|
|
322
340
|
connectedClient && (React.createElement(Box, { display: "none" },
|
|
@@ -336,9 +354,9 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
336
354
|
// Only include initial prompt when active (not during splash)
|
|
337
355
|
// Static component writes to stdout even with display="none"
|
|
338
356
|
// When resuming, show past events instead of initial prompt
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
357
|
+
const [resumeDisplay] = useState(() => resumeEvents ? prepareSessionResumeDisplay(resumeEvents) : null);
|
|
358
|
+
const resumeDisplayMessages = resumeDisplay?.displayMessages ?? null;
|
|
359
|
+
const responseStreamResumeState = resumeDisplay?.responseStreamState ?? null;
|
|
342
360
|
const sessionLinkMessage = isActive && preConnectedSession?.session_url
|
|
343
361
|
? [
|
|
344
362
|
{
|
|
@@ -502,23 +520,53 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
502
520
|
const isPolling = useRef(false);
|
|
503
521
|
const receivedResponseSinceLastInput = useRef(false);
|
|
504
522
|
const firstMessageNotified = useRef(!!resumeEvents);
|
|
505
|
-
const responseStreamKeys = useRef(new Map());
|
|
506
|
-
const
|
|
507
|
-
const
|
|
508
|
-
const
|
|
523
|
+
const responseStreamKeys = useRef(responseStreamResumeState?.keys ?? new Map());
|
|
524
|
+
const responseStreamContents = useRef(responseStreamResumeState?.contents ?? new Map());
|
|
525
|
+
const responseStreamTexts = useRef(responseStreamResumeState?.texts ?? new Map());
|
|
526
|
+
const responseStreamTimestamps = useRef(responseStreamResumeState?.timestamps ?? new Map());
|
|
527
|
+
const responseStreamStatuses = useRef(responseStreamResumeState?.statuses ??
|
|
528
|
+
new Map());
|
|
529
|
+
const responseStreamKeysByTask = useRef(responseStreamResumeState?.keysByTask ?? new Map());
|
|
530
|
+
const clearResponseStreamsForTask = (taskId, options = {}) => {
|
|
509
531
|
if (!taskId)
|
|
510
532
|
return;
|
|
511
533
|
const keys = responseStreamKeysByTask.current.get(taskId);
|
|
512
534
|
if (!keys?.size)
|
|
513
535
|
return;
|
|
536
|
+
// Removed keys disappear from the transcript; detached keys stay rendered
|
|
537
|
+
// but are no longer tracked as active streams for future cleanup.
|
|
538
|
+
const removedKeys = new Set();
|
|
539
|
+
const detachedKeys = new Set();
|
|
514
540
|
for (const [streamId, key] of responseStreamKeys.current.entries()) {
|
|
515
541
|
if (keys.has(key)) {
|
|
542
|
+
if (options.preserveContinued &&
|
|
543
|
+
responseStreamStatuses.current.get(streamId) === 'continued' &&
|
|
544
|
+
responseStreamTexts.current.get(streamId) !== options.finalText) {
|
|
545
|
+
responseStreamKeys.current.delete(streamId);
|
|
546
|
+
responseStreamContents.current.delete(streamId);
|
|
547
|
+
responseStreamTexts.current.delete(streamId);
|
|
548
|
+
responseStreamTimestamps.current.delete(streamId);
|
|
549
|
+
responseStreamStatuses.current.delete(streamId);
|
|
550
|
+
detachedKeys.add(key);
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
516
553
|
responseStreamKeys.current.delete(streamId);
|
|
554
|
+
responseStreamContents.current.delete(streamId);
|
|
555
|
+
responseStreamTexts.current.delete(streamId);
|
|
517
556
|
responseStreamTimestamps.current.delete(streamId);
|
|
557
|
+
responseStreamStatuses.current.delete(streamId);
|
|
558
|
+
removedKeys.add(key);
|
|
518
559
|
}
|
|
519
560
|
}
|
|
520
|
-
|
|
521
|
-
|
|
561
|
+
const inactiveKeys = new Set([...removedKeys, ...detachedKeys]);
|
|
562
|
+
const remainingKeys = new Set([...keys].filter((key) => !inactiveKeys.has(key)));
|
|
563
|
+
if (remainingKeys.size > 0) {
|
|
564
|
+
responseStreamKeysByTask.current.set(taskId, remainingKeys);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
responseStreamKeysByTask.current.delete(taskId);
|
|
568
|
+
}
|
|
569
|
+
setMessages((prev) => prev.filter((message) => !removedKeys.has(message.key)));
|
|
522
570
|
};
|
|
523
571
|
const upsertResponseStreamMessage = (event) => {
|
|
524
572
|
if (!isResponseStreamEvent(event))
|
|
@@ -529,9 +577,12 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
529
577
|
const taskId = event.task?.id;
|
|
530
578
|
const existingKey = responseStreamKeys.current.get(streamId);
|
|
531
579
|
if (event.content.status === 'aborted') {
|
|
580
|
+
responseStreamContents.current.delete(streamId);
|
|
581
|
+
responseStreamTexts.current.delete(streamId);
|
|
582
|
+
responseStreamTimestamps.current.delete(streamId);
|
|
583
|
+
responseStreamStatuses.current.delete(streamId);
|
|
532
584
|
if (existingKey) {
|
|
533
585
|
responseStreamKeys.current.delete(streamId);
|
|
534
|
-
responseStreamTimestamps.current.delete(streamId);
|
|
535
586
|
if (taskId) {
|
|
536
587
|
const keys = responseStreamKeysByTask.current.get(taskId);
|
|
537
588
|
keys?.delete(existingKey);
|
|
@@ -542,11 +593,22 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
542
593
|
}
|
|
543
594
|
return;
|
|
544
595
|
}
|
|
545
|
-
const
|
|
596
|
+
const streamContents = responseStreamContents.current.get(streamId) ?? [];
|
|
597
|
+
const existingContentIndex = streamContents.findIndex((content) => content.sequence === event.content.sequence);
|
|
598
|
+
if (existingContentIndex === -1) {
|
|
599
|
+
streamContents.push(event.content);
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
streamContents[existingContentIndex] = event.content;
|
|
603
|
+
}
|
|
604
|
+
responseStreamContents.current.set(streamId, streamContents);
|
|
605
|
+
const text = applyResponseStreamContentsInSequence(streamContents);
|
|
546
606
|
if (!text.trim())
|
|
547
607
|
return;
|
|
548
608
|
const key = existingKey ?? `response-stream-${streamId}`;
|
|
549
609
|
responseStreamKeys.current.set(streamId, key);
|
|
610
|
+
responseStreamTexts.current.set(streamId, text);
|
|
611
|
+
responseStreamStatuses.current.set(streamId, event.content.status);
|
|
550
612
|
if (taskId) {
|
|
551
613
|
const keys = responseStreamKeysByTask.current.get(taskId) ?? new Set();
|
|
552
614
|
keys.add(key);
|
|
@@ -798,7 +860,10 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
798
860
|
}
|
|
799
861
|
const text = extractMessageText(getAgentNotificationText(event));
|
|
800
862
|
if (text.trim()) {
|
|
801
|
-
clearResponseStreamsForTask(taskInfo?.id
|
|
863
|
+
clearResponseStreamsForTask(taskInfo?.id, {
|
|
864
|
+
preserveContinued: true,
|
|
865
|
+
finalText: text,
|
|
866
|
+
});
|
|
802
867
|
const taskName = agentName || 'assistant';
|
|
803
868
|
const messageContent = renderAssistantMessage(text, taskName);
|
|
804
869
|
setMessages((prev) => [
|
|
@@ -867,13 +932,16 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
867
932
|
event.content !== undefined &&
|
|
868
933
|
taskInfo &&
|
|
869
934
|
'agent' in taskInfo) {
|
|
870
|
-
clearResponseStreamsForTask(taskInfo.id);
|
|
871
935
|
// One-shot agents may complete with runtime_done without sending
|
|
872
936
|
// agent_notification_message. Display the output if we haven't
|
|
873
937
|
// already shown a response for this input cycle.
|
|
874
938
|
const contentStr = typeof event.content === 'string'
|
|
875
939
|
? event.content
|
|
876
940
|
: JSON.stringify(event.content);
|
|
941
|
+
clearResponseStreamsForTask(taskInfo.id, {
|
|
942
|
+
preserveContinued: true,
|
|
943
|
+
finalText: contentStr,
|
|
944
|
+
});
|
|
877
945
|
if (contentStr && contentStr !== '{}' && contentStr !== 'null') {
|
|
878
946
|
const rendered = fixListItemMarkdown(marked.parse(contentStr));
|
|
879
947
|
const taskName = agentName || 'assistant';
|
|
@@ -1170,11 +1238,13 @@ export function createChatCommand() {
|
|
|
1170
1238
|
.argument('[prompt...]', 'Optional initial prompt (multiple words)')
|
|
1171
1239
|
.option('--agent <identifier>', 'Agent ID or full name, e.g., foo~bar (default: assistant)')
|
|
1172
1240
|
.option('--once', 'One-shot mode: send message, wait for response, exit (non-interactive)')
|
|
1173
|
-
.option('--mode <format>', 'Machine-readable output format: json or jsonl')
|
|
1174
1241
|
.option('--workspace <identifier>', 'Workspace ID or full name (e.g., owner/workspace-name)')
|
|
1175
1242
|
.option('--no-splash', 'Skip the splash screen animation')
|
|
1176
1243
|
.option('--resume <session-id>', 'Resume an existing session')
|
|
1177
1244
|
.option('--events <types>', 'Event types to show (default: user). Shorthands: none, user, system, all, or comma-separated type names (e.g. agent_console,llm_start)')
|
|
1245
|
+
// Accept --mode so `guild chat --mode json` works when re-parsed.
|
|
1246
|
+
// The actual value is read from process.argv by getOutputMode().
|
|
1247
|
+
.addOption(new Option('--mode <format>').hideHelp())
|
|
1178
1248
|
.addHelpText('after', '\nTo chat with a local agent under development: guild agent chat')
|
|
1179
1249
|
.action(async (promptArgs, options) => {
|
|
1180
1250
|
const initialPrompt = promptArgs.length > 0 ? promptArgs.join(' ') : 'Hello';
|
|
@@ -1245,7 +1315,8 @@ export function createChatCommand() {
|
|
|
1245
1315
|
if (hasRootTaskError) {
|
|
1246
1316
|
debug('Found error event from root agent, exiting --once mode');
|
|
1247
1317
|
const errorEvents = allEvents.filter((e) => e.type === 'runtime_error' || e.type === 'agent_notification_error');
|
|
1248
|
-
|
|
1318
|
+
const outputMode = getOutputMode();
|
|
1319
|
+
if (errorEvents.length > 0 && outputMode === 'interactive') {
|
|
1249
1320
|
const lastError = errorEvents[errorEvents.length - 1];
|
|
1250
1321
|
const content = lastError.content;
|
|
1251
1322
|
if (content?.data) {
|
|
@@ -1255,7 +1326,7 @@ export function createChatCommand() {
|
|
|
1255
1326
|
console.error(chalk.red('Agent failed to start'));
|
|
1256
1327
|
}
|
|
1257
1328
|
}
|
|
1258
|
-
else if (
|
|
1329
|
+
else if (outputMode === 'json') {
|
|
1259
1330
|
console.log(JSON.stringify({
|
|
1260
1331
|
session_id: session.id,
|
|
1261
1332
|
events: allEvents,
|
|
@@ -1266,14 +1337,14 @@ export function createChatCommand() {
|
|
|
1266
1337
|
}
|
|
1267
1338
|
if (hasRootTaskDone || hasAgentMessage || hasUIPromptMessage) {
|
|
1268
1339
|
debug('Found completion event from root agent, exiting --once mode');
|
|
1269
|
-
await outputOnceResult(session.id, allEvents,
|
|
1340
|
+
await outputOnceResult(session.id, allEvents, getOutputMode());
|
|
1270
1341
|
process.exit(0);
|
|
1271
1342
|
}
|
|
1272
1343
|
// Timeout if no activity for too long
|
|
1273
1344
|
if (inactivityCounter >= maxInactivityAttempts) {
|
|
1274
1345
|
debug(`Inactivity timeout reached (${maxInactivityAttempts} attempts with no new events)`);
|
|
1275
1346
|
debug(`Exiting with ${allEvents.length} events total`);
|
|
1276
|
-
await outputOnceResult(session.id, allEvents,
|
|
1347
|
+
await outputOnceResult(session.id, allEvents, getOutputMode());
|
|
1277
1348
|
process.exit(0);
|
|
1278
1349
|
}
|
|
1279
1350
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { loadConfig, } from '../../lib/guild-config.js';
|
|
5
|
-
import {
|
|
5
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
6
6
|
import { createOutputWriter } from '../../lib/output.js';
|
|
7
7
|
/**
|
|
8
8
|
* All valid config keys across global and local configs.
|
|
@@ -25,7 +25,7 @@ export function createConfigGetCommand() {
|
|
|
25
25
|
.action(async (key) => {
|
|
26
26
|
const output = createOutputWriter();
|
|
27
27
|
const config = await loadConfig();
|
|
28
|
-
const
|
|
28
|
+
const jsonMode = isMachineReadable();
|
|
29
29
|
if (!ALL_VALID_KEYS.includes(key)) {
|
|
30
30
|
output.error(`Unknown config key: ${key}\n\nValid keys:\n Global: ${VALID_GLOBAL_KEYS.join(', ')}\n Local: ${VALID_LOCAL_KEYS.join(', ')}`);
|
|
31
31
|
process.exit(1);
|
|
@@ -44,7 +44,7 @@ export function createConfigGetCommand() {
|
|
|
44
44
|
source = 'local';
|
|
45
45
|
}
|
|
46
46
|
if (value === undefined) {
|
|
47
|
-
if (
|
|
47
|
+
if (jsonMode) {
|
|
48
48
|
output.data({ key, value: null, source: null });
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
@@ -52,7 +52,7 @@ export function createConfigGetCommand() {
|
|
|
52
52
|
}
|
|
53
53
|
process.exit(1);
|
|
54
54
|
}
|
|
55
|
-
if (
|
|
55
|
+
if (jsonMode) {
|
|
56
56
|
output.data({ key, value, source });
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
@@ -3,15 +3,14 @@
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { loadConfig } from '../../lib/guild-config.js';
|
|
6
|
-
import {
|
|
6
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
7
7
|
import { createOutputWriter } from '../../lib/output.js';
|
|
8
8
|
export function createConfigListCommand() {
|
|
9
9
|
const cmd = new Command('list');
|
|
10
10
|
cmd.description('Show all configuration values').action(async () => {
|
|
11
11
|
const output = createOutputWriter();
|
|
12
12
|
const config = await loadConfig();
|
|
13
|
-
|
|
14
|
-
if (mode === 'json') {
|
|
13
|
+
if (isMachineReadable()) {
|
|
15
14
|
output.data({
|
|
16
15
|
global: config.global || null,
|
|
17
16
|
local: config.local || null,
|
|
@@ -4,7 +4,7 @@ import { Command } from 'commander';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import * as fs from 'fs/promises';
|
|
6
6
|
import { getGlobalConfigPath, getLocalConfigPath } from '../../lib/guild-config.js';
|
|
7
|
-
import {
|
|
7
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
8
8
|
import { createOutputWriter } from '../../lib/output.js';
|
|
9
9
|
async function fileExists(filePath) {
|
|
10
10
|
return fs
|
|
@@ -18,10 +18,9 @@ export function createConfigPathCommand() {
|
|
|
18
18
|
const output = createOutputWriter();
|
|
19
19
|
const globalPath = getGlobalConfigPath();
|
|
20
20
|
const localPath = getLocalConfigPath();
|
|
21
|
-
const mode = getOutputMode();
|
|
22
21
|
const globalExists = await fileExists(globalPath);
|
|
23
22
|
const localExists = await fileExists(localPath);
|
|
24
|
-
if (
|
|
23
|
+
if (isMachineReadable()) {
|
|
25
24
|
output.data({
|
|
26
25
|
global: { path: globalPath, exists: globalExists },
|
|
27
26
|
local: { path: localPath, exists: localExists },
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { saveGlobalConfig } from '../../lib/guild-config.js';
|
|
6
|
-
import {
|
|
6
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
7
7
|
import { createOutputWriter } from '../../lib/output.js';
|
|
8
8
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
9
9
|
import { debug } from '../../lib/errors.js';
|
|
@@ -46,8 +46,8 @@ async function resolveWorkspaceName(workspaceId) {
|
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
function printResult(key, value,
|
|
50
|
-
if (
|
|
49
|
+
function printResult(key, value, jsonMode, output) {
|
|
50
|
+
if (jsonMode) {
|
|
51
51
|
output.data({ key, value });
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
@@ -62,7 +62,7 @@ export function createConfigSetCommand() {
|
|
|
62
62
|
.argument('<value>', 'Value to set')
|
|
63
63
|
.action(async (key, value) => {
|
|
64
64
|
const output = createOutputWriter();
|
|
65
|
-
const
|
|
65
|
+
const jsonMode = isMachineReadable();
|
|
66
66
|
if (!VALID_GLOBAL_KEYS.includes(key)) {
|
|
67
67
|
output.error(`Unknown config key: ${key}\n\nValid keys:\n${VALID_GLOBAL_KEYS.map((k) => ` ${k}`).join('\n')}`);
|
|
68
68
|
process.exit(1);
|
|
@@ -71,7 +71,7 @@ export function createConfigSetCommand() {
|
|
|
71
71
|
if (BOOLEAN_KEYS.has(typedKey)) {
|
|
72
72
|
const boolValue = parseBoolean(value, key, output);
|
|
73
73
|
await saveGlobalConfig({ [typedKey]: boolValue });
|
|
74
|
-
printResult(key, boolValue,
|
|
74
|
+
printResult(key, boolValue, jsonMode, output);
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
if (typedKey === 'default_workspace') {
|
|
@@ -80,14 +80,14 @@ export function createConfigSetCommand() {
|
|
|
80
80
|
default_workspace: value,
|
|
81
81
|
default_workspace_name: name,
|
|
82
82
|
});
|
|
83
|
-
printResult(key, value,
|
|
83
|
+
printResult(key, value, jsonMode, output);
|
|
84
84
|
if (name) {
|
|
85
|
-
if (
|
|
85
|
+
if (!jsonMode) {
|
|
86
86
|
output.progress(` Workspace name: ${name}`);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
else {
|
|
90
|
-
if (
|
|
90
|
+
if (!jsonMode) {
|
|
91
91
|
output.error('Could not resolve workspace name (not authenticated?)');
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -111,21 +111,21 @@ export function createConfigSetCommand() {
|
|
|
111
111
|
default_owner: ownerId,
|
|
112
112
|
default_owner_name: ownerName,
|
|
113
113
|
});
|
|
114
|
-
printResult(key, ownerId,
|
|
114
|
+
printResult(key, ownerId, jsonMode, output);
|
|
115
115
|
if (ownerName) {
|
|
116
|
-
if (
|
|
116
|
+
if (!jsonMode) {
|
|
117
117
|
output.progress(` Owner name: ${ownerName}`);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
else {
|
|
121
|
-
if (
|
|
121
|
+
if (!jsonMode) {
|
|
122
122
|
output.error('Could not resolve owner name (not authenticated?)');
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
127
|
await saveGlobalConfig({ [typedKey]: value });
|
|
128
|
-
printResult(key, value,
|
|
128
|
+
printResult(key, value, jsonMode, output);
|
|
129
129
|
});
|
|
130
130
|
return cmd;
|
|
131
131
|
}
|
|
@@ -5,7 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
6
6
|
import { getAuthToken } from '../../lib/auth.js';
|
|
7
7
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
8
|
-
import {
|
|
8
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
9
9
|
import { createOutputWriter } from '../../lib/output.js';
|
|
10
10
|
import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
|
|
11
11
|
import { Table } from '../../lib/table.js';
|
|
@@ -37,7 +37,7 @@ export function createCredentialsEndpointListCommand() {
|
|
|
37
37
|
params.append('search', options.search);
|
|
38
38
|
}
|
|
39
39
|
const response = await client.get(`/credentials/${credentialId}/endpoints?${params.toString()}`);
|
|
40
|
-
if (
|
|
40
|
+
if (isMachineReadable()) {
|
|
41
41
|
console.log(JSON.stringify(response, null, 2));
|
|
42
42
|
}
|
|
43
43
|
else {
|
|
@@ -4,7 +4,7 @@ import { Command } from 'commander';
|
|
|
4
4
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
5
5
|
import { getAuthToken } from '../../lib/auth.js';
|
|
6
6
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
|
-
import {
|
|
7
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
8
8
|
import { createOutputWriter, formatCredentialsTable } from '../../lib/output.js';
|
|
9
9
|
import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
|
|
10
10
|
export function createCredentialsListCommand() {
|
|
@@ -32,7 +32,7 @@ export function createCredentialsListCommand() {
|
|
|
32
32
|
params.append('search', options.search);
|
|
33
33
|
}
|
|
34
34
|
const response = await client.get(`/accounts/${accountId}/credentials?${params.toString()}`);
|
|
35
|
-
if (
|
|
35
|
+
if (isMachineReadable()) {
|
|
36
36
|
console.log(JSON.stringify(response, null, 2));
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
@@ -4,7 +4,7 @@ import { Command } from 'commander';
|
|
|
4
4
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
5
5
|
import { getAuthToken } from '../../lib/auth.js';
|
|
6
6
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
|
-
import {
|
|
7
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
8
8
|
import { createOutputWriter, formatPoliciesTable } from '../../lib/output.js';
|
|
9
9
|
import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
|
|
10
10
|
export function createCredentialsPolicyListCommand() {
|
|
@@ -27,7 +27,7 @@ export function createCredentialsPolicyListCommand() {
|
|
|
27
27
|
params.append('limit', options.limit);
|
|
28
28
|
params.append('offset', options.offset);
|
|
29
29
|
const response = await client.get(`/credentials/${credentialId}/policies?${params.toString()}`);
|
|
30
|
-
if (
|
|
30
|
+
if (isMachineReadable()) {
|
|
31
31
|
console.log(JSON.stringify(response, null, 2));
|
|
32
32
|
}
|
|
33
33
|
else {
|
package/dist/commands/doctor.js
CHANGED
|
@@ -6,7 +6,7 @@ import axios from 'axios';
|
|
|
6
6
|
import { getAuthToken } from '../lib/auth.js';
|
|
7
7
|
import { getGuildcoreUrl } from '../lib/config.js';
|
|
8
8
|
import { loadGlobalConfig, isAgentDirectory, getGlobalConfigPath, loadLocalConfig, } from '../lib/guild-config.js';
|
|
9
|
-
import {
|
|
9
|
+
import { isMachineReadable } from '../lib/output-mode.js';
|
|
10
10
|
import { createOutputWriter } from '../lib/output.js';
|
|
11
11
|
async function checkAuth() {
|
|
12
12
|
const token = await getAuthToken();
|
|
@@ -178,9 +178,9 @@ export function createDoctorCommand() {
|
|
|
178
178
|
const cmd = new Command('doctor');
|
|
179
179
|
cmd.description('Check CLI setup and diagnose issues').action(async () => {
|
|
180
180
|
const output = createOutputWriter();
|
|
181
|
-
const
|
|
181
|
+
const jsonMode = isMachineReadable();
|
|
182
182
|
const checks = [];
|
|
183
|
-
if (
|
|
183
|
+
if (!jsonMode) {
|
|
184
184
|
output.progress('\nChecking Guild CLI setup...\n');
|
|
185
185
|
}
|
|
186
186
|
const runners = [
|
|
@@ -195,7 +195,7 @@ export function createDoctorCommand() {
|
|
|
195
195
|
for (const runner of runners) {
|
|
196
196
|
const result = await runner();
|
|
197
197
|
checks.push(result);
|
|
198
|
-
if (
|
|
198
|
+
if (!jsonMode) {
|
|
199
199
|
const icon = result.status === 'pass'
|
|
200
200
|
? chalk.green('✓')
|
|
201
201
|
: result.status === 'fail'
|
|
@@ -212,7 +212,7 @@ export function createDoctorCommand() {
|
|
|
212
212
|
const passed = checks.filter((c) => c.status === 'pass').length;
|
|
213
213
|
const failed = checks.filter((c) => c.status === 'fail').length;
|
|
214
214
|
const skipped = checks.filter((c) => c.status === 'skip').length;
|
|
215
|
-
if (
|
|
215
|
+
if (jsonMode) {
|
|
216
216
|
output.data({ checks, passed, failed, skipped });
|
|
217
217
|
}
|
|
218
218
|
else {
|
|
@@ -5,7 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
6
6
|
import { getAuthToken } from '../../lib/auth.js';
|
|
7
7
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
8
|
-
import {
|
|
8
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
9
9
|
import { createOutputWriter } from '../../lib/output.js';
|
|
10
10
|
import { isInteractive } from '../../lib/stdin.js';
|
|
11
11
|
export function createIntegrationConnectCommand() {
|
|
@@ -54,7 +54,7 @@ export function createIntegrationConnectCommand() {
|
|
|
54
54
|
params.append('auth_config_id', integration.auth_config.id);
|
|
55
55
|
params.append('owner_id', options.owner);
|
|
56
56
|
const credential = await client.post(`/credentials/api-key?${params.toString()}`, { tokens: { token: apiKey } });
|
|
57
|
-
if (
|
|
57
|
+
if (isMachineReadable()) {
|
|
58
58
|
output.data(credential);
|
|
59
59
|
}
|
|
60
60
|
else {
|
|
@@ -5,7 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
6
6
|
import { getAuthToken } from '../../lib/auth.js';
|
|
7
7
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
8
|
-
import {
|
|
8
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
9
9
|
import { createOutputWriter } from '../../lib/output.js';
|
|
10
10
|
import { resolveOwnerId } from '../../lib/owner-helpers.js';
|
|
11
11
|
import { isInteractive } from '../../lib/stdin.js';
|
|
@@ -280,7 +280,7 @@ export function createIntegrationCreateCommand() {
|
|
|
280
280
|
body.webhook_config = webhookConfig;
|
|
281
281
|
}
|
|
282
282
|
const response = await client.post(`/accounts/${owner.name}/integrations`, body);
|
|
283
|
-
if (
|
|
283
|
+
if (isMachineReadable()) {
|
|
284
284
|
output.data(response);
|
|
285
285
|
}
|
|
286
286
|
else {
|
|
@@ -5,7 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
6
6
|
import { getAuthToken } from '../../lib/auth.js';
|
|
7
7
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
8
|
-
import {
|
|
8
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
9
9
|
import { createOutputWriter } from '../../lib/output.js';
|
|
10
10
|
function formatDate(dateStr) {
|
|
11
11
|
return new Date(dateStr).toLocaleString('en-US', {
|
|
@@ -77,7 +77,7 @@ export function createIntegrationGetCommand() {
|
|
|
77
77
|
}
|
|
78
78
|
const client = new GuildAPIClient();
|
|
79
79
|
const response = await client.get(`/integrations/${identifier}`);
|
|
80
|
-
if (
|
|
80
|
+
if (isMachineReadable()) {
|
|
81
81
|
output.data(response);
|
|
82
82
|
}
|
|
83
83
|
else {
|
|
@@ -4,7 +4,7 @@ import { Command } from 'commander';
|
|
|
4
4
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
5
5
|
import { getAuthToken } from '../../lib/auth.js';
|
|
6
6
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
|
-
import {
|
|
7
|
+
import { isMachineReadable } from '../../lib/output-mode.js';
|
|
8
8
|
import { createOutputWriter, formatIntegrationTable } from '../../lib/output.js';
|
|
9
9
|
import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
|
|
10
10
|
const SORT_MAP = {
|
|
@@ -44,7 +44,7 @@ export function createIntegrationListCommand() {
|
|
|
44
44
|
params.append('sort_by', sortField);
|
|
45
45
|
}
|
|
46
46
|
const response = await client.get(`/integrations?${params.toString()}`);
|
|
47
|
-
if (
|
|
47
|
+
if (isMachineReadable()) {
|
|
48
48
|
output.data(response);
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
@@ -6,7 +6,7 @@ import { readFileSync, existsSync } from 'fs';
|
|
|
6
6
|
import { GuildAPIClient } from '../../../lib/api-client.js';
|
|
7
7
|
import { getAuthToken } from '../../../lib/auth.js';
|
|
8
8
|
import { handleAxiosError } from '../../../lib/errors.js';
|
|
9
|
-
import {
|
|
9
|
+
import { isMachineReadable } from '../../../lib/output-mode.js';
|
|
10
10
|
import { createOutputWriter } from '../../../lib/output.js';
|
|
11
11
|
import { resolveVersionId } from '../../../lib/integration-helpers.js';
|
|
12
12
|
import { isInteractive } from '../../../lib/stdin.js';
|
|
@@ -43,13 +43,13 @@ export function createIntegrationOperationCreateCommand() {
|
|
|
43
43
|
}
|
|
44
44
|
const content = readFileSync(options.openapi, 'utf-8');
|
|
45
45
|
const response = await client.post(`/integration_versions/${versionId}/endpoint_generators`, { type: 'openapi', content });
|
|
46
|
-
if (
|
|
46
|
+
if (isMachineReadable()) {
|
|
47
47
|
output.data(response);
|
|
48
48
|
}
|
|
49
49
|
else {
|
|
50
50
|
console.log(chalk.green('OpenAPI operation generation triggered'));
|
|
51
51
|
console.log();
|
|
52
|
-
console.log(
|
|
52
|
+
console.log(`Operations will be generated asynchronously. Use 'guild integration operation list ${identifier}' to check results.`);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
else {
|
|
@@ -138,7 +138,7 @@ export function createIntegrationOperationCreateCommand() {
|
|
|
138
138
|
body.output_body_type = JSON.parse(readFileSync(options.outputBodySchema, 'utf-8'));
|
|
139
139
|
}
|
|
140
140
|
const response = await client.post(`/integration_versions/${versionId}/endpoints`, body);
|
|
141
|
-
if (
|
|
141
|
+
if (isMachineReadable()) {
|
|
142
142
|
output.data(response);
|
|
143
143
|
}
|
|
144
144
|
else {
|