@guildai/cli 0.5.13 → 0.6.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.
Files changed (99) hide show
  1. package/README.md +17 -0
  2. package/dist/commands/agent/chat.js +31 -31
  3. package/dist/commands/agent/clone.js +3 -1
  4. package/dist/commands/agent/code.js +3 -2
  5. package/dist/commands/agent/fork.js +41 -15
  6. package/dist/commands/agent/get.js +3 -2
  7. package/dist/commands/agent/grep.js +61 -31
  8. package/dist/commands/agent/init.js +1 -1
  9. package/dist/commands/agent/publish.js +3 -2
  10. package/dist/commands/agent/pull.js +36 -21
  11. package/dist/commands/agent/revalidate.js +4 -3
  12. package/dist/commands/agent/save.js +2 -2
  13. package/dist/commands/agent/search.js +3 -3
  14. package/dist/commands/agent/tags/add.js +4 -3
  15. package/dist/commands/agent/tags/list.js +3 -2
  16. package/dist/commands/agent/tags/remove.js +4 -3
  17. package/dist/commands/agent/tags/set.js +3 -2
  18. package/dist/commands/agent/test.js +8 -12
  19. package/dist/commands/agent/unpublish.js +3 -2
  20. package/dist/commands/agent/update.js +9 -8
  21. package/dist/commands/agent/versions.js +3 -2
  22. package/dist/commands/agent/workspaces.js +3 -2
  23. package/dist/commands/auth/login.js +3 -3
  24. package/dist/commands/chat.js +64 -102
  25. package/dist/commands/credentials/endpoint-list.d.ts +3 -0
  26. package/dist/commands/credentials/endpoint-list.js +87 -0
  27. package/dist/commands/credentials/list.d.ts +3 -0
  28. package/dist/commands/{container → credentials}/list.js +11 -10
  29. package/dist/commands/credentials/policy-create.d.ts +3 -0
  30. package/dist/commands/credentials/policy-create.js +66 -0
  31. package/dist/commands/credentials/policy-delete.d.ts +3 -0
  32. package/dist/commands/{container/get.js → credentials/policy-delete.js} +9 -9
  33. package/dist/commands/credentials/policy-list.d.ts +3 -0
  34. package/dist/commands/{container-image/list.js → credentials/policy-list.js} +9 -9
  35. package/dist/commands/credentials/policy-update.d.ts +3 -0
  36. package/dist/commands/credentials/policy-update.js +66 -0
  37. package/dist/commands/integration/connect.d.ts +3 -0
  38. package/dist/commands/integration/connect.js +76 -0
  39. package/dist/commands/integration/create.d.ts +3 -0
  40. package/dist/commands/integration/create.js +298 -0
  41. package/dist/commands/integration/get.d.ts +3 -0
  42. package/dist/commands/integration/get.js +95 -0
  43. package/dist/commands/integration/list.d.ts +3 -0
  44. package/dist/commands/integration/list.js +61 -0
  45. package/dist/commands/integration/operation/create.d.ts +3 -0
  46. package/dist/commands/integration/operation/create.js +163 -0
  47. package/dist/commands/integration/operation/list.d.ts +3 -0
  48. package/dist/commands/integration/operation/list.js +83 -0
  49. package/dist/commands/integration/update.d.ts +3 -0
  50. package/dist/commands/integration/update.js +139 -0
  51. package/dist/commands/integration/version/build.d.ts +3 -0
  52. package/dist/commands/integration/version/build.js +86 -0
  53. package/dist/commands/integration/version/create.d.ts +3 -0
  54. package/dist/commands/integration/version/create.js +45 -0
  55. package/dist/commands/integration/version/get.d.ts +3 -0
  56. package/dist/commands/integration/version/get.js +72 -0
  57. package/dist/commands/integration/version/list.d.ts +3 -0
  58. package/dist/commands/integration/version/list.js +44 -0
  59. package/dist/commands/integration/version/publish.d.ts +3 -0
  60. package/dist/commands/integration/version/publish.js +79 -0
  61. package/dist/commands/integration/version/test.d.ts +3 -0
  62. package/dist/commands/integration/version/test.js +104 -0
  63. package/dist/commands/trigger/create.js +35 -19
  64. package/dist/commands/workspace/create.js +10 -4
  65. package/dist/commands/workspace/select.js +0 -1
  66. package/dist/index.js +60 -27
  67. package/dist/lib/agent-helpers.d.ts +8 -0
  68. package/dist/lib/agent-helpers.js +15 -0
  69. package/dist/lib/api-types.d.ts +109 -78
  70. package/dist/lib/auth.d.ts +1 -1
  71. package/dist/lib/auth.js +10 -6
  72. package/dist/lib/integration-helpers.d.ts +15 -0
  73. package/dist/lib/integration-helpers.js +38 -0
  74. package/dist/lib/output.d.ts +13 -16
  75. package/dist/lib/output.js +137 -109
  76. package/dist/lib/session-events-fetch.d.ts +27 -0
  77. package/dist/lib/session-events-fetch.js +25 -0
  78. package/dist/lib/session-polling.d.ts +7 -2
  79. package/dist/lib/session-polling.js +18 -11
  80. package/dist/lib/session-resume.js +2 -5
  81. package/dist/lib/table.d.ts +0 -1
  82. package/dist/lib/table.js +0 -1
  83. package/dist/mcp/tools.js +6 -12
  84. package/docs/CLI_WORKFLOW.md +19 -2
  85. package/docs/skills/agent-dev.md +17 -2
  86. package/package.json +6 -5
  87. package/dist/commands/container/destroy.d.ts +0 -3
  88. package/dist/commands/container/destroy.js +0 -48
  89. package/dist/commands/container/events.d.ts +0 -3
  90. package/dist/commands/container/events.js +0 -44
  91. package/dist/commands/container/exec.d.ts +0 -3
  92. package/dist/commands/container/exec.js +0 -64
  93. package/dist/commands/container/get.d.ts +0 -3
  94. package/dist/commands/container/list.d.ts +0 -3
  95. package/dist/commands/container-image/create.d.ts +0 -3
  96. package/dist/commands/container-image/create.js +0 -41
  97. package/dist/commands/container-image/get.d.ts +0 -3
  98. package/dist/commands/container-image/get.js +0 -33
  99. package/dist/commands/container-image/list.d.ts +0 -3
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../../lib/api-client.js';
5
- import { getAgentId } from '../../../lib/agent-helpers.js';
5
+ import { getAgentId, resolveAgentRef } from '../../../lib/agent-helpers.js';
6
6
  import { handleAxiosError, ErrorCodes } from '../../../lib/errors.js';
7
7
  import { createOutputWriter } from '../../../lib/output.js';
8
8
  export function createAgentTagsListCommand() {
@@ -16,8 +16,9 @@ export function createAgentTagsListCommand() {
16
16
  const client = new GuildAPIClient();
17
17
  // Resolve agent ID
18
18
  const { agentId } = await getAgentId(agentIdArg);
19
+ const resolvedId = await resolveAgentRef(client, agentId);
19
20
  // Fetch tags
20
- const response = await client.get(`/agents/${agentId}/tags`);
21
+ const response = await client.get(`/agents/${resolvedId}/tags`);
21
22
  output.data(response);
22
23
  }
23
24
  catch (error) {
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../../lib/api-client.js';
5
- import { getAgentId } from '../../../lib/agent-helpers.js';
5
+ import { getAgentId, resolveAgentRef } from '../../../lib/agent-helpers.js';
6
6
  import { handleAxiosError, ErrorCodes } from '../../../lib/errors.js';
7
7
  import { createOutputWriter } from '../../../lib/output.js';
8
8
  export function createAgentTagsRemoveCommand() {
@@ -34,19 +34,20 @@ export function createAgentTagsRemoveCommand() {
34
34
  }
35
35
  // Now resolve agent ID properly
36
36
  const { agentId, config } = await getAgentId(agentIdArg);
37
+ const resolvedId = await resolveAgentRef(client, agentId);
37
38
  if (tagsToRemove.length === 0) {
38
39
  output.error('At least one tag is required.', 'Usage: guild agent tags remove [agent-id] <tag...>');
39
40
  process.exit(1);
40
41
  }
41
42
  // Fetch current tags
42
- const response = await client.get(`/agents/${agentId}/tags`);
43
+ const response = await client.get(`/agents/${resolvedId}/tags`);
43
44
  const currentTags = response.names;
44
45
  // Remove specified tags
45
46
  const updatedTags = currentTags.filter((tag) => !tagsToRemove.includes(tag));
46
47
  // Track which tags were not present
47
48
  const notPresentTags = tagsToRemove.filter((tag) => !currentTags.includes(tag));
48
49
  // Update tags
49
- await client.post(`/agents/${agentId}/tags`, { names: updatedTags });
50
+ await client.post(`/agents/${resolvedId}/tags`, { names: updatedTags });
50
51
  const agentName = config?.name || `agent ${agentId}`;
51
52
  const label = `${agentName}${config ? '' : ` (${agentId})`}`;
52
53
  output.success(`Updated tags for agent: ${label}`);
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../../lib/api-client.js';
5
- import { getAgentId } from '../../../lib/agent-helpers.js';
5
+ import { getAgentId, resolveAgentRef } from '../../../lib/agent-helpers.js';
6
6
  import { handleAxiosError, ErrorCodes } from '../../../lib/errors.js';
7
7
  import { createOutputWriter } from '../../../lib/output.js';
8
8
  export function createAgentTagsSetCommand() {
@@ -36,8 +36,9 @@ export function createAgentTagsSetCommand() {
36
36
  }
37
37
  // Now resolve agent ID properly
38
38
  const { agentId, config } = await getAgentId(agentIdArg);
39
+ const resolvedId = await resolveAgentRef(client, agentId);
39
40
  // Update tags (direct replacement)
40
- await client.post(`/agents/${agentId}/tags`, { names: tagsToSet });
41
+ await client.post(`/agents/${resolvedId}/tags`, { names: tagsToSet });
41
42
  const agentName = config?.name || `agent ${agentId}`;
42
43
  const label = `${agentName}${config ? '' : ` (${agentId})`}`;
43
44
  if (tagsToSet.length === 0) {
@@ -303,9 +303,9 @@ export function createAgentTestCommand() {
303
303
  mode: 'json',
304
304
  content: inputData,
305
305
  });
306
- // Poll for response (starting from event 0)
306
+ // Poll for response (starting from beginning)
307
307
  // 3 minutes - allow time for agents that use LLM calls for input parsing
308
- const response = await pollForResponse(client, session.id, 0, 180000);
308
+ const { response } = await pollForResponse(client, session.id, undefined, 180000);
309
309
  if (!response) {
310
310
  console.error('Error: No response received from agent within timeout');
311
311
  console.error('');
@@ -365,7 +365,7 @@ export function createAgentTestCommand() {
365
365
  });
366
366
  let lineNumber = 0;
367
367
  let processedCount = 0;
368
- let lastEventCount = 0;
368
+ let lastEventId;
369
369
  for await (const line of rl) {
370
370
  lineNumber++;
371
371
  if (!line.trim())
@@ -380,18 +380,14 @@ export function createAgentTestCommand() {
380
380
  mode: 'json',
381
381
  content: jsonInput,
382
382
  });
383
- // Wait for response (looking for events after our last count)
384
- const response = await pollForResponse(client, session.id, lastEventCount, 180000);
385
- if (!response) {
383
+ // Wait for response (looking for events after last seen)
384
+ const result = await pollForResponse(client, session.id, lastEventId, 180000);
385
+ lastEventId = result.lastEventId;
386
+ if (!result.response) {
386
387
  console.error(`Timeout: No response for line ${lineNumber}`);
387
- // Update event count even if timeout
388
- const eventsAfterResponse = await client.get(`/sessions/${session.id}/events`);
389
- lastEventCount = eventsAfterResponse?.items?.length || 0;
390
388
  continue;
391
389
  }
392
- // Update last event count
393
- const eventsAfterResponse = await client.get(`/sessions/${session.id}/events`);
394
- lastEventCount = eventsAfterResponse?.items?.length || 0;
390
+ const response = result.response;
395
391
  // Output response
396
392
  if (quiet) {
397
393
  // In quiet mode, output just the message content (or as JSON if --json is used)
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../lib/api-client.js';
5
- import { getAgentId } from '../../lib/agent-helpers.js';
5
+ import { getAgentId, resolveAgentRef } from '../../lib/agent-helpers.js';
6
6
  import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
7
7
  import { createOutputWriter } from '../../lib/output.js';
8
8
  export function createAgentUnpublishCommand() {
@@ -16,8 +16,9 @@ export function createAgentUnpublishCommand() {
16
16
  const client = new GuildAPIClient();
17
17
  // Resolve agent ID
18
18
  const { agentId, config } = await getAgentId(agentIdArg);
19
+ const resolvedId = await resolveAgentRef(client, agentId);
19
20
  // Fetch all versions
20
- const response = await client.get(`/agents/${agentId}/versions`);
21
+ const response = await client.get(`/agents/${resolvedId}/versions`);
21
22
  // Find latest PUBLISHED version
22
23
  const publishedVersions = response.items
23
24
  .filter((v) => v.status === 'PUBLISHED')
@@ -3,7 +3,7 @@
3
3
  import { Command } from 'commander';
4
4
  import * as readline from 'readline';
5
5
  import { GuildAPIClient } from '../../lib/api-client.js';
6
- import { getGuildcoreUrl } from '../../lib/config.js';
6
+ import { getAgentId, resolveAgentRef } from '../../lib/agent-helpers.js';
7
7
  import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
8
8
  import { createOutputWriter } from '../../lib/output.js';
9
9
  async function confirmVisibilityChange(agentName, makePublic) {
@@ -26,15 +26,15 @@ 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/agent-name)')
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')
33
- .action(async (agentId, options) => {
33
+ .action(async (identifierArg, options) => {
34
34
  const output = createOutputWriter();
35
35
  // Validate that at least one option is provided
36
36
  if (!options.public && !options.private) {
37
- output.error('No update options provided.', 'Usage: guild agent update <agent-id> [options]\n\nOptions:\n --public Make the agent public\n --private Make the agent private\n --yes Skip confirmation prompt\n\nExamples:\n guild agent update my-agent --public\n guild agent update my-agent --private --yes\n\nNote: Agent descriptions are set from README.md when publishing.');
37
+ output.error('No update options provided.', 'Usage: guild agent update [identifier] [options]\n\nOptions:\n --public Make the agent public\n --private Make the agent private\n --yes Skip confirmation prompt\n\nExamples:\n guild agent update my-agent --public\n guild agent update my-agent --private --yes\n guild agent update --public (uses guild.json)\n\nNote: Agent descriptions are set from README.md when publishing.');
38
38
  process.exit(1);
39
39
  }
40
40
  // Validate that --public and --private are not both specified
@@ -42,11 +42,12 @@ export function createAgentUpdateCommand() {
42
42
  output.error('Cannot specify both --public and --private');
43
43
  process.exit(1);
44
44
  }
45
- const baseUrl = getGuildcoreUrl();
46
- const client = new GuildAPIClient({ baseUrl });
45
+ const { agentId } = await getAgentId(identifierArg);
46
+ const client = new GuildAPIClient();
47
47
  try {
48
+ const resolvedId = await resolveAgentRef(client, agentId);
48
49
  // Fetch current agent info for confirmation prompts
49
- const agent = await client.get(`/agents/${agentId}`);
50
+ const agent = await client.get(`/agents/${resolvedId}`);
50
51
  // Handle visibility change confirmation
51
52
  const changingVisibility = options.public || options.private;
52
53
  if (changingVisibility) {
@@ -73,7 +74,7 @@ export function createAgentUpdateCommand() {
73
74
  if (options.private) {
74
75
  updatePayload.is_public = false;
75
76
  }
76
- const result = await client.patch(`/agents/${agentId}`, updatePayload);
77
+ const result = await client.patch(`/agents/${resolvedId}`, updatePayload);
77
78
  // Build success message
78
79
  const changes = [];
79
80
  if (changingVisibility) {
@@ -4,7 +4,7 @@ import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../lib/api-client.js';
5
5
  import { getGuildcoreUrl } from '../../lib/config.js';
6
6
  import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
7
- import { getAgentId } from '../../lib/agent-helpers.js';
7
+ import { getAgentId, resolveAgentRef } from '../../lib/agent-helpers.js';
8
8
  import { getOutputMode } from '../../lib/output-mode.js';
9
9
  import { createOutputWriter, formatVersionTable } from '../../lib/output.js';
10
10
  export function createAgentVersionsCommand() {
@@ -23,7 +23,8 @@ export function createAgentVersionsCommand() {
23
23
  const limit = parseInt(options.limit, 10);
24
24
  const offset = parseInt(options.offset, 10);
25
25
  try {
26
- const result = await client.get(`/agents/${agentId}/versions?limit=${limit}&offset=${offset}`);
26
+ const resolvedId = await resolveAgentRef(client, agentId);
27
+ const result = await client.get(`/agents/${resolvedId}/versions?limit=${limit}&offset=${offset}`);
27
28
  if (getOutputMode() === 'json') {
28
29
  output.data(result);
29
30
  }
@@ -4,7 +4,7 @@ import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../lib/api-client.js';
5
5
  import { getGuildcoreUrl } from '../../lib/config.js';
6
6
  import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
7
- import { getAgentId } from '../../lib/agent-helpers.js';
7
+ import { getAgentId, resolveAgentRef } from '../../lib/agent-helpers.js';
8
8
  import { createOutputWriter, formatWorkspaceTable } from '../../lib/output.js';
9
9
  import { getOutputMode } from '../../lib/output-mode.js';
10
10
  export function createAgentWorkspacesCommand() {
@@ -22,7 +22,8 @@ export function createAgentWorkspacesCommand() {
22
22
  const limit = parseInt(options.limit, 10);
23
23
  const offset = parseInt(options.offset, 10);
24
24
  try {
25
- const result = await client.get(`/agents/${agentId}/workspaces?limit=${limit}&offset=${offset}`);
25
+ const resolvedId = await resolveAgentRef(client, agentId);
26
+ const result = await client.get(`/agents/${resolvedId}/workspaces?limit=${limit}&offset=${offset}`);
26
27
  if (getOutputMode() === 'json') {
27
28
  output.data(result);
28
29
  }
@@ -11,11 +11,11 @@ export function createAuthLoginCommand() {
11
11
  .description('Login to Guild.ai')
12
12
  .option('--return-url <url>', 'Custom URL to redirect to after authentication')
13
13
  .option('--return-label <text>', 'Friendly label for return button (e.g., "VSCode")')
14
- .option('--no-browser', 'Skip opening the browser (print URL only)')
14
+ .option('--non-interactive', 'Skip interactive prompts (for use with coding agents)')
15
15
  .action(async (options) => {
16
16
  const output = createOutputWriter();
17
- const noBrowser = options.browser === false;
18
- const success = await login(options.returnUrl, options.returnLabel, noBrowser);
17
+ const nonInteractive = options.nonInteractive || false;
18
+ const success = await login(options.returnUrl, options.returnLabel, nonInteractive);
19
19
  if (success) {
20
20
  try {
21
21
  await configureNpmrc();
@@ -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 { fetchEvents, fetchTasks } from '../lib/session-events-fetch.js';
18
19
  import { AgentInstallPrompt } from '../components/AgentInstallPrompt.js';
19
20
  import { getWorkspaceId } from '../lib/guild-config.js';
20
21
  import { ensureInteractiveStdin } from '../lib/stdin.js';
@@ -46,6 +47,35 @@ function fixListItemMarkdown(text) {
46
47
  text = text.replace(/(?<![\\w])_([^_]+)_(?![\\w])/g, (_, content) => chalk.italic(content));
47
48
  return text;
48
49
  }
50
+ /**
51
+ * Output the result of a --once mode session.
52
+ * Handles both JSON and human-readable output formats.
53
+ */
54
+ async function outputOnceResult(sessionId, events, mode) {
55
+ if (mode === 'json') {
56
+ console.log(JSON.stringify({ session_id: sessionId, events }, null, 2));
57
+ }
58
+ else {
59
+ const agentMessages = events.filter((e) => e.type === 'agent_notification_message');
60
+ if (agentMessages.length > 0) {
61
+ let messageContent = agentMessages[agentMessages.length - 1].content.data;
62
+ const trimmed = messageContent.trim();
63
+ if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
64
+ try {
65
+ const parsed = JSON.parse(trimmed);
66
+ if (typeof parsed === 'object' && parsed !== null && 'message' in parsed) {
67
+ messageContent = parsed.message;
68
+ }
69
+ }
70
+ catch {
71
+ // If parsing fails, use content as-is
72
+ }
73
+ }
74
+ const rendered = fixListItemMarkdown(await marked(messageContent));
75
+ console.log(rendered.trim());
76
+ }
77
+ }
78
+ }
49
79
  import { createSpinner as createAnimatedSpinner, createRandomSpinner, } from '../lib/spinners.js';
50
80
  function CustomInput({ value, onChange, onSubmit, trackedTasksSize, setShowTaskPanel, isActive, }) {
51
81
  useInput((input, key) => {
@@ -146,6 +176,16 @@ export function ChatApp({ initialPrompt, version, workspaceId, versionId, agentN
146
176
  initialDelay: 500,
147
177
  maxDelay: 5000,
148
178
  backoffMultiplier: 1.5,
179
+ shouldRetry: (error) => {
180
+ if (typeof error === 'object' && error !== null) {
181
+ const err = error;
182
+ return (err.code === 'ECONNREFUSED' ||
183
+ err.code === 'ETIMEDOUT' ||
184
+ err.code === 'ENOTFOUND' ||
185
+ err.code === 'ECONNABORTED');
186
+ }
187
+ return false;
188
+ },
149
189
  });
150
190
  setConnectedClient(client);
151
191
  setConnectedSession(session);
@@ -382,7 +422,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
382
422
  const sentMessages = useRef(new Set());
383
423
  const pollInterval = useRef(null);
384
424
  const spinnerInterval = useRef(null);
385
- const lastMessageCountRef = useRef(resumeEvents?.length || 0);
425
+ const lastEventIdRef = useRef(resumeEvents?.length ? resumeEvents[resumeEvents.length - 1].id : undefined);
386
426
  const isPolling = useRef(false);
387
427
  const receivedResponseSinceLastInput = useRef(false);
388
428
  const firstMessageNotified = useRef(!!resumeEvents);
@@ -435,10 +475,7 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
435
475
  return;
436
476
  isPollingTasks.current = true;
437
477
  try {
438
- const response = await client.get(`/sessions/${session.id}/tasks?limit=1000`);
439
- const tasksList = (Array.isArray(response)
440
- ? response
441
- : response?.items || []);
478
+ const tasksList = await fetchTasks(client, session.id);
442
479
  setTasks(tasksList);
443
480
  }
444
481
  catch (error) {
@@ -463,20 +500,14 @@ function ChatUIWithConnection({ initialPrompt, version: _version, versionId: _ve
463
500
  if (isPolling.current)
464
501
  return;
465
502
  isPolling.current = true;
466
- debug(`poll() called, session=${session.id}`);
503
+ debug(`poll() called, session=${session.id}, fromId=${lastEventIdRef.current}`);
467
504
  try {
468
- const response = await client.get(`/sessions/${session.id}/events?limit=1000`);
469
- // Debug: log raw response structure
470
- const keys = response ? Object.keys(response) : [];
471
- debug(`Response: isArray=${Array.isArray(response)}, keys=${keys.join(',')}, type=${typeof response}`);
472
- const allEvents = (Array.isArray(response)
473
- ? response
474
- : response?.items || []);
475
- const newEvents = allEvents.slice(lastMessageCountRef.current);
476
- // Debug: log event counts
477
- debug(`Events: total=${allEvents.length}, lastCount=${lastMessageCountRef.current}, new=${newEvents.length}`);
505
+ const newEvents = await fetchEvents(client, session.id, {
506
+ fromId: lastEventIdRef.current,
507
+ });
508
+ debug(`Events: fromId=${lastEventIdRef.current}, new=${newEvents.length}`);
478
509
  if (newEvents.length > 0) {
479
- lastMessageCountRef.current = allEvents.length;
510
+ lastEventIdRef.current = newEvents[newEvents.length - 1].id;
480
511
  for (const event of newEvents) {
481
512
  // Track task from event if present
482
513
  const taskInfo = event.task;
@@ -919,7 +950,7 @@ export function createChatCommand() {
919
950
  .option('--workspace <identifier>', 'Workspace ID or full name (e.g., owner/workspace-name)')
920
951
  .option('--no-splash', 'Skip the splash screen animation')
921
952
  .option('--resume <session-id>', 'Resume an existing session')
922
- .addHelpText('after', '\nTo chat with the agent you are developing, use: guild agent chat')
953
+ .addHelpText('after', '\nTo chat with a local agent under development: guild agent chat')
923
954
  .action(async (promptArgs, options) => {
924
955
  const initialPrompt = promptArgs.length > 0 ? promptArgs.join(' ') : 'Hello';
925
956
  if (options.once) {
@@ -943,19 +974,15 @@ export function createChatCommand() {
943
974
  const inactivityTimeoutMs = 300000; // 5 minutes
944
975
  const pollIntervalMs = 500;
945
976
  const maxInactivityAttempts = inactivityTimeoutMs / pollIntervalMs;
946
- let lastMessageCount = 0;
977
+ let lastSeenEventId;
978
+ const allEvents = [];
947
979
  let inactivityCounter = 0;
948
980
  while (true) {
949
981
  await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
950
- const response = await client.get(`/sessions/${session.id}/events?limit=1000`);
951
- // Handle both array and paginated object responses (backend may return either)
952
- const events = (Array.isArray(response)
953
- ? response
954
- : response?.items || []);
955
- // Check if we got new events (reset inactivity counter)
956
- if (events.length > lastMessageCount) {
957
- // Debug: log all new events
958
- const newEvents = events.slice(lastMessageCount);
982
+ const newEvents = await fetchEvents(client, session.id, {
983
+ fromId: lastSeenEventId,
984
+ });
985
+ if (newEvents.length > 0) {
959
986
  for (const evt of newEvents) {
960
987
  const taskInfo = evt.task;
961
988
  if (taskInfo) {
@@ -965,8 +992,9 @@ export function createChatCommand() {
965
992
  debug(`Event: ${evt.type} (no task info)`);
966
993
  }
967
994
  }
968
- lastMessageCount = events.length;
969
- inactivityCounter = 0; // Reset - we got activity!
995
+ allEvents.push(...newEvents);
996
+ lastSeenEventId = newEvents[newEvents.length - 1].id;
997
+ inactivityCounter = 0;
970
998
  }
971
999
  else {
972
1000
  inactivityCounter++;
@@ -976,93 +1004,27 @@ export function createChatCommand() {
976
1004
  // For orchestrating agents like agent-builder that spawn child tasks, we need to
977
1005
  // wait for the root agent's completion, not just any runtime_done event.
978
1006
  const targetAgent = options.agent || 'assistant';
979
- const hasRootTaskDone = events.some((e) => e.type === 'runtime_done' &&
1007
+ const hasRootTaskDone = allEvents.some((e) => e.type === 'runtime_done' &&
980
1008
  matchesAgent(e.task?.agent, targetAgent) &&
981
1009
  !e.task?.parent_task_id // Root task has no parent
982
1010
  );
983
1011
  // Also check for agent_notification_message events from the root agent
984
- const hasAgentMessage = events.some((e) => e.type === 'agent_notification_message' &&
1012
+ const hasAgentMessage = allEvents.some((e) => e.type === 'agent_notification_message' &&
985
1013
  matchesAgent(e.task?.agent, targetAgent) &&
986
1014
  !e.task?.parent_task_id);
987
1015
  // Check for a ui_prompt request... that ends the game.
988
- const hasUIPromptMessage = events.some((e) => e.type === 'agent_notification_message' &&
1016
+ const hasUIPromptMessage = allEvents.some((e) => e.type === 'agent_notification_message' &&
989
1017
  e.task?.tool_name === 'ui_prompt');
990
1018
  if (hasRootTaskDone || hasAgentMessage || hasUIPromptMessage) {
991
1019
  debug(`Found completion event from root agent (${targetAgent}), exiting --once mode`);
992
- // Output format depends on --mode flag
993
- if (options.mode === 'json') {
994
- // JSON mode: output structured events
995
- console.log(JSON.stringify({
996
- session_id: session.id,
997
- events: events,
998
- }, null, 2));
999
- }
1000
- else {
1001
- // Human-readable mode (default): extract and render message content
1002
- const agentMessages = events.filter((e) => e.type === 'agent_notification_message');
1003
- if (agentMessages.length > 0) {
1004
- // Get the last message content
1005
- let messageContent = agentMessages[agentMessages.length - 1].content.data;
1006
- // Handle JSON {"message": "..."} wrapper
1007
- const trimmed = messageContent.trim();
1008
- if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
1009
- try {
1010
- const parsed = JSON.parse(trimmed);
1011
- if (typeof parsed === 'object' &&
1012
- parsed !== null &&
1013
- 'message' in parsed) {
1014
- messageContent = parsed.message;
1015
- }
1016
- }
1017
- catch {
1018
- // If parsing fails, use content as-is
1019
- }
1020
- }
1021
- // Render markdown and output
1022
- const rendered = fixListItemMarkdown(await marked(messageContent));
1023
- console.log(rendered.trim());
1024
- }
1025
- }
1020
+ await outputOnceResult(session.id, allEvents, options.mode);
1026
1021
  process.exit(0);
1027
1022
  }
1028
1023
  // Timeout if no activity for too long
1029
1024
  if (inactivityCounter >= maxInactivityAttempts) {
1030
1025
  debug(`Inactivity timeout reached (${maxInactivityAttempts} attempts with no new events)`);
1031
- debug(`Exiting with ${events.length} events total`);
1032
- // Output format depends on --mode flag
1033
- if (options.mode === 'json') {
1034
- // JSON mode: output structured events
1035
- console.log(JSON.stringify({
1036
- session_id: session.id,
1037
- events: events,
1038
- }, null, 2));
1039
- }
1040
- else {
1041
- // Human-readable mode (default): extract and render message content
1042
- const agentMessages = events.filter((e) => e.type === 'agent_notification_message');
1043
- if (agentMessages.length > 0) {
1044
- // Get the last message content
1045
- let messageContent = agentMessages[agentMessages.length - 1].content.data;
1046
- // Handle JSON {"message": "..."} wrapper
1047
- const trimmed = messageContent.trim();
1048
- if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
1049
- try {
1050
- const parsed = JSON.parse(trimmed);
1051
- if (typeof parsed === 'object' &&
1052
- parsed !== null &&
1053
- 'message' in parsed) {
1054
- messageContent = parsed.message;
1055
- }
1056
- }
1057
- catch {
1058
- // If parsing fails, use content as-is
1059
- }
1060
- }
1061
- // Render markdown and output
1062
- const rendered = fixListItemMarkdown(await marked(messageContent));
1063
- console.log(rendered.trim());
1064
- }
1065
- }
1026
+ debug(`Exiting with ${allEvents.length} events total`);
1027
+ await outputOnceResult(session.id, allEvents, options.mode);
1066
1028
  process.exit(0);
1067
1029
  }
1068
1030
  }
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function createCredentialsEndpointListCommand(): Command;
3
+ //# sourceMappingURL=endpoint-list.d.ts.map
@@ -0,0 +1,87 @@
1
+ // Copyright 2026 Guild.ai
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { GuildAPIClient } from '../../lib/api-client.js';
6
+ import { getAuthToken } from '../../lib/auth.js';
7
+ import { handleAxiosError } from '../../lib/errors.js';
8
+ import { getOutputMode } from '../../lib/output-mode.js';
9
+ import { createOutputWriter } from '../../lib/output.js';
10
+ import { Table } from '../../lib/table.js';
11
+ export function createCredentialsEndpointListCommand() {
12
+ const cmd = new Command('list');
13
+ cmd
14
+ .description('List endpoints for a credential')
15
+ .argument('<credential-id>', 'Credential ID')
16
+ .option('--include-previous-versions', 'Include endpoints from previous versions')
17
+ .option('--search <query>', 'Search by operation name')
18
+ .option('--limit <number>', 'Number of results to return', '20')
19
+ .option('--offset <number>', 'Offset for pagination', '0')
20
+ .action(async (credentialId, options) => {
21
+ const output = createOutputWriter();
22
+ try {
23
+ const token = await getAuthToken();
24
+ if (!token) {
25
+ output.error('Not authenticated. Run: guild auth login');
26
+ process.exit(1);
27
+ }
28
+ const client = new GuildAPIClient();
29
+ const params = new URLSearchParams();
30
+ params.append('limit', options.limit);
31
+ params.append('offset', options.offset);
32
+ if (options.includePreviousVersions) {
33
+ params.append('include_previous_versions', 'true');
34
+ }
35
+ if (options.search) {
36
+ params.append('search', options.search);
37
+ }
38
+ const response = await client.get(`/credentials/${credentialId}/endpoints?${params.toString()}`);
39
+ if (getOutputMode() === 'json') {
40
+ console.log(JSON.stringify(response, null, 2));
41
+ }
42
+ else {
43
+ formatEndpointsTable(response.items, response.pagination);
44
+ }
45
+ }
46
+ catch (error) {
47
+ const formattedError = handleAxiosError(error);
48
+ output.error(formattedError.details);
49
+ process.exit(1);
50
+ }
51
+ });
52
+ return cmd;
53
+ }
54
+ function formatEndpointsTable(endpoints, pagination) {
55
+ if (endpoints.length === 0) {
56
+ console.log(chalk.dim('No endpoints found'));
57
+ return;
58
+ }
59
+ const table = new Table({
60
+ columns: [
61
+ { name: 'operation', title: 'OPERATION', alignment: 'left' },
62
+ { name: 'method', title: 'METHOD', alignment: 'left' },
63
+ { name: 'path', title: 'PATH', alignment: 'left' },
64
+ { name: 'tags', title: 'TAGS', alignment: 'left' },
65
+ ],
66
+ });
67
+ endpoints.forEach((ep) => {
68
+ const methodColor = ep.method === 'DELETE' ? chalk.red : chalk.green;
69
+ table.addRow({
70
+ operation: ep.operation,
71
+ method: methodColor(ep.method),
72
+ path: ep.path,
73
+ tags: ep.tags?.join(', ') || '',
74
+ });
75
+ });
76
+ table.printTable();
77
+ const showing = Math.min(pagination.limit, endpoints.length);
78
+ if (pagination.has_more) {
79
+ const nextOffset = pagination.offset + pagination.limit;
80
+ console.log(`\nShowing ${showing} of ${pagination.total_count} endpoints. ` +
81
+ chalk.dim(`Use --offset ${nextOffset} to see more.`));
82
+ }
83
+ else if (pagination.total_count > showing) {
84
+ console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} endpoints`));
85
+ }
86
+ }
87
+ //# sourceMappingURL=endpoint-list.js.map
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function createCredentialsListCommand(): Command;
3
+ //# sourceMappingURL=list.d.ts.map