@guildai/cli 0.6.2 → 0.7.1
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 +41 -99
- package/dist/commands/agent/clone.js +1 -1
- package/dist/commands/agent/code.js +1 -1
- package/dist/commands/agent/fork.js +2 -2
- package/dist/commands/agent/get.js +1 -1
- package/dist/commands/agent/grep.js +2 -2
- package/dist/commands/agent/init.js +10 -3
- package/dist/commands/agent/list.js +9 -1
- package/dist/commands/agent/publish.js +1 -1
- package/dist/commands/agent/revalidate.js +1 -1
- package/dist/commands/agent/save.js +23 -2
- package/dist/commands/agent/test.js +70 -130
- package/dist/commands/agent/unpublish.js +1 -1
- package/dist/commands/agent/update.js +1 -1
- package/dist/commands/agent/versions.js +1 -1
- package/dist/commands/agent/workspaces.js +1 -1
- package/dist/commands/chat.d.ts +2 -1
- package/dist/commands/chat.js +189 -88
- package/dist/commands/config/list.js +2 -2
- package/dist/commands/integration/operation/create.js +2 -2
- package/dist/commands/integration/operation/list.js +2 -2
- package/dist/commands/integration/update.js +1 -1
- package/dist/commands/integration/version/get.js +2 -2
- package/dist/commands/integration/version/publish.js +2 -2
- package/dist/commands/integration/version/test.js +2 -2
- package/dist/commands/session/events.js +7 -3
- 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/commands/workspace/get.js +1 -1
- package/dist/commands/workspace/list.js +28 -6
- package/dist/commands/workspace/select.js +40 -9
- package/dist/components/TaskView.js +2 -2
- package/dist/index.js +2 -0
- package/dist/lib/agent-helpers.d.ts +59 -2
- package/dist/lib/agent-helpers.js +153 -8
- package/dist/lib/alternate-screen.js +2 -0
- package/dist/lib/api-client.js +2 -1
- package/dist/lib/config.d.ts +3 -0
- package/dist/lib/config.js +33 -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 +27 -2
- package/dist/lib/session-events.js +5 -3
- package/dist/lib/session-polling.d.ts +8 -0
- package/dist/lib/session-polling.js +49 -0
- package/dist/lib/spinners.js +4 -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
|
@@ -13,13 +13,13 @@ import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
|
|
|
13
13
|
import { format } from '../../lib/progress.js';
|
|
14
14
|
import { showBetaGuidance } from '../../lib/auth.js';
|
|
15
15
|
import * as readline from 'readline';
|
|
16
|
+
import { parseEventFilter } from '../../lib/event-filter.js';
|
|
16
17
|
import { isQuietMode, getOutputMode } from '../../lib/output-mode.js';
|
|
17
|
-
import { pollForResponse } from '../../lib/session-polling.js';
|
|
18
|
+
import { pollForResponse, pollForResponseWithEvents, } from '../../lib/session-polling.js';
|
|
18
19
|
import { readStdinAsJSON, ensureInteractiveStdin } from '../../lib/stdin.js';
|
|
19
20
|
import { loadLocalConfig, getWorkspaceId } from '../../lib/guild-config.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { readAgentFiles } from '../../lib/agent-helpers.js';
|
|
21
|
+
import { GitError, formatGitError } from '../../lib/git.js';
|
|
22
|
+
import { readAgentFiles, buildEphemeralVersion, BuildTimeoutError, BuildFailedError, } from '../../lib/agent-helpers.js';
|
|
23
23
|
import { fetchSession, fetchSessionEvents } from '../../lib/session-resume.js';
|
|
24
24
|
import { ChatApp, ensureAuthenticated } from '../chat.js';
|
|
25
25
|
import { suppressScrollbackClear } from '../../lib/alternate-screen.js';
|
|
@@ -33,11 +33,17 @@ export function createAgentTestCommand() {
|
|
|
33
33
|
.description('Test agent in interactive REPL session')
|
|
34
34
|
.option('--workspace <identifier>', 'Workspace ID or full name (e.g., owner/workspace-name)')
|
|
35
35
|
.option('--mode <format>', 'Input mode: json (one-shot) or jsonl (line-by-line)')
|
|
36
|
-
.option('--
|
|
36
|
+
.option('--agent-version <id>', 'Test a specific version (UUID or version number)')
|
|
37
37
|
.option('--resume <session-id>', 'Resume an existing test session')
|
|
38
38
|
.option('--open', 'Open session in web dashboard')
|
|
39
|
+
.option('--events <types>', 'Event types to stream (default: user). Shorthands: none, user, system, all, or comma-separated type names')
|
|
40
|
+
.option('--no-cache', 'Skip ephemeral build cache (force a fresh build)')
|
|
39
41
|
.action(async (options) => {
|
|
40
42
|
const cwd = process.cwd();
|
|
43
|
+
// Parse --events filter once, before any branching
|
|
44
|
+
const eventFilter = options.events
|
|
45
|
+
? parseEventFilter(options.events)
|
|
46
|
+
: undefined;
|
|
41
47
|
try {
|
|
42
48
|
// Handle --resume: skip build, fetch existing session, hand off to ChatApp
|
|
43
49
|
if (options.resume) {
|
|
@@ -57,6 +63,7 @@ export function createAgentTestCommand() {
|
|
|
57
63
|
resumeSession,
|
|
58
64
|
resumeEvents,
|
|
59
65
|
resumeCommand,
|
|
66
|
+
eventFilter,
|
|
60
67
|
}), { exitOnCtrlC: false });
|
|
61
68
|
await waitUntilExit();
|
|
62
69
|
return;
|
|
@@ -75,49 +82,6 @@ export function createAgentTestCommand() {
|
|
|
75
82
|
console.error(' guild agent clone <agent-id>');
|
|
76
83
|
process.exit(1);
|
|
77
84
|
}
|
|
78
|
-
// For ephemeral mode, we skip git checks and read files directly
|
|
79
|
-
// For committed mode, we require a clean working tree
|
|
80
|
-
let commitSha = null;
|
|
81
|
-
let agentFiles = null;
|
|
82
|
-
if (options.ephemeral) {
|
|
83
|
-
// Ephemeral mode: read files from disk
|
|
84
|
-
try {
|
|
85
|
-
agentFiles = await readAgentFiles(cwd);
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
const err = error;
|
|
89
|
-
console.error('Error: Could not read agent files');
|
|
90
|
-
console.error('');
|
|
91
|
-
console.error(err.message);
|
|
92
|
-
console.error('');
|
|
93
|
-
console.error('Ensure you are in an agent directory with:');
|
|
94
|
-
console.error(' - agent.ts (required)');
|
|
95
|
-
console.error(' - package.json (required)');
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
// Committed mode: require clean working tree
|
|
101
|
-
const { stdout: statusOutput } = await runGit(['status', '--porcelain'], {
|
|
102
|
-
cwd,
|
|
103
|
-
});
|
|
104
|
-
if (statusOutput.trim().length > 0) {
|
|
105
|
-
console.error('Error: Working tree has unsaved changes');
|
|
106
|
-
console.error('');
|
|
107
|
-
console.error('Options:');
|
|
108
|
-
console.error(' 1. Save your changes first:');
|
|
109
|
-
console.error(' guild agent save --message "your changes"');
|
|
110
|
-
console.error('');
|
|
111
|
-
console.error(' 2. Test unsaved changes:');
|
|
112
|
-
console.error(' guild agent test --ephemeral');
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
// Get commit SHA
|
|
116
|
-
const { stdout: shaOutput } = await runGit(['rev-parse', 'HEAD'], {
|
|
117
|
-
cwd,
|
|
118
|
-
});
|
|
119
|
-
commitSha = shaOutput.trim();
|
|
120
|
-
}
|
|
121
85
|
// If using JSON input, read and validate it early (before auth/session creation)
|
|
122
86
|
// This provides better UX - fail fast on bad JSON without needing auth
|
|
123
87
|
let inputData;
|
|
@@ -156,35 +120,60 @@ export function createAgentTestCommand() {
|
|
|
156
120
|
}
|
|
157
121
|
// Validate auth before any API calls or UI rendering
|
|
158
122
|
await ensureAuthenticated();
|
|
159
|
-
//
|
|
123
|
+
// Resolve version for testing
|
|
160
124
|
const client = new GuildAPIClient();
|
|
161
125
|
let version;
|
|
126
|
+
let ephemeralCached = false;
|
|
162
127
|
try {
|
|
163
|
-
if (options.
|
|
164
|
-
//
|
|
165
|
-
version = (await client.post(`/agents/${guildConfig.agent_id}/versions`, {
|
|
166
|
-
files: agentFiles,
|
|
167
|
-
summary: '[Test] Ephemeral development version',
|
|
168
|
-
version_type: 'EPHEMERAL',
|
|
169
|
-
}));
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
// Committed mode: check if a version for this commit already exists
|
|
128
|
+
if (options.agentVersion) {
|
|
129
|
+
// Explicit version: look it up by ID or version number
|
|
173
130
|
const existingVersions = (await client.get(`/agents/${guildConfig.agent_id}/versions`));
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
version_type: 'COMMITTED',
|
|
183
|
-
}));
|
|
131
|
+
const match = existingVersions.items.find((v) => v.id === options.agentVersion ||
|
|
132
|
+
v.version_number === options.agentVersion);
|
|
133
|
+
if (!match) {
|
|
134
|
+
console.error(`Error: Version not found: ${options.agentVersion}`);
|
|
135
|
+
console.error('');
|
|
136
|
+
console.error('List available versions:');
|
|
137
|
+
console.error(` guild agent versions ${guildConfig.agent_id}`);
|
|
138
|
+
process.exit(1);
|
|
184
139
|
}
|
|
140
|
+
version = match;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// Default: build ephemeral version from working directory,
|
|
144
|
+
// reusing the last build if files haven't changed.
|
|
145
|
+
const agentFiles = await readAgentFiles(cwd);
|
|
146
|
+
const noCache = options.cache === false;
|
|
147
|
+
const result = await buildEphemeralVersion(client, guildConfig.agent_id, agentFiles, cwd, '[Test] Ephemeral development version', { noCache });
|
|
148
|
+
version = result.version;
|
|
149
|
+
ephemeralCached = result.cached;
|
|
185
150
|
}
|
|
186
151
|
}
|
|
187
152
|
catch (error) {
|
|
153
|
+
if (error instanceof BuildTimeoutError) {
|
|
154
|
+
console.error('Error: Build did not complete');
|
|
155
|
+
console.error('');
|
|
156
|
+
console.error(error.message);
|
|
157
|
+
console.error('');
|
|
158
|
+
console.error('Check build status:');
|
|
159
|
+
console.error(' guild agent versions');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
if (error instanceof BuildFailedError) {
|
|
163
|
+
console.error(`Error: ${error.message}`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
if (error instanceof Error &&
|
|
167
|
+
error.message.startsWith('Missing required')) {
|
|
168
|
+
console.error('Error: Could not read agent files');
|
|
169
|
+
console.error('');
|
|
170
|
+
console.error(error.message);
|
|
171
|
+
console.error('');
|
|
172
|
+
console.error('Ensure you are in an agent directory with:');
|
|
173
|
+
console.error(' - agent.ts (required)');
|
|
174
|
+
console.error(' - package.json (required)');
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
188
177
|
const formattedError = handleAxiosError(error);
|
|
189
178
|
if (formattedError.code === ErrorCodes.NOT_FOUND) {
|
|
190
179
|
console.error(`Error: Agent not found: ${guildConfig.agent_id}`);
|
|
@@ -200,61 +189,6 @@ export function createAgentTestCommand() {
|
|
|
200
189
|
}
|
|
201
190
|
throw error;
|
|
202
191
|
}
|
|
203
|
-
// Wait for validation to complete
|
|
204
|
-
const pollResult = await pollUntilComplete({
|
|
205
|
-
resourceId: version.id,
|
|
206
|
-
endpoint: `/versions/${version.id}`,
|
|
207
|
-
isComplete: (response) => response.validation_status !== 'PENDING' &&
|
|
208
|
-
response.validation_status !== 'RUNNING',
|
|
209
|
-
message: 'Building...',
|
|
210
|
-
successMessage: 'Build finished',
|
|
211
|
-
timeoutMessage: 'Build timed out',
|
|
212
|
-
maxAttempts: 120,
|
|
213
|
-
delayMs: 1000,
|
|
214
|
-
});
|
|
215
|
-
if (!pollResult.success || !pollResult.response) {
|
|
216
|
-
console.error('Error: Build did not complete');
|
|
217
|
-
console.error('');
|
|
218
|
-
console.error('The agent version build timed out or failed to report status.');
|
|
219
|
-
console.error('');
|
|
220
|
-
console.error('Check build status:');
|
|
221
|
-
console.error(` guild agent versions ${guildConfig.agent_id}`);
|
|
222
|
-
console.error('');
|
|
223
|
-
console.error('Retry the test:');
|
|
224
|
-
console.error(' guild agent test');
|
|
225
|
-
process.exit(1);
|
|
226
|
-
}
|
|
227
|
-
version = pollResult.response;
|
|
228
|
-
if (version.validation_status === 'FAILED') {
|
|
229
|
-
console.error('Error: Build failed');
|
|
230
|
-
console.error('');
|
|
231
|
-
// Fetch validation steps to show the actual error
|
|
232
|
-
try {
|
|
233
|
-
const stepsResponse = await client.get(`/versions/${version.id}/validation/steps`);
|
|
234
|
-
const failedSteps = stepsResponse.steps.filter((step) => step.status === 'FAILED');
|
|
235
|
-
if (failedSteps.length > 0) {
|
|
236
|
-
for (const step of failedSteps) {
|
|
237
|
-
console.error(`Step "${step.name}" failed:`);
|
|
238
|
-
if (step.content) {
|
|
239
|
-
console.error(step.content);
|
|
240
|
-
}
|
|
241
|
-
console.error('');
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
console.error('No failed steps found. Check validation logs for details.');
|
|
246
|
-
console.error('');
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
catch {
|
|
250
|
-
// If we can't fetch steps, just show generic message
|
|
251
|
-
console.error('Could not fetch validation details.');
|
|
252
|
-
console.error('');
|
|
253
|
-
}
|
|
254
|
-
console.error('Fix the issues and retry:');
|
|
255
|
-
console.error(' guild agent test');
|
|
256
|
-
process.exit(1);
|
|
257
|
-
}
|
|
258
192
|
// Create test session
|
|
259
193
|
let session;
|
|
260
194
|
try {
|
|
@@ -280,9 +214,11 @@ export function createAgentTestCommand() {
|
|
|
280
214
|
const quiet = isQuietMode();
|
|
281
215
|
if (!quiet) {
|
|
282
216
|
console.log(`✓ Agent: ${guildConfig.name} (${guildConfig.agent_id})`);
|
|
283
|
-
const versionDisplay = options.
|
|
284
|
-
?
|
|
285
|
-
:
|
|
217
|
+
const versionDisplay = options.agentVersion
|
|
218
|
+
? options.agentVersion
|
|
219
|
+
: ephemeralCached
|
|
220
|
+
? 'ephemeral (cached, no changes)'
|
|
221
|
+
: 'ephemeral (working directory)';
|
|
286
222
|
console.log(`✓ Version: ${versionDisplay}`);
|
|
287
223
|
console.log(`✓ Workspace: ${workspaceId}`);
|
|
288
224
|
const sessionLink = session.session_url
|
|
@@ -305,7 +241,9 @@ export function createAgentTestCommand() {
|
|
|
305
241
|
});
|
|
306
242
|
// Poll for response (starting from beginning)
|
|
307
243
|
// 3 minutes - allow time for agents that use LLM calls for input parsing
|
|
308
|
-
const { response } =
|
|
244
|
+
const { response } = eventFilter
|
|
245
|
+
? await pollForResponseWithEvents(client, session.id, eventFilter, undefined, 180000)
|
|
246
|
+
: await pollForResponse(client, session.id, undefined, 180000);
|
|
309
247
|
if (!response) {
|
|
310
248
|
console.error('Error: No response received from agent within timeout');
|
|
311
249
|
console.error('');
|
|
@@ -381,7 +319,9 @@ export function createAgentTestCommand() {
|
|
|
381
319
|
content: jsonInput,
|
|
382
320
|
});
|
|
383
321
|
// Wait for response (looking for events after last seen)
|
|
384
|
-
const result =
|
|
322
|
+
const result = eventFilter
|
|
323
|
+
? await pollForResponseWithEvents(client, session.id, eventFilter, lastEventId, 180000)
|
|
324
|
+
: await pollForResponse(client, session.id, lastEventId, 180000);
|
|
385
325
|
lastEventId = result.lastEventId;
|
|
386
326
|
if (!result.response) {
|
|
387
327
|
console.error(`Timeout: No response for line ${lineNumber}`);
|
|
@@ -430,6 +370,7 @@ export function createAgentTestCommand() {
|
|
|
430
370
|
resumeSession: session,
|
|
431
371
|
resumeEvents: [],
|
|
432
372
|
resumeCommand,
|
|
373
|
+
eventFilter,
|
|
433
374
|
}), { exitOnCtrlC: false });
|
|
434
375
|
await waitUntilExit();
|
|
435
376
|
}
|
|
@@ -452,7 +393,6 @@ export function createAgentTestCommand() {
|
|
|
452
393
|
console.error('Failed to start test session. Troubleshooting:');
|
|
453
394
|
console.error(' - Verify the agent exists: guild agent get');
|
|
454
395
|
console.error(' - Check your workspace: guild workspace list');
|
|
455
|
-
console.error(' - Test unsaved changes: guild agent test --ephemeral');
|
|
456
396
|
if (formattedError.code) {
|
|
457
397
|
console.error(` - Error code: ${formattedError.code}`);
|
|
458
398
|
}
|
|
@@ -9,7 +9,7 @@ export function createAgentUnpublishCommand() {
|
|
|
9
9
|
const cmd = new Command('unpublish');
|
|
10
10
|
cmd
|
|
11
11
|
.description('Unpublish the latest published version of an agent')
|
|
12
|
-
.argument('[identifier]', 'Agent ID or full name (e.g., owner
|
|
12
|
+
.argument('[identifier]', 'Agent ID or full name (e.g., owner~agent-name)')
|
|
13
13
|
.action(async (agentIdArg) => {
|
|
14
14
|
const output = createOutputWriter();
|
|
15
15
|
try {
|
|
@@ -26,7 +26,7 @@ export function createAgentUpdateCommand() {
|
|
|
26
26
|
const cmd = new Command('update');
|
|
27
27
|
cmd
|
|
28
28
|
.description('Update agent properties (visibility)')
|
|
29
|
-
.argument('[identifier]', 'Agent ID or full name (e.g., owner
|
|
29
|
+
.argument('[identifier]', 'Agent ID or full name (e.g., owner~agent-name)')
|
|
30
30
|
.option('--public', 'Make the agent public (visible to everyone)')
|
|
31
31
|
.option('--private', 'Make the agent private (only visible to owner)')
|
|
32
32
|
.option('--yes', 'Skip confirmation prompt for visibility changes')
|
|
@@ -11,7 +11,7 @@ export function createAgentVersionsCommand() {
|
|
|
11
11
|
const cmd = new Command('versions');
|
|
12
12
|
cmd
|
|
13
13
|
.description('List all versions of an agent')
|
|
14
|
-
.argument('[identifier]', 'Agent ID or full name (e.g., owner
|
|
14
|
+
.argument('[identifier]', 'Agent ID or full name (e.g., owner~agent-name)')
|
|
15
15
|
.option('--limit <number>', 'Maximum number of versions to return', '20')
|
|
16
16
|
.option('--offset <number>', 'Number of versions to skip', '0')
|
|
17
17
|
.action(async (agentIdArg, options) => {
|
|
@@ -11,7 +11,7 @@ export function createAgentWorkspacesCommand() {
|
|
|
11
11
|
const cmd = new Command('workspaces');
|
|
12
12
|
cmd
|
|
13
13
|
.description('List workspaces that use an agent')
|
|
14
|
-
.argument('[identifier]', 'Agent ID or full name (e.g., owner
|
|
14
|
+
.argument('[identifier]', 'Agent ID or full name (e.g., owner~agent-name)')
|
|
15
15
|
.option('--limit <number>', 'Maximum number of workspaces to return', '20')
|
|
16
16
|
.option('--offset <number>', 'Number of workspaces to skip', '0')
|
|
17
17
|
.action(async (agentIdArg, options) => {
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -17,8 +17,9 @@ export interface ChatAppProps {
|
|
|
17
17
|
resumeEvents?: SessionEvent[];
|
|
18
18
|
resumeCommand?: string;
|
|
19
19
|
openDashboard?: boolean;
|
|
20
|
+
eventFilter?: Set<string>;
|
|
20
21
|
}
|
|
21
|
-
export declare function ChatApp({ initialPrompt, version, workspaceId, versionId, agentName, showSplash, resumeSession, resumeEvents, resumeCommand, openDashboard, }: ChatAppProps): React.JSX.Element;
|
|
22
|
+
export declare function ChatApp({ initialPrompt, version, workspaceId, versionId, agentName, showSplash, resumeSession, resumeEvents, resumeCommand, openDashboard, eventFilter, }: ChatAppProps): React.JSX.Element;
|
|
22
23
|
export declare function ensureAuthenticated(): Promise<string>;
|
|
23
24
|
export declare function createSession(client: GuildAPIClient, workspaceId: string | undefined, initialPrompt: string, versionId?: string, onProgress?: (status: string) => void): Promise<Session>;
|
|
24
25
|
export declare function createChatCommand(): Command;
|