@guildai/cli 0.6.1 → 0.7.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/README.md +3 -1
- package/dist/commands/agent/chat.js +17 -42
- package/dist/commands/agent/publish.js +13 -53
- package/dist/commands/agent/save.js +14 -50
- package/dist/commands/agent/test.js +24 -51
- package/dist/commands/chat.d.ts +2 -1
- package/dist/commands/chat.js +165 -77
- package/dist/commands/session/interrupt.d.ts +3 -0
- package/dist/commands/session/interrupt.js +33 -0
- package/dist/commands/setup.js +70 -11
- package/dist/index.js +2 -0
- package/dist/lib/event-filter.d.ts +50 -0
- package/dist/lib/event-filter.js +91 -0
- package/dist/lib/generated-types.d.ts +2 -0
- package/dist/lib/generated-types.js +20 -0
- package/dist/lib/session-events.d.ts +26 -1
- package/dist/lib/session-polling.js +1 -1
- package/dist/lib/version-helpers.d.ts +15 -0
- package/dist/lib/version-helpers.js +83 -0
- package/dist/mcp/tools.js +1 -1
- package/docs/CLI_WORKFLOW.md +7 -1
- package/docs/DESIGN.md +1 -1
- package/docs/skills/codex-agent-dev.md +155 -0
- package/docs/skills/integrations.md +338 -0
- package/package.json +1 -1
package/dist/commands/chat.js
CHANGED
|
@@ -15,6 +15,7 @@ import path from 'path';
|
|
|
15
15
|
import { fileURLToPath } from 'url';
|
|
16
16
|
import { isUnfulfilledAgentInstallRequest, isFilteredTaskName, getTaskDisplayName, matchesAgent, getAgentName, } from '../lib/session-events.js';
|
|
17
17
|
import { printResumeHint, fetchSession, fetchSessionEvents, eventsToDisplayMessages, } from '../lib/session-resume.js';
|
|
18
|
+
import { DEFAULT_EVENT_TYPES, parseEventFilter, shouldShowEvent, } from '../lib/event-filter.js';
|
|
18
19
|
import { fetchEvents, fetchTasks } from '../lib/session-events-fetch.js';
|
|
19
20
|
import { AgentInstallPrompt } from '../components/AgentInstallPrompt.js';
|
|
20
21
|
import { getWorkspaceId } from '../lib/guild-config.js';
|
|
@@ -117,7 +118,7 @@ function InputWrapper({ isReady, isInterrupted, input, setInput, handleSubmit, t
|
|
|
117
118
|
React.createElement(Text, { color: isReady ? BRAND_COLOR : 'gray' }, "> "),
|
|
118
119
|
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...)')))));
|
|
119
120
|
}
|
|
120
|
-
export function ChatApp({ initialPrompt, version, workspaceId, versionId, agentName, showSplash = true, resumeSession, resumeEvents, resumeCommand, openDashboard, }) {
|
|
121
|
+
export function ChatApp({ initialPrompt, version, workspaceId, versionId, agentName, showSplash = true, resumeSession, resumeEvents, resumeCommand, openDashboard, eventFilter, }) {
|
|
121
122
|
const { exit } = useApp();
|
|
122
123
|
const isResuming = !!resumeSession;
|
|
123
124
|
const [phase, setPhase] = useState(isResuming || !showSplash ? 'chat' : 'splash');
|
|
@@ -241,13 +242,14 @@ export function ChatApp({ initialPrompt, version, workspaceId, versionId, agentN
|
|
|
241
242
|
}
|
|
242
243
|
// If not connected yet, ignore escape (let connection complete)
|
|
243
244
|
} })),
|
|
244
|
-
phase === 'chat' && (React.createElement(ChatUIWithConnection, { initialPrompt: initialPrompt, version: version, versionId: versionId, agentName: agentName, client: connectedClient, session: connectedSession, onFirstMessage: () => setFirstMessageReceived(true), resumeEvents: resumeEvents, resumeCommand: resumeCommand })),
|
|
245
|
+
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 })),
|
|
245
246
|
(phase === 'splash' || phase === 'finalizing') &&
|
|
246
247
|
connectedSession &&
|
|
247
248
|
connectedClient && (React.createElement(Box, { display: "none" },
|
|
248
|
-
React.createElement(ChatUIWithConnection, { initialPrompt: initialPrompt, version: version, versionId: versionId, agentName: agentName, client: connectedClient, session: connectedSession, onFirstMessage: () => setFirstMessageReceived(true), isActive: false })))));
|
|
249
|
+
React.createElement(ChatUIWithConnection, { initialPrompt: initialPrompt, version: version, versionId: versionId, agentName: agentName, client: connectedClient, session: connectedSession, onFirstMessage: () => setFirstMessageReceived(true), isActive: false, eventFilter: eventFilter })))));
|
|
249
250
|
}
|
|
250
|
-
function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _versionId, agentName, client: preConnectedClient, session: preConnectedSession, onFirstMessage, isActive = true, resumeEvents, resumeCommand, }) {
|
|
251
|
+
function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _versionId, agentName, client: preConnectedClient, session: preConnectedSession, onFirstMessage, isActive = true, resumeEvents, resumeCommand, eventFilter, }) {
|
|
252
|
+
const activeFilter = eventFilter ?? DEFAULT_EVENT_TYPES;
|
|
251
253
|
// Note: We handle SIGINT directly via process.on, not using useApp().exit
|
|
252
254
|
// Task panel state - managed at this level to handle keyboard input before TextInput
|
|
253
255
|
// Default to showing task panel (Ctrl-T to toggle)
|
|
@@ -485,9 +487,9 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
485
487
|
isPollingTasks.current = false;
|
|
486
488
|
}
|
|
487
489
|
};
|
|
488
|
-
// Poll immediately and then every
|
|
490
|
+
// Poll immediately and then every 2 seconds
|
|
489
491
|
pollTasks();
|
|
490
|
-
const interval = setInterval(pollTasks,
|
|
492
|
+
const interval = setInterval(pollTasks, 2000);
|
|
491
493
|
return () => {
|
|
492
494
|
clearInterval(interval);
|
|
493
495
|
};
|
|
@@ -525,18 +527,107 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
525
527
|
}
|
|
526
528
|
// Process events that affect the chat UI (task state comes from tasks poll)
|
|
527
529
|
if (event.type === 'runtime_error') {
|
|
528
|
-
//
|
|
529
|
-
const errorText = typeof event.content === 'string' ? event.content : 'Unknown error';
|
|
530
|
-
const taskName = agentName || 'assistant';
|
|
531
|
-
setMessages((prev) => [
|
|
532
|
-
...prev,
|
|
533
|
-
{
|
|
534
|
-
key: `error-${Date.now()}`,
|
|
535
|
-
content: `${chalk.red('●')} ${chalk.bold(taskName)}\n${chalk.red(`Error: ${errorText}`)}`,
|
|
536
|
-
type: 'assistant',
|
|
537
|
-
},
|
|
538
|
-
]);
|
|
530
|
+
// Always clear the spinner on runtime errors so the UI doesn't get stuck
|
|
539
531
|
setCurrentOperation('');
|
|
532
|
+
// Show runtime errors in the chat (gated on --events filter)
|
|
533
|
+
if (shouldShowEvent('runtime_error', activeFilter)) {
|
|
534
|
+
const errorText = typeof event.content === 'string' ? event.content : 'Unknown error';
|
|
535
|
+
const taskName = agentName || 'assistant';
|
|
536
|
+
setMessages((prev) => [
|
|
537
|
+
...prev,
|
|
538
|
+
{
|
|
539
|
+
key: `error-${Date.now()}`,
|
|
540
|
+
content: `${chalk.red('●')} ${chalk.bold(taskName)}\n${chalk.red(`Error: ${errorText}`)}`,
|
|
541
|
+
type: 'assistant',
|
|
542
|
+
},
|
|
543
|
+
]);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
else if (event.type === 'runtime_start') {
|
|
547
|
+
if (shouldShowEvent('runtime_start', activeFilter)) {
|
|
548
|
+
setMessages((prev) => [
|
|
549
|
+
...prev,
|
|
550
|
+
{
|
|
551
|
+
key: `runtime-start-${Date.now()}`,
|
|
552
|
+
content: chalk.dim('[runtime/start]'),
|
|
553
|
+
type: 'assistant',
|
|
554
|
+
},
|
|
555
|
+
]);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
else if (event.type === 'runtime_running') {
|
|
559
|
+
if (shouldShowEvent('runtime_running', activeFilter)) {
|
|
560
|
+
setMessages((prev) => [
|
|
561
|
+
...prev,
|
|
562
|
+
{
|
|
563
|
+
key: `runtime-running-${Date.now()}`,
|
|
564
|
+
content: chalk.dim('[runtime/running]'),
|
|
565
|
+
type: 'assistant',
|
|
566
|
+
},
|
|
567
|
+
]);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
else if (event.type === 'runtime_waiting') {
|
|
571
|
+
if (shouldShowEvent('runtime_waiting', activeFilter)) {
|
|
572
|
+
setMessages((prev) => [
|
|
573
|
+
...prev,
|
|
574
|
+
{
|
|
575
|
+
key: `runtime-waiting-${Date.now()}`,
|
|
576
|
+
content: chalk.dim('[runtime/waiting]'),
|
|
577
|
+
type: 'assistant',
|
|
578
|
+
},
|
|
579
|
+
]);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
else if (event.type === 'trigger_message') {
|
|
583
|
+
if (shouldShowEvent('trigger_message', activeFilter)) {
|
|
584
|
+
const triggerText = typeof event.content === 'object' ? event.content?.data || '' : '';
|
|
585
|
+
setMessages((prev) => [
|
|
586
|
+
...prev,
|
|
587
|
+
{
|
|
588
|
+
key: `trigger-${Date.now()}`,
|
|
589
|
+
content: `${chalk.cyan('[trigger]')} ${triggerText}`,
|
|
590
|
+
type: 'assistant',
|
|
591
|
+
},
|
|
592
|
+
]);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
else if (event.type === 'system_error') {
|
|
596
|
+
if (shouldShowEvent('system_error', activeFilter)) {
|
|
597
|
+
const errText = typeof event.content === 'object' ? event.content?.data || '' : '';
|
|
598
|
+
setMessages((prev) => [
|
|
599
|
+
...prev,
|
|
600
|
+
{
|
|
601
|
+
key: `system-error-${Date.now()}`,
|
|
602
|
+
content: `${chalk.red('[system_error]')} ${errText}`,
|
|
603
|
+
type: 'assistant',
|
|
604
|
+
},
|
|
605
|
+
]);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
else if (event.type === 'llm_start') {
|
|
609
|
+
if (shouldShowEvent('llm_start', activeFilter)) {
|
|
610
|
+
setMessages((prev) => [
|
|
611
|
+
...prev,
|
|
612
|
+
{
|
|
613
|
+
key: `llm-start-${Date.now()}`,
|
|
614
|
+
content: chalk.dim(`[llm_start] provider:${event.provider}`),
|
|
615
|
+
type: 'assistant',
|
|
616
|
+
},
|
|
617
|
+
]);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
else if (event.type === 'llm_done') {
|
|
621
|
+
if (shouldShowEvent('llm_done', activeFilter)) {
|
|
622
|
+
setMessages((prev) => [
|
|
623
|
+
...prev,
|
|
624
|
+
{
|
|
625
|
+
key: `llm-done-${Date.now()}`,
|
|
626
|
+
content: chalk.dim(`[llm_done] HTTP ${event.status_code}`),
|
|
627
|
+
type: 'assistant',
|
|
628
|
+
},
|
|
629
|
+
]);
|
|
630
|
+
}
|
|
540
631
|
}
|
|
541
632
|
else if (event.type === 'agent_notification_progress') {
|
|
542
633
|
// Update status line with progress text (task tracking is done by tasks poll)
|
|
@@ -609,48 +700,63 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
609
700
|
]);
|
|
610
701
|
setCurrentOperation('');
|
|
611
702
|
}
|
|
612
|
-
else if (event.type === 'agent_console'
|
|
613
|
-
// Show console logs when
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
703
|
+
else if (event.type === 'agent_console') {
|
|
704
|
+
// Show console logs when enabled via --events or --debug
|
|
705
|
+
// --debug continues to show console logs for backwards compatibility
|
|
706
|
+
if (shouldShowEvent('agent_console', activeFilter) || isDebugMode()) {
|
|
707
|
+
const content = typeof event.content === 'string' ? event.content : '';
|
|
708
|
+
setMessages((prev) => [
|
|
709
|
+
...prev,
|
|
710
|
+
{
|
|
711
|
+
key: `console-${Date.now()}-${Math.random()}`,
|
|
712
|
+
content: chalk.dim(`[console.${event.level}] ${content}`),
|
|
713
|
+
type: 'assistant',
|
|
714
|
+
},
|
|
715
|
+
]);
|
|
716
|
+
}
|
|
623
717
|
}
|
|
624
|
-
else if (event.type === 'runtime_done'
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
taskInfo &&
|
|
628
|
-
'agent' in taskInfo) {
|
|
629
|
-
// One-shot agents may complete with runtime_done without sending
|
|
630
|
-
// agent_notification_message. Display the output if we haven't
|
|
631
|
-
// already shown a response for this input cycle.
|
|
632
|
-
const contentStr = typeof event.content === 'string'
|
|
633
|
-
? event.content
|
|
634
|
-
: JSON.stringify(event.content);
|
|
635
|
-
if (contentStr && contentStr !== '{}' && contentStr !== 'null') {
|
|
636
|
-
const rendered = fixListItemMarkdown(marked.parse(contentStr));
|
|
637
|
-
const taskName = agentName || 'assistant';
|
|
638
|
-
const messageContent = `${chalk.green('●')} ${chalk.bold(taskName)}\n${rendered.trim()}`;
|
|
718
|
+
else if (event.type === 'runtime_done') {
|
|
719
|
+
if (shouldShowEvent('runtime_done', activeFilter)) {
|
|
720
|
+
// Show runtime_done as a system event when enabled via --events
|
|
639
721
|
setMessages((prev) => [
|
|
640
722
|
...prev,
|
|
641
723
|
{
|
|
642
|
-
key: `
|
|
643
|
-
content:
|
|
724
|
+
key: `runtime-done-${Date.now()}`,
|
|
725
|
+
content: chalk.dim('[runtime/done]'),
|
|
644
726
|
type: 'assistant',
|
|
645
|
-
timestamp: new Date().toLocaleTimeString(),
|
|
646
727
|
},
|
|
647
728
|
]);
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
729
|
+
}
|
|
730
|
+
if (!receivedResponseSinceLastInput.current &&
|
|
731
|
+
event.content !== undefined &&
|
|
732
|
+
taskInfo &&
|
|
733
|
+
'agent' in taskInfo) {
|
|
734
|
+
// One-shot agents may complete with runtime_done without sending
|
|
735
|
+
// agent_notification_message. Display the output if we haven't
|
|
736
|
+
// already shown a response for this input cycle.
|
|
737
|
+
const contentStr = typeof event.content === 'string'
|
|
738
|
+
? event.content
|
|
739
|
+
: JSON.stringify(event.content);
|
|
740
|
+
if (contentStr && contentStr !== '{}' && contentStr !== 'null') {
|
|
741
|
+
const rendered = fixListItemMarkdown(marked.parse(contentStr));
|
|
742
|
+
const taskName = agentName || 'assistant';
|
|
743
|
+
const messageContent = `${chalk.green('●')} ${chalk.bold(taskName)}\n${rendered.trim()}`;
|
|
744
|
+
setMessages((prev) => [
|
|
745
|
+
...prev,
|
|
746
|
+
{
|
|
747
|
+
key: `msg-${Date.now()}-${Math.random()}`,
|
|
748
|
+
content: messageContent,
|
|
749
|
+
type: 'assistant',
|
|
750
|
+
timestamp: new Date().toLocaleTimeString(),
|
|
751
|
+
},
|
|
752
|
+
]);
|
|
753
|
+
if (!firstMessageNotified.current && onFirstMessage) {
|
|
754
|
+
firstMessageNotified.current = true;
|
|
755
|
+
onFirstMessage();
|
|
756
|
+
}
|
|
757
|
+
receivedResponseSinceLastInput.current = true;
|
|
758
|
+
setCurrentOperation('');
|
|
651
759
|
}
|
|
652
|
-
receivedResponseSinceLastInput.current = true;
|
|
653
|
-
setCurrentOperation('');
|
|
654
760
|
}
|
|
655
761
|
}
|
|
656
762
|
else if (event.type === 'interrupted') {
|
|
@@ -684,7 +790,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
|
|
|
684
790
|
isPolling.current = false;
|
|
685
791
|
}
|
|
686
792
|
};
|
|
687
|
-
pollInterval.current = setInterval(poll,
|
|
793
|
+
pollInterval.current = setInterval(poll, 2000);
|
|
688
794
|
poll();
|
|
689
795
|
return () => {
|
|
690
796
|
if (pollInterval.current) {
|
|
@@ -887,29 +993,7 @@ export async function createSession(client, workspaceId, initialPrompt, versionI
|
|
|
887
993
|
}
|
|
888
994
|
}
|
|
889
995
|
if (!workspaceId) {
|
|
890
|
-
|
|
891
|
-
progress('Fetching workspaces');
|
|
892
|
-
const response = await client.get('/me/workspaces');
|
|
893
|
-
if (!response) {
|
|
894
|
-
throw new Error('Failed to fetch workspaces');
|
|
895
|
-
}
|
|
896
|
-
// Handle both array and paginated object responses
|
|
897
|
-
const workspaces = (Array.isArray(response)
|
|
898
|
-
? response
|
|
899
|
-
: response?.items || []);
|
|
900
|
-
if (workspaces.length === 0) {
|
|
901
|
-
// Get current user to use as workspace owner
|
|
902
|
-
progress('Creating workspace');
|
|
903
|
-
const me = (await client.get('/me'));
|
|
904
|
-
const newWorkspace = (await client.post('/workspaces', {
|
|
905
|
-
name: 'My Workspace',
|
|
906
|
-
owner_id: me.id,
|
|
907
|
-
}));
|
|
908
|
-
workspaceId = newWorkspace.id;
|
|
909
|
-
}
|
|
910
|
-
else {
|
|
911
|
-
workspaceId = workspaces[0].id;
|
|
912
|
-
}
|
|
996
|
+
throw new Error('No workspace configured. Run: guild workspace select, or pass --workspace <id>');
|
|
913
997
|
}
|
|
914
998
|
progress('Creating session');
|
|
915
999
|
const sessionData = {
|
|
@@ -950,9 +1034,13 @@ export function createChatCommand() {
|
|
|
950
1034
|
.option('--workspace <identifier>', 'Workspace ID or full name (e.g., owner/workspace-name)')
|
|
951
1035
|
.option('--no-splash', 'Skip the splash screen animation')
|
|
952
1036
|
.option('--resume <session-id>', 'Resume an existing session')
|
|
1037
|
+
.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)')
|
|
953
1038
|
.addHelpText('after', '\nTo chat with a local agent under development: guild agent chat')
|
|
954
1039
|
.action(async (promptArgs, options) => {
|
|
955
1040
|
const initialPrompt = promptArgs.length > 0 ? promptArgs.join(' ') : 'Hello';
|
|
1041
|
+
const eventFilter = options.events
|
|
1042
|
+
? parseEventFilter(options.events)
|
|
1043
|
+
: DEFAULT_EVENT_TYPES;
|
|
956
1044
|
if (options.once) {
|
|
957
1045
|
// --once mode: use old spinner-based approach
|
|
958
1046
|
const spinner = createSpinner('Connecting to Guild servers...');
|
|
@@ -972,7 +1060,7 @@ export function createChatCommand() {
|
|
|
972
1060
|
// Timeout after 5 minutes of INACTIVITY (no new messages)
|
|
973
1061
|
// Agent initialization can take 1-2 minutes with no events
|
|
974
1062
|
const inactivityTimeoutMs = 300000; // 5 minutes
|
|
975
|
-
const pollIntervalMs =
|
|
1063
|
+
const pollIntervalMs = 2000;
|
|
976
1064
|
const maxInactivityAttempts = inactivityTimeoutMs / pollIntervalMs;
|
|
977
1065
|
let lastSeenEventId;
|
|
978
1066
|
const allEvents = [];
|
|
@@ -1075,7 +1163,7 @@ export function createChatCommand() {
|
|
|
1075
1163
|
if (shouldShowSplash) {
|
|
1076
1164
|
suppressScrollbackClear();
|
|
1077
1165
|
}
|
|
1078
|
-
const { waitUntilExit } = render(React.createElement(ChatApp, { initialPrompt: initialPrompt, version: packageJson.version, workspaceId: options.workspace, versionId: options.agent, showSplash: shouldShowSplash, resumeSession: resumeSession, resumeEvents: resumeSessionEvents, resumeCommand: resumeCommand }), {
|
|
1166
|
+
const { waitUntilExit } = render(React.createElement(ChatApp, { initialPrompt: initialPrompt, version: packageJson.version, workspaceId: options.workspace, versionId: options.agent, showSplash: shouldShowSplash, resumeSession: resumeSession, resumeEvents: resumeSessionEvents, resumeCommand: resumeCommand, eventFilter: eventFilter }), {
|
|
1079
1167
|
exitOnCtrlC: false, // We handle Ctrl-C in useInput (raw mode)
|
|
1080
1168
|
});
|
|
1081
1169
|
await waitUntilExit();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright 2026 Guild.ai
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
5
|
+
import { getAuthToken } from '../../lib/auth.js';
|
|
6
|
+
import { handleAxiosError } from '../../lib/errors.js';
|
|
7
|
+
import { createOutputWriter } from '../../lib/output.js';
|
|
8
|
+
export function createSessionInterruptCommand() {
|
|
9
|
+
const cmd = new Command('interrupt');
|
|
10
|
+
cmd
|
|
11
|
+
.description('Interrupt a running session')
|
|
12
|
+
.argument('<session-id>', 'Session ID')
|
|
13
|
+
.action(async (sessionId) => {
|
|
14
|
+
const output = createOutputWriter();
|
|
15
|
+
try {
|
|
16
|
+
const token = await getAuthToken();
|
|
17
|
+
if (!token) {
|
|
18
|
+
output.error('Not authenticated. Run: guild auth login');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const client = new GuildAPIClient();
|
|
22
|
+
const response = await client.post(`/sessions/${sessionId}/interrupt`, {});
|
|
23
|
+
output.data(response);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const formattedError = handleAxiosError(error);
|
|
27
|
+
output.error(`Failed to interrupt session: ${formattedError.details}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return cmd;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=interrupt.js.map
|
package/dist/commands/setup.js
CHANGED
|
@@ -11,7 +11,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
11
11
|
const __dirname = path.dirname(__filename);
|
|
12
12
|
const packageRoot = path.resolve(__dirname, '..', '..');
|
|
13
13
|
const docsDir = path.join(packageRoot, 'docs');
|
|
14
|
-
const
|
|
14
|
+
const CLAUDE_SKILL_FILES = [
|
|
15
15
|
{
|
|
16
16
|
src: path.join(docsDir, 'skills', 'agent-dev.md'),
|
|
17
17
|
dest: path.join('.claude', 'skills', 'agent-dev', 'skill.md'),
|
|
@@ -22,6 +22,18 @@ const SKILL_FILES = [
|
|
|
22
22
|
dest: path.join('.claude', 'skills', 'guild-cli-workflow', 'skill.md'),
|
|
23
23
|
label: '.claude/skills/guild-cli-workflow/skill.md',
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
src: path.join(docsDir, 'skills', 'integrations.md'),
|
|
27
|
+
dest: path.join('.claude', 'skills', 'integrations', 'skill.md'),
|
|
28
|
+
label: '.claude/skills/integrations/skill.md',
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
const CODEX_SKILL_FILES = [
|
|
32
|
+
{
|
|
33
|
+
src: path.join(docsDir, 'skills', 'codex-agent-dev.md'),
|
|
34
|
+
dest: path.join('.agents', 'skills', 'guild-agent-dev', 'SKILL.md'),
|
|
35
|
+
label: '.agents/skills/guild-agent-dev/SKILL.md',
|
|
36
|
+
},
|
|
25
37
|
];
|
|
26
38
|
const CLAUDE_MD_TEMPLATE = `# CLAUDE.md
|
|
27
39
|
|
|
@@ -38,6 +50,22 @@ guild agent save --message "Initial version" --wait --publish
|
|
|
38
50
|
|
|
39
51
|
See \`.claude/skills/agent-dev/skill.md\` for SDK reference, patterns, and anti-hallucination guide.
|
|
40
52
|
`;
|
|
53
|
+
const AGENTS_MD_TEMPLATE = `# AGENTS.md
|
|
54
|
+
|
|
55
|
+
## Guild Agent Development
|
|
56
|
+
|
|
57
|
+
This project uses Guild for agent development. Codex instructions are installed in \`.agents/skills/guild-agent-dev/SKILL.md\`.
|
|
58
|
+
|
|
59
|
+
### Quick Start
|
|
60
|
+
|
|
61
|
+
\`\`\`bash
|
|
62
|
+
guild agent init --name my-agent --template LLM
|
|
63
|
+
guild agent test --ephemeral
|
|
64
|
+
guild agent save -A --message "Initial version"
|
|
65
|
+
\`\`\`
|
|
66
|
+
|
|
67
|
+
Use \`guild doctor\` to check authentication, server connectivity, workspace selection, and git setup.
|
|
68
|
+
`;
|
|
41
69
|
async function fileExists(filePath) {
|
|
42
70
|
try {
|
|
43
71
|
await fs.access(filePath);
|
|
@@ -82,21 +110,29 @@ async function setupMcp(options) {
|
|
|
82
110
|
}
|
|
83
111
|
async function setup(options) {
|
|
84
112
|
const output = createOutputWriter();
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
113
|
+
if (options.agentsMd && !options.codex) {
|
|
114
|
+
output.error('--agents-md requires --codex', 'Create Codex setup files with:\n guild setup --codex --agents-md');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
if (options.claudeMd && options.codex) {
|
|
118
|
+
output.error('--claude-md cannot be used with --codex', 'Create Claude setup with:\n guild setup --claude-md\n\nCreate Codex setup with:\n guild setup --codex --agents-md');
|
|
89
119
|
process.exit(1);
|
|
90
120
|
}
|
|
121
|
+
const skillFiles = options.codex ? CODEX_SKILL_FILES : CLAUDE_SKILL_FILES;
|
|
122
|
+
// Verify source docs exist
|
|
123
|
+
for (const file of skillFiles) {
|
|
124
|
+
if (!(await fileExists(file.src))) {
|
|
125
|
+
output.error('Could not find Guild CLI docs. Reinstall the CLI: npm install -g @guildai/cli');
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
91
129
|
output.progress('Setting up Guild CLI skills...');
|
|
92
130
|
output.progress('');
|
|
93
|
-
// Ensure .claude/skills/ directory exists
|
|
94
|
-
const skillsDir = path.join(process.cwd(), '.claude', 'skills');
|
|
95
|
-
await fs.mkdir(skillsDir, { recursive: true });
|
|
96
131
|
let filesCreated = 0;
|
|
97
132
|
let filesSkipped = 0;
|
|
133
|
+
let codexProjectFilesChanged = false;
|
|
98
134
|
// Copy skill files
|
|
99
|
-
for (const file of
|
|
135
|
+
for (const file of skillFiles) {
|
|
100
136
|
const destPath = path.join(process.cwd(), file.dest);
|
|
101
137
|
const exists = await fileExists(destPath);
|
|
102
138
|
if (exists && !options.force) {
|
|
@@ -113,6 +149,9 @@ async function setup(options) {
|
|
|
113
149
|
output.success(`Created ${file.label}`);
|
|
114
150
|
}
|
|
115
151
|
filesCreated++;
|
|
152
|
+
if (options.codex) {
|
|
153
|
+
codexProjectFilesChanged = true;
|
|
154
|
+
}
|
|
116
155
|
}
|
|
117
156
|
}
|
|
118
157
|
// Handle --mcp flag
|
|
@@ -139,6 +178,21 @@ async function setup(options) {
|
|
|
139
178
|
filesCreated++;
|
|
140
179
|
}
|
|
141
180
|
}
|
|
181
|
+
// Handle AGENTS.md template for Codex setup
|
|
182
|
+
if (options.agentsMd) {
|
|
183
|
+
const agentsMdPath = path.join(process.cwd(), 'AGENTS.md');
|
|
184
|
+
const exists = await fileExists(agentsMdPath);
|
|
185
|
+
if (exists) {
|
|
186
|
+
output.progress('AGENTS.md already exists (not overwriting)');
|
|
187
|
+
filesSkipped++;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
await fs.writeFile(agentsMdPath, AGENTS_MD_TEMPLATE, 'utf-8');
|
|
191
|
+
output.success('Created AGENTS.md');
|
|
192
|
+
filesCreated++;
|
|
193
|
+
codexProjectFilesChanged = true;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
142
196
|
// Summary
|
|
143
197
|
output.progress('');
|
|
144
198
|
if (filesCreated > 0 && filesSkipped === 0) {
|
|
@@ -155,13 +209,18 @@ async function setup(options) {
|
|
|
155
209
|
else {
|
|
156
210
|
output.success('Guild CLI skills installed.');
|
|
157
211
|
}
|
|
212
|
+
if (codexProjectFilesChanged) {
|
|
213
|
+
output.progress('Restart Codex to pick up the new project instructions.');
|
|
214
|
+
}
|
|
158
215
|
}
|
|
159
216
|
export function createSetupCommand() {
|
|
160
217
|
const cmd = new Command('setup');
|
|
161
218
|
cmd
|
|
162
|
-
.description('Set up Guild CLI skills for coding assistants (Claude Code, etc.)')
|
|
163
|
-
.option('--force', 'Overwrite existing skill files', false)
|
|
219
|
+
.description('Set up Guild CLI skills for coding assistants (Claude Code, Codex, etc.)')
|
|
220
|
+
.option('--force', 'Overwrite existing skill files and Guild MCP config', false)
|
|
221
|
+
.option('--codex', 'Install Codex skill files instead of Claude Code skills', false)
|
|
164
222
|
.option('--claude-md', 'Also create a CLAUDE.md template in the project root', false)
|
|
223
|
+
.option('--agents-md', 'With --codex, also create an AGENTS.md template in the project root', false)
|
|
165
224
|
.option('--no-mcp', 'Skip MCP server configuration')
|
|
166
225
|
.action(async (options) => {
|
|
167
226
|
await setup(options);
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ import { createSessionEventsCommand } from './commands/session/events.js';
|
|
|
59
59
|
import { createSessionTasksCommand } from './commands/session/tasks.js';
|
|
60
60
|
import { createSessionCreateCommand } from './commands/session/create.js';
|
|
61
61
|
import { createSessionSendCommand } from './commands/session/send.js';
|
|
62
|
+
import { createSessionInterruptCommand } from './commands/session/interrupt.js';
|
|
62
63
|
import { createJobGetCommand } from './commands/job/get.js';
|
|
63
64
|
import { createJobStepGetCommand } from './commands/job/step-get.js';
|
|
64
65
|
import { createConfigListCommand } from './commands/config/list.js';
|
|
@@ -276,6 +277,7 @@ sessionCmd.addCommand(createSessionEventsCommand());
|
|
|
276
277
|
sessionCmd.addCommand(createSessionTasksCommand());
|
|
277
278
|
sessionCmd.addCommand(createSessionCreateCommand());
|
|
278
279
|
sessionCmd.addCommand(createSessionSendCommand());
|
|
280
|
+
sessionCmd.addCommand(createSessionInterruptCommand());
|
|
279
281
|
// Job command group
|
|
280
282
|
const jobCmd = program.command('job').description('Job management');
|
|
281
283
|
jobCmd.addCommand(createJobGetCommand());
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event type filtering for the CLI `--events` flag.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the web UI's "Filter by type" modal, which groups event types into
|
|
5
|
+
* two categories: user-facing events (on by default) and system/debug events
|
|
6
|
+
* (off by default).
|
|
7
|
+
*
|
|
8
|
+
* The canonical event type list is generated from the backend EventType enum
|
|
9
|
+
* (see generated-types.ts). The user/system grouping is a UI concern defined
|
|
10
|
+
* here and in www/src/components/EventTypeFilters/types.ts.
|
|
11
|
+
*/
|
|
12
|
+
import type { EventType } from './generated-types.js';
|
|
13
|
+
/**
|
|
14
|
+
* User-facing event types — shown by default (mirrors web UI defaults).
|
|
15
|
+
*/
|
|
16
|
+
export declare const USER_EVENT_TYPES: readonly EventType[];
|
|
17
|
+
/**
|
|
18
|
+
* System / debug event types — hidden by default (mirrors web UI defaults).
|
|
19
|
+
*/
|
|
20
|
+
export declare const SYSTEM_EVENT_TYPES: readonly EventType[];
|
|
21
|
+
/**
|
|
22
|
+
* Default active filter: all user-facing types, no system types.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DEFAULT_EVENT_TYPES: Set<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Parse the value of the `--events` flag into a Set of event type names.
|
|
27
|
+
*
|
|
28
|
+
* Whatever you pass replaces the defaults entirely:
|
|
29
|
+
* - `none` → empty set (no event types shown)
|
|
30
|
+
* - `user` → all USER_EVENT_TYPES (same as default)
|
|
31
|
+
* - `system` → only SYSTEM_EVENT_TYPES
|
|
32
|
+
* - `all` → both USER_EVENT_TYPES + SYSTEM_EVENT_TYPES
|
|
33
|
+
*
|
|
34
|
+
* Comma-separated for fine-grained control:
|
|
35
|
+
* - `agent_console,llm_start` → only those two types
|
|
36
|
+
* - `user,system` → same as `all`
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseEventFilter(raw: string): Set<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Check whether an event should be shown given the active filter.
|
|
41
|
+
*
|
|
42
|
+
* Returns `true` when the event type is in the filter set.
|
|
43
|
+
*
|
|
44
|
+
* Note: certain event types (e.g. `agent_notification_progress`,
|
|
45
|
+
* `agent_notification_message`) drive core UI state (spinner, chat history)
|
|
46
|
+
* and are always processed regardless of the filter; only their *display* is
|
|
47
|
+
* gated here for new/optional event types.
|
|
48
|
+
*/
|
|
49
|
+
export declare function shouldShowEvent(type: string, filter: Set<string>): boolean;
|
|
50
|
+
//# sourceMappingURL=event-filter.d.ts.map
|