@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
package/README.md CHANGED
@@ -183,6 +183,23 @@ guild trigger deactivate <trigger-id> # Deactivate a trigger
183
183
  guild trigger sessions <trigger-id> # List sessions spawned by a trigger
184
184
  ```
185
185
 
186
+ ### Integrations
187
+
188
+ ```bash
189
+ guild integration list # List integrations
190
+ guild integration get <id> # Get integration details
191
+ guild integration create <name> # Create a new integration
192
+ guild integration update <id> # Update an integration
193
+ guild integration version list <id> # List versions
194
+ guild integration version create <id> # Create a draft version
195
+ guild integration version get <id> # Get version details
196
+ guild integration version build <id> # Build (validate) a draft
197
+ guild integration version publish <id> # Publish a built version
198
+ guild integration version test <id> # Test an endpoint invocation
199
+ guild integration operation list <id> # List operations for a version
200
+ guild integration operation create <id> # Create operations (or import from OpenAPI)
201
+ ```
202
+
186
203
  ### Chat
187
204
 
188
205
  ```bash
@@ -38,13 +38,29 @@ export function createAgentChatCommand() {
38
38
  .option('--no-splash', 'Skip the splash screen animation')
39
39
  .option('--resume <session-id>', 'Resume an existing session')
40
40
  .option('--open', 'Open session in web dashboard')
41
- .addHelpText('after', '\nFor general chat with the Guild assistant, use: guild chat')
41
+ .addHelpText('after', '\nTo chat with a published agent by name: guild chat --agent owner/agent-name')
42
42
  .action(async (promptArgs, options) => {
43
43
  try {
44
44
  // Get agent ID from guild.json in the specified path
45
45
  const agentPath = options.path || '.';
46
46
  const { agentId, config } = await getAgentId(undefined, agentPath);
47
47
  const initialPrompt = promptArgs.length > 0 ? promptArgs.join(' ') : 'Hello';
48
+ // If using JSON input, read it early (before auth) for fast failure on bad input
49
+ let inputData;
50
+ if (options.mode === 'json') {
51
+ try {
52
+ inputData = await readStdinAsJSON();
53
+ }
54
+ catch (error) {
55
+ const err = error;
56
+ console.error(`Error: ${err.message}`);
57
+ console.error('');
58
+ console.error('Example usage:');
59
+ console.error(' echo \'{"prompt": "test"}\' | guild agent chat --mode json');
60
+ console.error(' guild agent chat --mode json < input.json');
61
+ process.exit(1);
62
+ }
63
+ }
48
64
  // Check authentication (uses shared function from chat.tsx)
49
65
  await ensureAuthenticated();
50
66
  const client = new GuildAPIClient();
@@ -152,25 +168,14 @@ export function createAgentChatCommand() {
152
168
  console.error(` guild agent chat ${agentId}`);
153
169
  process.exit(1);
154
170
  }
155
- // If using JSON input, read it early (before session creation)
156
- let inputData;
157
- if (options.mode === 'json') {
158
- try {
159
- inputData = await readStdinAsJSON();
160
- }
161
- catch (error) {
162
- const err = error;
163
- console.error(`Error: ${err.message}`);
164
- console.error('');
165
- console.error('Example usage:');
166
- console.error(' echo \'{"prompt": "test"}\' | guild agent chat --mode json');
167
- console.error(' guild agent chat --mode json < input.json');
168
- process.exit(1);
169
- }
170
- }
171
171
  // Branch: JSON/JSONL modes vs interactive
172
172
  if (options.mode === 'json' || options.mode === 'jsonl') {
173
- const session = await createSession(client, options.workspace, initialPrompt, version.id);
173
+ // For JSON mode with piped input, use the piped data as the initial prompt
174
+ // so the agent receives it as its input (not the default 'Hello')
175
+ const sessionPrompt = options.mode === 'json' && inputData
176
+ ? JSON.stringify(inputData)
177
+ : initialPrompt;
178
+ const session = await createSession(client, options.workspace, sessionPrompt, version.id);
174
179
  if (!quiet) {
175
180
  console.log(`✓ Agent: ${config?.name || agentId}`);
176
181
  const sessionLink = session.session_url
@@ -183,13 +188,10 @@ export function createAgentChatCommand() {
183
188
  await open(session.session_url);
184
189
  }
185
190
  if (options.mode === 'json' && inputData) {
186
- // JSON one-shot mode
191
+ // JSON one-shot mode — input was passed as initial_prompt during
192
+ // session creation, so the agent already has it. Just poll for the response.
187
193
  try {
188
- await client.post(`/sessions/${session.id}/events`, {
189
- mode: 'json',
190
- content: inputData,
191
- });
192
- const response = await pollForResponse(client, session.id, 0);
194
+ const { response } = await pollForResponse(client, session.id, undefined);
193
195
  if (!response) {
194
196
  console.error('Timeout: No response received from agent');
195
197
  process.exit(1);
@@ -219,7 +221,7 @@ export function createAgentChatCommand() {
219
221
  });
220
222
  let lineNumber = 0;
221
223
  let processedCount = 0;
222
- let lastEventCount = 0;
224
+ let lastEventId;
223
225
  for await (const line of rl) {
224
226
  lineNumber++;
225
227
  if (!line.trim())
@@ -233,15 +235,13 @@ export function createAgentChatCommand() {
233
235
  mode: 'json',
234
236
  content: jsonInput,
235
237
  });
236
- const response = await pollForResponse(client, session.id, lastEventCount);
237
- if (!response) {
238
+ const result = await pollForResponse(client, session.id, lastEventId);
239
+ lastEventId = result.lastEventId;
240
+ if (!result.response) {
238
241
  console.error(`Timeout: No response for line ${lineNumber}`);
239
- const eventsAfterResponse = await client.get(`/sessions/${session.id}/events`);
240
- lastEventCount = eventsAfterResponse?.items?.length || 0;
241
242
  continue;
242
243
  }
243
- const eventsAfterResponse = await client.get(`/sessions/${session.id}/events`);
244
- lastEventCount = eventsAfterResponse?.items?.length || 0;
244
+ const response = result.response;
245
245
  if (quiet) {
246
246
  console.log(response);
247
247
  }
@@ -8,6 +8,7 @@ import * as path from 'path';
8
8
  import { getAuthenticatedUrl } from '../../lib/auth.js';
9
9
  import { runGit, GitError, formatGitError, installPrePushHook } from '../../lib/git.js';
10
10
  import { createOutputWriter } from '../../lib/output.js';
11
+ import { resolveAgentRef } from '../../lib/agent-helpers.js';
11
12
  async function isDirectoryEmpty(dirPath) {
12
13
  try {
13
14
  const files = await fs.readdir(dirPath);
@@ -30,7 +31,8 @@ export function createAgentCloneCommand() {
30
31
  try {
31
32
  // Fetch agent details
32
33
  const client = new GuildAPIClient();
33
- const agent = await client.get(`/agents/${agentId}`);
34
+ const resolvedId = await resolveAgentRef(client, agentId);
35
+ const agent = await client.get(`/agents/${resolvedId}`);
34
36
  if (!agent.git_url) {
35
37
  output.error('Error: Agent does not have a git repository', 'This agent may not have been initialized with git.');
36
38
  process.exit(1);
@@ -3,7 +3,7 @@
3
3
  import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../lib/api-client.js';
5
5
  import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
6
- import { getAgentId } from '../../lib/agent-helpers.js';
6
+ import { getAgentId, resolveAgentRef } from '../../lib/agent-helpers.js';
7
7
  import { createOutputWriter } from '../../lib/output.js';
8
8
  import * as fs from 'fs/promises';
9
9
  import * as path from 'path';
@@ -22,7 +22,8 @@ export function createAgentCodeCommand() {
22
22
  const includeDraft = options.draft ? '1' : '0';
23
23
  let files;
24
24
  try {
25
- files = await client.get(`/agents/${agentId}/code?include_unpublished=${includeDraft}`);
25
+ const resolvedId = await resolveAgentRef(client, agentId);
26
+ files = await client.get(`/agents/${resolvedId}/code?include_unpublished=${includeDraft}`);
26
27
  }
27
28
  catch (error) {
28
29
  const formattedError = handleAxiosError(error);
@@ -2,6 +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, resolveAgentRef } from '../../lib/agent-helpers.js';
5
6
  import { handleAxiosError, ErrorCodes, debug } from '../../lib/errors.js';
6
7
  import * as fs from 'fs/promises';
7
8
  import * as readline from 'readline';
@@ -47,21 +48,48 @@ export function createAgentForkCommand() {
47
48
  const cmd = new Command('fork');
48
49
  cmd
49
50
  .description('Fork an existing agent version to create a new agent')
50
- .argument('<agent-id>:<version-id>', 'Source agent and version (e.g., agent_abc:version_xyz)')
51
+ .argument('[identifier]', 'Agent ID, full name, or agent:version (e.g., owner/agent-name:version_xyz)')
51
52
  .option('--name <name>', 'Name for the forked agent')
52
53
  .option('--description <desc>', 'Description for the forked agent')
53
54
  .option('--directory <path>', 'Target directory for clone')
54
- .option('--owner <owner-id>', 'Owner account (user or organization ID)')
55
- .action(async (sourceArg, options) => {
55
+ .option('--owner <owner>', 'Owner (name or ID)')
56
+ .action(async (identifierArg, options) => {
56
57
  const output = createOutputWriter();
57
58
  try {
58
- // Parse agent-id:version-id format
59
- const parts = sourceArg.split(':');
60
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
61
- output.error('Error: Invalid argument format', `Expected: <agent-id>:<version-id>\nExample: guild agent fork agent_abc123:version_xyz789\n\nTo find versions:\n guild agent versions ${parts[0] || '<agent-id>'}`);
62
- process.exit(1);
59
+ // Resolve agent ID and optional version ID
60
+ let sourceAgentId;
61
+ let sourceVersionId;
62
+ if (identifierArg && identifierArg.includes(':')) {
63
+ // Explicit agent:version format
64
+ const colonIndex = identifierArg.lastIndexOf(':');
65
+ const agentPart = identifierArg.substring(0, colonIndex);
66
+ sourceVersionId = identifierArg.substring(colonIndex + 1);
67
+ if (!agentPart || !sourceVersionId) {
68
+ output.error('Error: Invalid argument format', 'Expected: [identifier] or [identifier]:[version-id]\nExample: guild agent fork owner/agent-name:version_xyz\n\nTo find versions:\n guild agent versions <agent-id>');
69
+ process.exit(1);
70
+ }
71
+ const resolved = await getAgentId(agentPart);
72
+ sourceAgentId = resolved.agentId;
73
+ }
74
+ else {
75
+ // No version specified — resolve agent, then find latest published
76
+ const resolved = await getAgentId(identifierArg);
77
+ sourceAgentId = resolved.agentId;
78
+ }
79
+ // Auto-resolve version if not specified
80
+ const client = new GuildAPIClient();
81
+ sourceAgentId = await resolveAgentRef(client, sourceAgentId);
82
+ if (!sourceVersionId) {
83
+ const versions = await client.get(`/agents/${sourceAgentId}/versions`);
84
+ const published = versions.items
85
+ .filter((v) => v.status === 'PUBLISHED')
86
+ .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
87
+ if (published.length === 0) {
88
+ output.error('No published versions found', `Agent ${sourceAgentId} has no published versions to fork.\n\nTo see all versions:\n guild agent versions ${sourceAgentId}`);
89
+ process.exit(1);
90
+ }
91
+ sourceVersionId = published[0].id;
63
92
  }
64
- const [sourceAgentId, sourceVersionId] = parts;
65
93
  // Determine name (validate before API call for better UX)
66
94
  let agentName = options.name;
67
95
  if (!agentName) {
@@ -73,7 +101,7 @@ export function createAgentForkCommand() {
73
101
  }
74
102
  }
75
103
  else {
76
- output.error('Error: Agent name required in non-interactive mode', `Provide a name:\n guild agent fork ${sourceArg} --name my-forked-agent\n\nOr run interactively to be prompted.`);
104
+ output.error('Error: Agent name required in non-interactive mode', `Provide a name:\n guild agent fork ${identifierArg || '<identifier>'} --name my-forked-agent\n\nOr run interactively to be prompted.`);
77
105
  process.exit(1);
78
106
  }
79
107
  }
@@ -92,12 +120,11 @@ export function createAgentForkCommand() {
92
120
  if (dirExists) {
93
121
  const isEmpty = await isDirectoryEmpty(targetDir);
94
122
  if (!isEmpty) {
95
- output.error(`Error: Directory '${targetDir}' already exists and is not empty`, `Choose a different directory:\n guild agent fork ${sourceArg} --directory ./different-path\n\nOr remove the existing directory first.`);
123
+ output.error(`Error: Directory '${targetDir}' already exists and is not empty`, `Choose a different directory:\n guild agent fork ${identifierArg || '<identifier>'} --directory ./different-path\n\nOr remove the existing directory first.`);
96
124
  process.exit(1);
97
125
  }
98
126
  }
99
- // Now fetch source version from API (after local validations)
100
- const client = new GuildAPIClient();
127
+ // Fetch source version from API (after local validations)
101
128
  const sourceVersion = await client.get(`/agents/${sourceAgentId}/versions/${sourceVersionId}`);
102
129
  output.progress(`✓ Fetched source version from '${sourceVersion.agent.name}' (${sourceVersionId.substring(0, 12)})`);
103
130
  // Determine description
@@ -174,8 +201,7 @@ export function createAgentForkCommand() {
174
201
  process.exit(1);
175
202
  }
176
203
  if (formattedError.code === ErrorCodes.NOT_FOUND) {
177
- const [sourceAgentId] = sourceArg.split(':');
178
- output.error(`Error: Version not found: ${sourceArg}`, `Check available versions:\n guild agent versions ${sourceAgentId}`);
204
+ output.error(`Error: Agent or version not found: ${identifierArg || '<identifier>'}`, `Check available versions:\n guild agent versions <agent-id>`);
179
205
  process.exit(1);
180
206
  }
181
207
  if (formattedError.code === ErrorCodes.CONN_REFUSED) {
@@ -3,7 +3,7 @@
3
3
  import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../lib/api-client.js';
5
5
  import { getAuthToken } from '../../lib/auth.js';
6
- import { getAgentId } from '../../lib/agent-helpers.js';
6
+ import { getAgentId, resolveAgentRef } from '../../lib/agent-helpers.js';
7
7
  import { handleAxiosError } from '../../lib/errors.js';
8
8
  import { createOutputWriter } from '../../lib/output.js';
9
9
  export function createAgentGetCommand() {
@@ -22,7 +22,8 @@ export function createAgentGetCommand() {
22
22
  // Get agent ID from argument or guild.json
23
23
  const { agentId } = await getAgentId(idArg);
24
24
  const client = new GuildAPIClient();
25
- const response = await client.get(`/agents/${agentId}`);
25
+ const resolvedId = await resolveAgentRef(client, agentId);
26
+ const response = await client.get(`/agents/${resolvedId}`);
26
27
  output.data(response);
27
28
  }
28
29
  catch (error) {
@@ -5,12 +5,14 @@ import { GuildAPIClient } from '../../lib/api-client.js';
5
5
  import { getAuthToken } from '../../lib/auth.js';
6
6
  import { createOutputWriter } from '../../lib/output.js';
7
7
  import { handleAxiosError } from '../../lib/errors.js';
8
+ import { loadLocalConfig } from '../../lib/guild-config.js';
8
9
  export function createAgentGrepCommand() {
9
10
  const cmd = new Command('grep');
10
11
  cmd
11
12
  .description('Search agent files for a matching pattern')
12
13
  .argument('[pattern]', 'JavaScript regex for which to search: all lines matching this pattern will be printed')
13
- .option('--published', 'Only search published agents')
14
+ .option('--all', 'Search all agents (default: current agent only)')
15
+ .option('--published', 'Only search published agents (requires --all)')
14
16
  .action(grep);
15
17
  return cmd;
16
18
  }
@@ -36,36 +38,11 @@ async function grep(patternArg, options) {
36
38
  process.exit(1);
37
39
  }
38
40
  const client = new GuildAPIClient();
39
- let offset = 0;
40
- while (true) {
41
- const params = new URLSearchParams();
42
- params.append('offset', `${offset}`);
43
- params.append('limit', `${BATCH_SIZE}`);
44
- if (options.published) {
45
- params.append('published_only', 'true');
46
- }
47
- const response = await client.get(`/agents?${params.toString()}`);
48
- await Promise.all(response.items.map(async (agent) => {
49
- let files = [];
50
- try {
51
- files = await client.get(`/agents/${agent.id}/code`);
52
- }
53
- catch (ex) {
54
- const formattedError = handleAxiosError(ex);
55
- output.error(`${agent.owner?.name}/${agent.name}: ${formattedError.details}`);
56
- return;
57
- }
58
- for (const { path, content } of files) {
59
- content.split('\n').forEach((line, lineNumber) => {
60
- if (patternRE.test(line)) {
61
- output.progress(`${agent.owner?.name}/${agent.name}/${path}:${lineNumber + 1}:${line}`);
62
- }
63
- });
64
- }
65
- }));
66
- offset += response.pagination.limit;
67
- if (!response.pagination.has_more)
68
- break;
41
+ if (options.all) {
42
+ await grepAllAgents(client, patternRE, options.published, output);
43
+ }
44
+ else {
45
+ await grepCurrentAgent(client, patternRE, output);
69
46
  }
70
47
  }
71
48
  catch (error) {
@@ -74,4 +51,57 @@ async function grep(patternArg, options) {
74
51
  process.exit(1);
75
52
  }
76
53
  }
54
+ function searchFiles(files, patternRE, prefix, output) {
55
+ for (const { path, content } of files) {
56
+ content.split('\n').forEach((line, lineNumber) => {
57
+ if (patternRE.test(line)) {
58
+ output.progress(`${prefix}${path}:${lineNumber + 1}:${line}`);
59
+ }
60
+ });
61
+ }
62
+ }
63
+ async function grepCurrentAgent(client, patternRE, output) {
64
+ const config = await loadLocalConfig();
65
+ if (!config?.agent_id) {
66
+ output.error('Not in an agent directory.', 'Either run from an agent directory with guild.json:\n cd <agent-directory>\n guild agent grep <pattern>\n\nOr search all agents:\n guild agent grep <pattern> --all');
67
+ process.exit(1);
68
+ }
69
+ let files = [];
70
+ try {
71
+ files = await client.get(`/agents/${config.agent_id}/code`);
72
+ }
73
+ catch (ex) {
74
+ const formattedError = handleAxiosError(ex);
75
+ output.error(`Failed to fetch agent code: ${formattedError.details}`);
76
+ process.exit(1);
77
+ }
78
+ searchFiles(files, patternRE, '', output);
79
+ }
80
+ async function grepAllAgents(client, patternRE, publishedOnly, output) {
81
+ let offset = 0;
82
+ while (true) {
83
+ const params = new URLSearchParams();
84
+ params.append('offset', `${offset}`);
85
+ params.append('limit', `${BATCH_SIZE}`);
86
+ if (publishedOnly) {
87
+ params.append('published_only', 'true');
88
+ }
89
+ const response = await client.get(`/agents?${params.toString()}`);
90
+ await Promise.all(response.items.map(async (agent) => {
91
+ let files = [];
92
+ try {
93
+ files = await client.get(`/agents/${agent.id}/code`);
94
+ }
95
+ catch (ex) {
96
+ const formattedError = handleAxiosError(ex);
97
+ output.error(`${agent.owner?.name}/${agent.name}: ${formattedError.details}`);
98
+ return;
99
+ }
100
+ searchFiles(files, patternRE, `${agent.owner?.name}/${agent.name}/`, output);
101
+ }));
102
+ offset += response.pagination.limit;
103
+ if (!response.pagination.has_more)
104
+ break;
105
+ }
106
+ }
77
107
  //# sourceMappingURL=grep.js.map
@@ -79,7 +79,7 @@ export function createAgentInitCommand() {
79
79
  .option('--name <name>', 'Agent name')
80
80
  .option('--template <template>', 'Agent template (LLM, AUTO_MANAGED_STATE, BLANK)')
81
81
  .option('--fork <agent-id>', 'Fork from existing agent')
82
- .option('--owner <owner-id>', 'Owner account (user or organization ID)')
82
+ .option('--owner <owner>', 'Owner (name or ID)')
83
83
  .option('--directory <path>', 'Directory to initialize (created if needed)')
84
84
  .option('--force', 'Overwrite existing guild.json', false)
85
85
  .action(async (options) => {
@@ -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 { pollUntilComplete } from '../../lib/polling.js';
8
8
  import { createOutputWriter } from '../../lib/output.js';
@@ -18,8 +18,9 @@ export function createAgentPublishCommand() {
18
18
  const client = new GuildAPIClient();
19
19
  // Resolve agent ID
20
20
  const { agentId, config } = await getAgentId(agentIdArg);
21
+ const resolvedId = await resolveAgentRef(client, agentId);
21
22
  // Fetch all versions
22
- const response = await client.get(`/agents/${agentId}/versions`);
23
+ const response = await client.get(`/agents/${resolvedId}/versions`);
23
24
  // Find latest DRAFT version
24
25
  const draftVersions = response.items
25
26
  .filter((v) => v.status === 'DRAFT')
@@ -3,6 +3,7 @@
3
3
  import { Command } from 'commander';
4
4
  import { GuildAPIClient } from '../../lib/api-client.js';
5
5
  import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
6
+ import { getOutputMode } from '../../lib/output-mode.js';
6
7
  import { createOutputWriter } from '../../lib/output.js';
7
8
  import * as fs from 'fs/promises';
8
9
  import * as path from 'path';
@@ -90,10 +91,12 @@ export function createAgentPullCommand() {
90
91
  if (errMessage.includes('no tracking information') ||
91
92
  errMessage.includes("couldn't find remote ref")) {
92
93
  output.progress('✓ Already up to date (no remote branch yet)');
93
- output.data({
94
- success: true,
95
- message: 'Already up to date (no remote branch yet)',
96
- });
94
+ if (getOutputMode() === 'json') {
95
+ output.data({
96
+ success: true,
97
+ message: 'Already up to date (no remote branch yet)',
98
+ });
99
+ }
97
100
  return;
98
101
  }
99
102
  // Unknown git error
@@ -109,22 +112,28 @@ export function createAgentPullCommand() {
109
112
  // Truly up to date — git pull + version match
110
113
  if (!gitPulledNewCommits) {
111
114
  output.progress('✓ Already up to date');
112
- output.data({ success: true, message: 'Already up to date' });
113
115
  }
114
- else {
115
- output.data({ success: true, message: 'Pulled remote changes' });
116
+ if (getOutputMode() === 'json') {
117
+ output.data({
118
+ success: true,
119
+ message: gitPulledNewCommits
120
+ ? 'Pulled remote changes'
121
+ : 'Already up to date',
122
+ });
116
123
  }
117
124
  }
118
125
  else if (latest.sha && latest.sha !== localHead) {
119
126
  // SHA mismatch — warn user
120
127
  output.progress(`⚠ Remote has a newer version (${latest.sha.slice(0, 7)}) not on this branch`);
121
128
  output.progress(' Try: git fetch origin && git log --oneline origin/main');
122
- output.data({
123
- success: true,
124
- message: 'SHA mismatch with latest version',
125
- latest_sha: latest.sha,
126
- local_sha: localHead,
127
- });
129
+ if (getOutputMode() === 'json') {
130
+ output.data({
131
+ success: true,
132
+ message: 'SHA mismatch with latest version',
133
+ latest_sha: latest.sha,
134
+ local_sha: localHead,
135
+ });
136
+ }
128
137
  }
129
138
  else {
130
139
  // Ephemeral version — download from API
@@ -142,21 +151,27 @@ export function createAgentPullCommand() {
142
151
  await fs.writeFile(filePath, file.content, 'utf-8');
143
152
  }
144
153
  output.progress(`✓ Downloaded ${files.length} files from latest draft version`);
145
- output.data({
146
- success: true,
147
- message: `Downloaded ${files.length} files from draft version`,
148
- files_updated: files.length,
149
- });
154
+ if (getOutputMode() === 'json') {
155
+ output.data({
156
+ success: true,
157
+ message: `Downloaded ${files.length} files from draft version`,
158
+ files_updated: files.length,
159
+ });
160
+ }
150
161
  }
151
162
  }
152
163
  else {
153
164
  // No versions exist yet — just report git pull result
154
165
  if (!gitPulledNewCommits) {
155
166
  output.progress('✓ Already up to date');
156
- output.data({ success: true, message: 'Already up to date' });
157
167
  }
158
- else {
159
- output.data({ success: true, message: 'Pulled remote changes' });
168
+ if (getOutputMode() === 'json') {
169
+ output.data({
170
+ success: true,
171
+ message: gitPulledNewCommits
172
+ ? 'Pulled remote changes'
173
+ : 'Already up to date',
174
+ });
160
175
  }
161
176
  }
162
177
  }
@@ -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 } from '../../lib/output.js';
9
9
  export function createAgentRevalidateCommand() {
10
10
  const cmd = new Command('revalidate');
@@ -19,10 +19,11 @@ export function createAgentRevalidateCommand() {
19
19
  const baseUrl = getGuildcoreUrl();
20
20
  const client = new GuildAPIClient({ baseUrl });
21
21
  try {
22
+ const resolvedId = await resolveAgentRef(client, agentId);
22
23
  let versionId = versionIdArg;
23
24
  // If no version ID provided, get the latest version
24
25
  if (!versionId) {
25
- const versions = await client.get(`/agents/${agentId}/versions?limit=1&offset=0`);
26
+ const versions = await client.get(`/agents/${resolvedId}/versions?limit=1&offset=0`);
26
27
  if (!versions.items || versions.items.length === 0) {
27
28
  output.error('No versions found for this agent.', `The agent may still be initializing. Check status:\n guild agent get ${agentId}`);
28
29
  process.exit(1);
@@ -30,7 +31,7 @@ export function createAgentRevalidateCommand() {
30
31
  versionId = versions.items[0].id;
31
32
  }
32
33
  // Revalidate the version
33
- const result = await client.post(`/agents/${agentId}/versions/${versionId}/revalidate`);
34
+ const result = await client.post(`/agents/${resolvedId}/versions/${versionId}/revalidate`);
34
35
  output.data(result);
35
36
  }
36
37
  catch (error) {
@@ -13,9 +13,9 @@ import { pollUntilComplete } from '../../lib/polling.js';
13
13
  export function createAgentSaveCommand() {
14
14
  const cmd = new Command('save');
15
15
  cmd
16
- .description('Push committed changes to Guild and create a version')
16
+ .description('Commit, push, and create a new agent version')
17
17
  .option('-A, --all', 'Stage all changes and commit before pushing', false)
18
- .option('--message <text>', 'Commit message (required with --all)')
18
+ .option('-m, --message <text>', 'Commit message (required with --all)')
19
19
  .option('--wait', 'Wait for validation to complete before returning', false)
20
20
  .option('--publish', 'Publish after validation passes (implies --wait)', false)
21
21
  .option('--bump [level]', 'Bump package.json version before saving (patch, or minor/major)', 'patch')
@@ -15,10 +15,10 @@ const SORT_MAP = {
15
15
  export function createAgentSearchCommand() {
16
16
  const cmd = new Command('search');
17
17
  cmd
18
- .description('Search published agents')
18
+ .description('Search agents')
19
19
  .argument('<query>', 'Search query')
20
20
  .option('--sort <field>', 'Sort by: updated, newest, name, popular (default: updated)', 'updated')
21
- .option('--all', 'Include unpublished agents')
21
+ .option('--published', 'Only show published agents')
22
22
  .option('--limit <number>', 'Number of results to return', '20')
23
23
  .option('--offset <number>', 'Offset for pagination', '0')
24
24
  .action(async (query, options) => {
@@ -34,7 +34,7 @@ export function createAgentSearchCommand() {
34
34
  params.append('search', query);
35
35
  params.append('limit', options.limit);
36
36
  params.append('offset', options.offset);
37
- if (!options.all) {
37
+ if (options.published) {
38
38
  params.append('published_only', 'true');
39
39
  }
40
40
  const sortField = SORT_MAP[options.sort];
@@ -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 createAgentTagsAddCommand() {
@@ -34,17 +34,18 @@ export function createAgentTagsAddCommand() {
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 (tagsToAdd.length === 0) {
38
39
  output.error('At least one tag is required.', 'Usage: guild agent tags add [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
  // Add new tags (deduplicate)
45
46
  const updatedTags = Array.from(new Set([...currentTags, ...tagsToAdd]));
46
47
  // Update tags
47
- await client.post(`/agents/${agentId}/tags`, { names: updatedTags });
48
+ await client.post(`/agents/${resolvedId}/tags`, { names: updatedTags });
48
49
  const agentName = config?.name || `agent ${agentId}`;
49
50
  const label = `${agentName}${config ? '' : ` (${agentId})`}`;
50
51
  output.success(`Updated tags for agent: ${label}`);