@guildai/cli 0.3.15 → 0.3.17
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/clone.js +21 -40
- package/dist/commands/agent/code.js +12 -32
- package/dist/commands/agent/create.js +14 -30
- package/dist/commands/agent/fork.js +27 -73
- package/dist/commands/agent/get.js +5 -4
- package/dist/commands/agent/grep.js +7 -9
- package/dist/commands/agent/init.js +2 -0
- package/dist/commands/agent/list.js +5 -12
- package/dist/commands/agent/publish.js +27 -44
- package/dist/commands/agent/pull.js +8 -35
- package/dist/commands/agent/revalidate.js +8 -16
- package/dist/commands/agent/save.js +23 -74
- package/dist/commands/agent/search.js +5 -12
- package/dist/commands/agent/tags/add.js +14 -24
- package/dist/commands/agent/tags/list.js +12 -23
- package/dist/commands/agent/tags/remove.js +16 -27
- package/dist/commands/agent/tags/set.js +14 -19
- package/dist/commands/agent/unpublish.js +12 -17
- package/dist/commands/agent/update.js +12 -29
- package/dist/commands/agent/versions.js +7 -11
- package/dist/commands/auth/login.js +4 -2
- package/dist/commands/auth/logout.js +3 -1
- package/dist/commands/auth/status.js +4 -3
- package/dist/commands/auth/token.js +3 -2
- package/dist/commands/chat.js +85 -10
- package/dist/commands/config/get.js +7 -9
- package/dist/commands/config/list.js +13 -11
- package/dist/commands/config/path.js +6 -4
- package/dist/commands/config/set.js +17 -22
- package/dist/commands/doctor.js +9 -7
- package/dist/commands/session/create.js +7 -5
- package/dist/commands/session/events.js +5 -3
- package/dist/commands/session/get.js +5 -3
- package/dist/commands/session/list.js +5 -4
- package/dist/commands/session/send.js +7 -5
- package/dist/commands/session/tasks.js +5 -3
- package/dist/commands/setup.js +15 -14
- package/dist/commands/trigger/activate.js +7 -6
- package/dist/commands/trigger/create.js +16 -15
- package/dist/commands/trigger/deactivate.js +7 -6
- package/dist/commands/trigger/get.js +5 -4
- package/dist/commands/trigger/list.js +5 -5
- package/dist/commands/trigger/sessions.js +7 -6
- package/dist/commands/trigger/update.js +11 -10
- package/dist/commands/version.js +7 -5
- package/dist/commands/workspace/agent/add.js +16 -22
- package/dist/commands/workspace/agent/list.js +9 -30
- package/dist/commands/workspace/agent/remove.js +9 -15
- package/dist/commands/workspace/context/edit.js +13 -27
- package/dist/commands/workspace/context/get.js +8 -14
- package/dist/commands/workspace/context/list.js +7 -38
- package/dist/commands/workspace/context/publish.js +7 -11
- package/dist/commands/workspace/create.js +7 -11
- package/dist/commands/workspace/current.js +19 -31
- package/dist/commands/workspace/get.js +7 -11
- package/dist/commands/workspace/list.js +5 -8
- package/dist/commands/workspace/select.js +17 -22
- package/dist/components/TaskView.js +2 -0
- package/dist/lib/output.js +4 -4
- package/dist/lib/session-events.d.ts +7 -2
- package/package.json +1 -1
package/dist/commands/chat.js
CHANGED
|
@@ -76,7 +76,11 @@ function CustomInput({ value, onChange, onSubmit, trackedTasksSize, setShowTaskP
|
|
|
76
76
|
const renderedValue = value + chalk.inverse(' ');
|
|
77
77
|
return React.createElement(Text, null, renderedValue);
|
|
78
78
|
}
|
|
79
|
-
function InputWrapper({ isReady, input, setInput, handleSubmit, trackedTasksSize, setShowTaskPanel, isActive, }) {
|
|
79
|
+
function InputWrapper({ isReady, isInterrupted, input, setInput, handleSubmit, trackedTasksSize, setShowTaskPanel, isActive, }) {
|
|
80
|
+
if (isInterrupted) {
|
|
81
|
+
return (React.createElement(Box, { height: 1 },
|
|
82
|
+
React.createElement(Text, { color: "gray" }, chalk.dim('Interrupted — this session cannot be resumed. Press Ctrl+C to exit.'))));
|
|
83
|
+
}
|
|
80
84
|
return (React.createElement(Box, { height: 1 },
|
|
81
85
|
React.createElement(Text, { color: isReady ? BRAND_COLOR : 'gray' }, "> "),
|
|
82
86
|
isReady && isActive ? (React.createElement(CustomInput, { value: input, onChange: setInput, onSubmit: handleSubmit, trackedTasksSize: trackedTasksSize, setShowTaskPanel: setShowTaskPanel, isActive: isActive })) : isReady ? (React.createElement(Text, null, input)) : (React.createElement(Text, null, chalk.dim('(connecting...)')))));
|
|
@@ -229,11 +233,22 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
229
233
|
]
|
|
230
234
|
: []);
|
|
231
235
|
const [input, setInput] = useState('');
|
|
236
|
+
const inputTextRef = useRef('');
|
|
237
|
+
// Keep ref in sync so useInput handler can read current input text
|
|
238
|
+
const updateInput = (value) => {
|
|
239
|
+
inputTextRef.current = value;
|
|
240
|
+
setInput(value);
|
|
241
|
+
};
|
|
232
242
|
const [currentOperation, setCurrentOperation] = useState(resumeEvents ? '' : 'Waiting for response...');
|
|
233
243
|
const [exitHint, setExitHint] = useState(null);
|
|
244
|
+
const [isInterrupted, setIsInterrupted] = useState(false);
|
|
234
245
|
// Double-tap exit tracking (shared for Ctrl+C and Ctrl+D)
|
|
235
246
|
const exitKeyPressed = useRef(false);
|
|
236
247
|
const exitKeyTimeout = useRef(null);
|
|
248
|
+
// Interrupt tracking - prevents duplicate interrupt requests
|
|
249
|
+
const isInterrupting = useRef(false);
|
|
250
|
+
// Debounce Escape after mount so splash-skip doesn't trigger interrupt
|
|
251
|
+
const mountedAt = useRef(Date.now());
|
|
237
252
|
// Track terminal size for layout calculations
|
|
238
253
|
// Debounce resize to prevent spam during rapid resize events
|
|
239
254
|
const [terminalSize, setTerminalSize] = useState({
|
|
@@ -264,11 +279,55 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
264
279
|
}, []);
|
|
265
280
|
// Global keyboard shortcuts
|
|
266
281
|
useInput((input, key) => {
|
|
267
|
-
//
|
|
282
|
+
// Escape: Interrupt agent while processing
|
|
283
|
+
// Ignore Escape within 300ms of mount to prevent splash-skip from triggering interrupt
|
|
284
|
+
if (key.escape &&
|
|
285
|
+
client &&
|
|
286
|
+
session &&
|
|
287
|
+
currentOperation &&
|
|
288
|
+
!isInterrupting.current &&
|
|
289
|
+
Date.now() - mountedAt.current > 300) {
|
|
290
|
+
isInterrupting.current = true;
|
|
291
|
+
client
|
|
292
|
+
.post(`/sessions/${session.id}/interrupt`, {})
|
|
293
|
+
.then(() => {
|
|
294
|
+
debug('Session interrupted');
|
|
295
|
+
})
|
|
296
|
+
.catch((err) => {
|
|
297
|
+
debug('Interrupt failed (session may already be done):', err);
|
|
298
|
+
})
|
|
299
|
+
.finally(() => {
|
|
300
|
+
isInterrupting.current = false;
|
|
301
|
+
});
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
// Ctrl-C: Clear input on first press (if text present), double-tap to exit
|
|
268
305
|
const isCtrlC = input === '\x03' || (key.ctrl && input === 'c');
|
|
306
|
+
if (isCtrlC) {
|
|
307
|
+
// If there's text in the input, clear it instead of showing exit hint
|
|
308
|
+
if (inputTextRef.current && !exitKeyPressed.current) {
|
|
309
|
+
updateInput('');
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (exitKeyPressed.current) {
|
|
313
|
+
if (preConnectedSession?.id && resumeCommand) {
|
|
314
|
+
printResumeHint(preConnectedSession.id, resumeCommand);
|
|
315
|
+
}
|
|
316
|
+
process.exit(0);
|
|
317
|
+
}
|
|
318
|
+
exitKeyPressed.current = true;
|
|
319
|
+
setExitHint('ctrl-c');
|
|
320
|
+
if (exitKeyTimeout.current)
|
|
321
|
+
clearTimeout(exitKeyTimeout.current);
|
|
322
|
+
exitKeyTimeout.current = setTimeout(() => {
|
|
323
|
+
exitKeyPressed.current = false;
|
|
324
|
+
setExitHint(null);
|
|
325
|
+
}, 2000);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
// Ctrl-D: Double-tap to exit
|
|
269
329
|
const isCtrlD = input === '\x04' || (key.ctrl && input === 'd');
|
|
270
|
-
if (
|
|
271
|
-
const keyName = isCtrlC ? 'ctrl-c' : 'ctrl-d';
|
|
330
|
+
if (isCtrlD) {
|
|
272
331
|
if (exitKeyPressed.current) {
|
|
273
332
|
if (preConnectedSession?.id && resumeCommand) {
|
|
274
333
|
printResumeHint(preConnectedSession.id, resumeCommand);
|
|
@@ -276,7 +335,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
276
335
|
process.exit(0);
|
|
277
336
|
}
|
|
278
337
|
exitKeyPressed.current = true;
|
|
279
|
-
setExitHint(
|
|
338
|
+
setExitHint('ctrl-d');
|
|
280
339
|
if (exitKeyTimeout.current)
|
|
281
340
|
clearTimeout(exitKeyTimeout.current);
|
|
282
341
|
exitKeyTimeout.current = setTimeout(() => {
|
|
@@ -539,6 +598,19 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
539
598
|
setCurrentOperation('');
|
|
540
599
|
}
|
|
541
600
|
}
|
|
601
|
+
else if (event.type === 'interrupted') {
|
|
602
|
+
// Session was interrupted — interrupted sessions are terminal on the backend
|
|
603
|
+
setMessages((prev) => [
|
|
604
|
+
...prev,
|
|
605
|
+
{
|
|
606
|
+
key: `interrupted-${Date.now()}`,
|
|
607
|
+
content: chalk.dim('⊘ Interrupted'),
|
|
608
|
+
type: 'assistant',
|
|
609
|
+
},
|
|
610
|
+
]);
|
|
611
|
+
setCurrentOperation('');
|
|
612
|
+
setIsInterrupted(true);
|
|
613
|
+
}
|
|
542
614
|
else if (isUnfulfilledAgentInstallRequest(event)) {
|
|
543
615
|
// Check for agent install requests that need user approval
|
|
544
616
|
if (!promptedEventIds.current.has(event.id) && !pendingInstallRequest) {
|
|
@@ -589,7 +661,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
589
661
|
},
|
|
590
662
|
]);
|
|
591
663
|
// Clear input right after showing the message
|
|
592
|
-
|
|
664
|
+
updateInput('');
|
|
593
665
|
try {
|
|
594
666
|
await client.post(`/sessions/${session.id}/events`, {
|
|
595
667
|
content: value,
|
|
@@ -657,18 +729,21 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
657
729
|
const showTasksHintText = '[ctrl-t to show tasks]';
|
|
658
730
|
const showTasksHint = `[${chalk.bold('ctrl-t')} to show tasks]`;
|
|
659
731
|
// Build status line with right-aligned hint
|
|
660
|
-
//
|
|
732
|
+
// Priority: exit hint > esc to interrupt > ctrl-t task hint
|
|
661
733
|
// Strip ANSI codes to get visible length (statusLine contains spinner with color codes)
|
|
662
734
|
const stripAnsi = (str) => str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
663
735
|
const statusWithHint = (() => {
|
|
664
|
-
// Pick which hint to show: exit hint takes priority
|
|
665
736
|
let hintText = null;
|
|
666
737
|
let hint = null;
|
|
667
738
|
if (exitHint) {
|
|
668
739
|
hintText = `[${exitHint} again to exit]`;
|
|
669
740
|
hint = `[${chalk.bold(exitHint)} again to exit]`;
|
|
670
741
|
}
|
|
671
|
-
else if (
|
|
742
|
+
else if (currentOperation) {
|
|
743
|
+
hintText = '(esc to interrupt)';
|
|
744
|
+
hint = `(${chalk.bold('esc')} to interrupt)`;
|
|
745
|
+
}
|
|
746
|
+
if (!hintText && activeTaskCount > 0 && currentOperation) {
|
|
672
747
|
hintText = showTaskPanel ? hideTasksHintText : showTasksHintText;
|
|
673
748
|
hint = showTaskPanel ? hideTasksHint : showTasksHint;
|
|
674
749
|
}
|
|
@@ -721,7 +796,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
721
796
|
React.createElement(Text, null, statusWithHint)),
|
|
722
797
|
React.createElement(Box, { height: 1 },
|
|
723
798
|
React.createElement(Text, { color: "gray" }, '─'.repeat(Math.max(1, terminalWidth - 2)))),
|
|
724
|
-
React.createElement(InputWrapper, { isReady: isReady, input: input, setInput:
|
|
799
|
+
React.createElement(InputWrapper, { isReady: isReady, isInterrupted: isInterrupted, input: input, setInput: updateInput, handleSubmit: handleSubmit, trackedTasksSize: tasks.length, setShowTaskPanel: setShowTaskPanel, isActive: isActive })));
|
|
725
800
|
}
|
|
726
801
|
export async function ensureAuthenticated() {
|
|
727
802
|
const token = await getAuthToken();
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { loadConfig, } from '../../lib/guild-config.js';
|
|
4
4
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
5
|
+
import { createOutputWriter } from '../../lib/output.js';
|
|
5
6
|
/**
|
|
6
7
|
* All valid config keys across global and local configs.
|
|
7
8
|
* Note: default_workspace_name is internal (auto-resolved from API).
|
|
@@ -21,14 +22,11 @@ export function createConfigGetCommand() {
|
|
|
21
22
|
.description('Get a configuration value')
|
|
22
23
|
.argument('<key>', `Config key (${ALL_VALID_KEYS.join(', ')})`)
|
|
23
24
|
.action(async (key) => {
|
|
25
|
+
const output = createOutputWriter();
|
|
24
26
|
const config = await loadConfig();
|
|
25
27
|
const mode = getOutputMode();
|
|
26
28
|
if (!ALL_VALID_KEYS.includes(key)) {
|
|
27
|
-
|
|
28
|
-
console.error('');
|
|
29
|
-
console.error('Valid keys:');
|
|
30
|
-
console.error(` Global: ${VALID_GLOBAL_KEYS.join(', ')}`);
|
|
31
|
-
console.error(` Local: ${VALID_LOCAL_KEYS.join(', ')}`);
|
|
29
|
+
output.error(`Unknown config key: ${key}\n\nValid keys:\n Global: ${VALID_GLOBAL_KEYS.join(', ')}\n Local: ${VALID_LOCAL_KEYS.join(', ')}`);
|
|
32
30
|
process.exit(1);
|
|
33
31
|
}
|
|
34
32
|
// Look up in global first, then local
|
|
@@ -46,18 +44,18 @@ export function createConfigGetCommand() {
|
|
|
46
44
|
}
|
|
47
45
|
if (value === undefined) {
|
|
48
46
|
if (mode === 'json') {
|
|
49
|
-
|
|
47
|
+
output.data({ key, value: null, source: null });
|
|
50
48
|
}
|
|
51
49
|
else {
|
|
52
|
-
|
|
50
|
+
output.error(`Key not found: ${key}`);
|
|
53
51
|
}
|
|
54
52
|
process.exit(1);
|
|
55
53
|
}
|
|
56
54
|
if (mode === 'json') {
|
|
57
|
-
|
|
55
|
+
output.data({ key, value, source });
|
|
58
56
|
}
|
|
59
57
|
else {
|
|
60
|
-
|
|
58
|
+
output.data(value);
|
|
61
59
|
}
|
|
62
60
|
});
|
|
63
61
|
return cmd;
|
|
@@ -3,39 +3,41 @@ import { Command } from 'commander';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { loadConfig } from '../../lib/guild-config.js';
|
|
5
5
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
6
|
+
import { createOutputWriter } from '../../lib/output.js';
|
|
6
7
|
export function createConfigListCommand() {
|
|
7
8
|
const cmd = new Command('list');
|
|
8
9
|
cmd.description('Show all configuration values').action(async () => {
|
|
10
|
+
const output = createOutputWriter();
|
|
9
11
|
const config = await loadConfig();
|
|
10
12
|
const mode = getOutputMode();
|
|
11
13
|
if (mode === 'json') {
|
|
12
|
-
|
|
14
|
+
output.data({
|
|
13
15
|
global: config.global || null,
|
|
14
16
|
local: config.local || null,
|
|
15
|
-
}
|
|
17
|
+
});
|
|
16
18
|
return;
|
|
17
19
|
}
|
|
18
20
|
const hasGlobal = config.global && Object.keys(config.global).length > 0;
|
|
19
21
|
const hasLocal = config.local && Object.keys(config.local).length > 0;
|
|
20
22
|
if (!hasGlobal && !hasLocal) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
output.progress('No configuration found.');
|
|
24
|
+
output.progress('');
|
|
25
|
+
output.progress('Set a default workspace:');
|
|
26
|
+
output.progress(chalk.dim(' guild workspace select'));
|
|
25
27
|
return;
|
|
26
28
|
}
|
|
27
29
|
if (hasGlobal) {
|
|
28
|
-
|
|
30
|
+
output.progress(chalk.bold('Global config') + chalk.dim(' (~/.guild/config.json):'));
|
|
29
31
|
for (const [key, value] of Object.entries(config.global)) {
|
|
30
|
-
|
|
32
|
+
output.progress(` ${key}: ${chalk.cyan(String(value))}`);
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
if (hasLocal) {
|
|
34
36
|
if (hasGlobal)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
output.progress('');
|
|
38
|
+
output.progress(chalk.bold('Local config') + chalk.dim(' (guild.json):'));
|
|
37
39
|
for (const [key, value] of Object.entries(config.local)) {
|
|
38
|
-
|
|
40
|
+
output.progress(` ${key}: ${chalk.cyan(String(value))}`);
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
});
|
|
@@ -4,6 +4,7 @@ import chalk from 'chalk';
|
|
|
4
4
|
import * as fs from 'fs/promises';
|
|
5
5
|
import { getGlobalConfigPath, getLocalConfigPath } from '../../lib/guild-config.js';
|
|
6
6
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
7
|
+
import { createOutputWriter } from '../../lib/output.js';
|
|
7
8
|
async function fileExists(filePath) {
|
|
8
9
|
return fs
|
|
9
10
|
.access(filePath)
|
|
@@ -13,22 +14,23 @@ async function fileExists(filePath) {
|
|
|
13
14
|
export function createConfigPathCommand() {
|
|
14
15
|
const cmd = new Command('path');
|
|
15
16
|
cmd.description('Show configuration file paths').action(async () => {
|
|
17
|
+
const output = createOutputWriter();
|
|
16
18
|
const globalPath = getGlobalConfigPath();
|
|
17
19
|
const localPath = getLocalConfigPath();
|
|
18
20
|
const mode = getOutputMode();
|
|
19
21
|
const globalExists = await fileExists(globalPath);
|
|
20
22
|
const localExists = await fileExists(localPath);
|
|
21
23
|
if (mode === 'json') {
|
|
22
|
-
|
|
24
|
+
output.data({
|
|
23
25
|
global: { path: globalPath, exists: globalExists },
|
|
24
26
|
local: { path: localPath, exists: localExists },
|
|
25
|
-
}
|
|
27
|
+
});
|
|
26
28
|
return;
|
|
27
29
|
}
|
|
28
30
|
const globalStatus = globalExists ? chalk.green('exists') : chalk.dim('not found');
|
|
29
31
|
const localStatus = localExists ? chalk.green('exists') : chalk.dim('not found');
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
output.progress(`Global: ${globalPath} (${globalStatus})`);
|
|
33
|
+
output.progress(`Local: ${localPath} (${localStatus})`);
|
|
32
34
|
});
|
|
33
35
|
return cmd;
|
|
34
36
|
}
|
|
@@ -3,6 +3,7 @@ import { Command } from 'commander';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { saveGlobalConfig } from '../../lib/guild-config.js';
|
|
5
5
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
6
|
+
import { createOutputWriter } from '../../lib/output.js';
|
|
6
7
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
7
8
|
import { debug } from '../../lib/errors.js';
|
|
8
9
|
/**
|
|
@@ -19,15 +20,13 @@ const VALID_GLOBAL_KEYS = [
|
|
|
19
20
|
const BOOLEAN_KEYS = new Set(['debug', 'json', 'quiet']);
|
|
20
21
|
const TRUTHY = new Set(['true', 'yes', 'on', '1']);
|
|
21
22
|
const FALSY = new Set(['false', 'no', 'off', '0']);
|
|
22
|
-
function parseBoolean(value, key) {
|
|
23
|
+
function parseBoolean(value, key, output) {
|
|
23
24
|
const lower = value.toLowerCase();
|
|
24
25
|
if (TRUTHY.has(lower))
|
|
25
26
|
return true;
|
|
26
27
|
if (FALSY.has(lower))
|
|
27
28
|
return false;
|
|
28
|
-
|
|
29
|
-
console.error('');
|
|
30
|
-
console.error('Accepted values: true/false, yes/no, on/off, 1/0');
|
|
29
|
+
output.error(`Invalid boolean value for "${key}": "${value}"\n\nAccepted values: true/false, yes/no, on/off, 1/0`);
|
|
31
30
|
process.exit(1);
|
|
32
31
|
}
|
|
33
32
|
/**
|
|
@@ -66,12 +65,12 @@ async function resolveOwnerName(ownerId) {
|
|
|
66
65
|
return undefined;
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
|
-
function printResult(key, value, mode) {
|
|
68
|
+
function printResult(key, value, mode, output) {
|
|
70
69
|
if (mode === 'json') {
|
|
71
|
-
|
|
70
|
+
output.data({ key, value });
|
|
72
71
|
}
|
|
73
72
|
else {
|
|
74
|
-
|
|
73
|
+
output.success(`Set ${chalk.bold(key)} = ${chalk.cyan(String(value))}`);
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
export function createConfigSetCommand() {
|
|
@@ -81,21 +80,17 @@ export function createConfigSetCommand() {
|
|
|
81
80
|
.argument('<key>', `Config key (${VALID_GLOBAL_KEYS.join(', ')})`)
|
|
82
81
|
.argument('<value>', 'Value to set')
|
|
83
82
|
.action(async (key, value) => {
|
|
83
|
+
const output = createOutputWriter();
|
|
84
84
|
const mode = getOutputMode();
|
|
85
85
|
if (!VALID_GLOBAL_KEYS.includes(key)) {
|
|
86
|
-
|
|
87
|
-
console.error('');
|
|
88
|
-
console.error('Valid keys:');
|
|
89
|
-
for (const k of VALID_GLOBAL_KEYS) {
|
|
90
|
-
console.error(` ${k}`);
|
|
91
|
-
}
|
|
86
|
+
output.error(`Unknown config key: ${key}\n\nValid keys:\n${VALID_GLOBAL_KEYS.map((k) => ` ${k}`).join('\n')}`);
|
|
92
87
|
process.exit(1);
|
|
93
88
|
}
|
|
94
89
|
const typedKey = key;
|
|
95
90
|
if (BOOLEAN_KEYS.has(typedKey)) {
|
|
96
|
-
const boolValue = parseBoolean(value, key);
|
|
91
|
+
const boolValue = parseBoolean(value, key, output);
|
|
97
92
|
await saveGlobalConfig({ [typedKey]: boolValue });
|
|
98
|
-
printResult(key, boolValue, mode);
|
|
93
|
+
printResult(key, boolValue, mode, output);
|
|
99
94
|
return;
|
|
100
95
|
}
|
|
101
96
|
if (typedKey === 'default_workspace') {
|
|
@@ -104,15 +99,15 @@ export function createConfigSetCommand() {
|
|
|
104
99
|
default_workspace: value,
|
|
105
100
|
default_workspace_name: name,
|
|
106
101
|
});
|
|
107
|
-
printResult(key, value, mode);
|
|
102
|
+
printResult(key, value, mode, output);
|
|
108
103
|
if (name) {
|
|
109
104
|
if (mode !== 'json') {
|
|
110
|
-
|
|
105
|
+
output.progress(` Workspace name: ${name}`);
|
|
111
106
|
}
|
|
112
107
|
}
|
|
113
108
|
else {
|
|
114
109
|
if (mode !== 'json') {
|
|
115
|
-
|
|
110
|
+
output.error('Could not resolve workspace name (not authenticated?)');
|
|
116
111
|
}
|
|
117
112
|
}
|
|
118
113
|
return;
|
|
@@ -123,21 +118,21 @@ export function createConfigSetCommand() {
|
|
|
123
118
|
default_owner: value,
|
|
124
119
|
default_owner_name: name,
|
|
125
120
|
});
|
|
126
|
-
printResult(key, value, mode);
|
|
121
|
+
printResult(key, value, mode, output);
|
|
127
122
|
if (name) {
|
|
128
123
|
if (mode !== 'json') {
|
|
129
|
-
|
|
124
|
+
output.progress(` Owner name: ${name}`);
|
|
130
125
|
}
|
|
131
126
|
}
|
|
132
127
|
else {
|
|
133
128
|
if (mode !== 'json') {
|
|
134
|
-
|
|
129
|
+
output.error('Could not resolve owner name (not authenticated?)');
|
|
135
130
|
}
|
|
136
131
|
}
|
|
137
132
|
return;
|
|
138
133
|
}
|
|
139
134
|
await saveGlobalConfig({ [typedKey]: value });
|
|
140
|
-
printResult(key, value, mode);
|
|
135
|
+
printResult(key, value, mode, output);
|
|
141
136
|
});
|
|
142
137
|
return cmd;
|
|
143
138
|
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -6,6 +6,7 @@ import { getAuthToken } from '../lib/auth.js';
|
|
|
6
6
|
import { getGuildcoreUrl } from '../lib/config.js';
|
|
7
7
|
import { loadGlobalConfig, isAgentDirectory, getGlobalConfigPath, loadLocalConfig, } from '../lib/guild-config.js';
|
|
8
8
|
import { getOutputMode } from '../lib/output-mode.js';
|
|
9
|
+
import { createOutputWriter } from '../lib/output.js';
|
|
9
10
|
async function checkAuth() {
|
|
10
11
|
const token = await getAuthToken();
|
|
11
12
|
if (token) {
|
|
@@ -175,10 +176,11 @@ async function checkGit() {
|
|
|
175
176
|
export function createDoctorCommand() {
|
|
176
177
|
const cmd = new Command('doctor');
|
|
177
178
|
cmd.description('Check CLI setup and diagnose issues').action(async () => {
|
|
179
|
+
const output = createOutputWriter();
|
|
178
180
|
const mode = getOutputMode();
|
|
179
181
|
const checks = [];
|
|
180
182
|
if (mode !== 'json') {
|
|
181
|
-
|
|
183
|
+
output.progress('\nChecking Guild CLI setup...\n');
|
|
182
184
|
}
|
|
183
185
|
const runners = [
|
|
184
186
|
checkAuth,
|
|
@@ -199,10 +201,10 @@ export function createDoctorCommand() {
|
|
|
199
201
|
? chalk.red('✗')
|
|
200
202
|
: chalk.dim('-');
|
|
201
203
|
const nameCol = result.name.padEnd(20);
|
|
202
|
-
|
|
204
|
+
output.progress(` ${icon} ${chalk.bold(nameCol)} ${result.message}`);
|
|
203
205
|
if (result.suggestion) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
output.progress(` ${chalk.dim(result.suggestion)}`);
|
|
207
|
+
output.progress('');
|
|
206
208
|
}
|
|
207
209
|
}
|
|
208
210
|
}
|
|
@@ -210,10 +212,10 @@ export function createDoctorCommand() {
|
|
|
210
212
|
const failed = checks.filter((c) => c.status === 'fail').length;
|
|
211
213
|
const skipped = checks.filter((c) => c.status === 'skip').length;
|
|
212
214
|
if (mode === 'json') {
|
|
213
|
-
|
|
215
|
+
output.data({ checks, passed, failed, skipped });
|
|
214
216
|
}
|
|
215
217
|
else {
|
|
216
|
-
|
|
218
|
+
output.progress('');
|
|
217
219
|
const parts = [];
|
|
218
220
|
if (passed > 0)
|
|
219
221
|
parts.push(chalk.green(`${passed} passed`));
|
|
@@ -221,7 +223,7 @@ export function createDoctorCommand() {
|
|
|
221
223
|
parts.push(chalk.red(`${failed} failed`));
|
|
222
224
|
if (skipped > 0)
|
|
223
225
|
parts.push(chalk.dim(`${skipped} skipped`));
|
|
224
|
-
|
|
226
|
+
output.progress(parts.join(', '));
|
|
225
227
|
}
|
|
226
228
|
process.exit(failed > 0 ? 1 : 0);
|
|
227
229
|
});
|
|
@@ -4,6 +4,7 @@ import { GuildAPIClient } from '../../lib/api-client.js';
|
|
|
4
4
|
import { getAuthToken } from '../../lib/auth.js';
|
|
5
5
|
import { getWorkspaceId } from '../../lib/guild-config.js';
|
|
6
6
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
|
+
import { createOutputWriter } from '../../lib/output.js';
|
|
7
8
|
export function createSessionCreateCommand() {
|
|
8
9
|
const cmd = new Command('create');
|
|
9
10
|
cmd
|
|
@@ -13,21 +14,22 @@ export function createSessionCreateCommand() {
|
|
|
13
14
|
.option('--prompt <text>', 'Initial prompt (required for chat sessions)')
|
|
14
15
|
.option('--agent <identifier>', 'Agent identifier, e.g., owner/agent-name')
|
|
15
16
|
.action(async (options) => {
|
|
17
|
+
const output = createOutputWriter();
|
|
16
18
|
try {
|
|
17
19
|
const token = await getAuthToken();
|
|
18
20
|
if (!token) {
|
|
19
|
-
|
|
21
|
+
output.error('Not authenticated. Run: guild auth login');
|
|
20
22
|
process.exit(1);
|
|
21
23
|
}
|
|
22
24
|
if (options.type === 'chat' && !options.prompt) {
|
|
23
|
-
|
|
25
|
+
output.error('--prompt is required for chat sessions');
|
|
24
26
|
process.exit(1);
|
|
25
27
|
}
|
|
26
28
|
let workspaceId = options.workspace;
|
|
27
29
|
if (!workspaceId) {
|
|
28
30
|
const resolved = await getWorkspaceId();
|
|
29
31
|
if (!resolved) {
|
|
30
|
-
|
|
32
|
+
output.error('No workspace specified. Run: guild workspace select');
|
|
31
33
|
process.exit(1);
|
|
32
34
|
}
|
|
33
35
|
workspaceId = resolved.workspaceId;
|
|
@@ -43,11 +45,11 @@ export function createSessionCreateCommand() {
|
|
|
43
45
|
body.agent_id = options.agent;
|
|
44
46
|
}
|
|
45
47
|
const response = await client.post(`/workspaces/${workspaceId}/sessions`, body);
|
|
46
|
-
|
|
48
|
+
output.data(response);
|
|
47
49
|
}
|
|
48
50
|
catch (error) {
|
|
49
51
|
const formattedError = handleAxiosError(error);
|
|
50
|
-
|
|
52
|
+
output.error(`Failed to create session: ${formattedError.details}`);
|
|
51
53
|
process.exit(1);
|
|
52
54
|
}
|
|
53
55
|
});
|
|
@@ -3,6 +3,7 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
4
4
|
import { getAuthToken } from '../../lib/auth.js';
|
|
5
5
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
6
|
+
import { createOutputWriter } from '../../lib/output.js';
|
|
6
7
|
export function createSessionEventsCommand() {
|
|
7
8
|
const cmd = new Command('events');
|
|
8
9
|
cmd
|
|
@@ -12,10 +13,11 @@ export function createSessionEventsCommand() {
|
|
|
12
13
|
.option('--limit <number>', 'Number of results to return', '100')
|
|
13
14
|
.option('--offset <number>', 'Offset for pagination', '0')
|
|
14
15
|
.action(async (sessionId, options) => {
|
|
16
|
+
const output = createOutputWriter();
|
|
15
17
|
try {
|
|
16
18
|
const token = await getAuthToken();
|
|
17
19
|
if (!token) {
|
|
18
|
-
|
|
20
|
+
output.error('Not authenticated. Run: guild auth login');
|
|
19
21
|
process.exit(1);
|
|
20
22
|
}
|
|
21
23
|
const client = new GuildAPIClient();
|
|
@@ -26,11 +28,11 @@ export function createSessionEventsCommand() {
|
|
|
26
28
|
params.append('types', options.types);
|
|
27
29
|
}
|
|
28
30
|
const response = await client.get(`/sessions/${sessionId}/events?${params.toString()}`);
|
|
29
|
-
|
|
31
|
+
output.data(response);
|
|
30
32
|
}
|
|
31
33
|
catch (error) {
|
|
32
34
|
const formattedError = handleAxiosError(error);
|
|
33
|
-
|
|
35
|
+
output.error(`Failed to get session events: ${formattedError.details}`);
|
|
34
36
|
process.exit(1);
|
|
35
37
|
}
|
|
36
38
|
});
|
|
@@ -3,25 +3,27 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
4
4
|
import { getAuthToken } from '../../lib/auth.js';
|
|
5
5
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
6
|
+
import { createOutputWriter } from '../../lib/output.js';
|
|
6
7
|
export function createSessionGetCommand() {
|
|
7
8
|
const cmd = new Command('get');
|
|
8
9
|
cmd
|
|
9
10
|
.description('Get session details')
|
|
10
11
|
.argument('<session-id>', 'Session ID')
|
|
11
12
|
.action(async (sessionId) => {
|
|
13
|
+
const output = createOutputWriter();
|
|
12
14
|
try {
|
|
13
15
|
const token = await getAuthToken();
|
|
14
16
|
if (!token) {
|
|
15
|
-
|
|
17
|
+
output.error('Not authenticated. Run: guild auth login');
|
|
16
18
|
process.exit(1);
|
|
17
19
|
}
|
|
18
20
|
const client = new GuildAPIClient();
|
|
19
21
|
const response = await client.get(`/sessions/${sessionId}`);
|
|
20
|
-
|
|
22
|
+
output.data(response);
|
|
21
23
|
}
|
|
22
24
|
catch (error) {
|
|
23
25
|
const formattedError = handleAxiosError(error);
|
|
24
|
-
|
|
26
|
+
output.error(`Failed to get session: ${formattedError.details}`);
|
|
25
27
|
process.exit(1);
|
|
26
28
|
}
|
|
27
29
|
});
|
|
@@ -5,7 +5,7 @@ import { getAuthToken } from '../../lib/auth.js';
|
|
|
5
5
|
import { getWorkspaceId } from '../../lib/guild-config.js';
|
|
6
6
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
7
|
import { getOutputMode } from '../../lib/output-mode.js';
|
|
8
|
-
import { formatSessionTable } from '../../lib/output.js';
|
|
8
|
+
import { createOutputWriter, formatSessionTable } from '../../lib/output.js';
|
|
9
9
|
export function createSessionListCommand() {
|
|
10
10
|
const cmd = new Command('list');
|
|
11
11
|
cmd
|
|
@@ -15,17 +15,18 @@ export function createSessionListCommand() {
|
|
|
15
15
|
.option('--limit <number>', 'Number of results to return', '20')
|
|
16
16
|
.option('--offset <number>', 'Offset for pagination', '0')
|
|
17
17
|
.action(async (options) => {
|
|
18
|
+
const output = createOutputWriter();
|
|
18
19
|
try {
|
|
19
20
|
const token = await getAuthToken();
|
|
20
21
|
if (!token) {
|
|
21
|
-
|
|
22
|
+
output.error('Not authenticated. Run: guild auth login');
|
|
22
23
|
process.exit(1);
|
|
23
24
|
}
|
|
24
25
|
let workspaceId = options.workspace;
|
|
25
26
|
if (!workspaceId) {
|
|
26
27
|
const resolved = await getWorkspaceId();
|
|
27
28
|
if (!resolved) {
|
|
28
|
-
|
|
29
|
+
output.error('No workspace specified. Run: guild workspace select');
|
|
29
30
|
process.exit(1);
|
|
30
31
|
}
|
|
31
32
|
workspaceId = resolved.workspaceId;
|
|
@@ -47,7 +48,7 @@ export function createSessionListCommand() {
|
|
|
47
48
|
}
|
|
48
49
|
catch (error) {
|
|
49
50
|
const formattedError = handleAxiosError(error);
|
|
50
|
-
|
|
51
|
+
output.error(`Failed to list sessions: ${formattedError.details}`);
|
|
51
52
|
process.exit(1);
|
|
52
53
|
}
|
|
53
54
|
});
|