@guildai/cli 0.9.1 → 0.11.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.
Files changed (72) hide show
  1. package/dist/commands/agent/chat.js +10 -7
  2. package/dist/commands/agent/clone.js +2 -0
  3. package/dist/commands/agent/fork.js +3 -0
  4. package/dist/commands/agent/init.js +58 -44
  5. package/dist/commands/agent/list.js +5 -4
  6. package/dist/commands/agent/logs.d.ts +3 -0
  7. package/dist/commands/agent/logs.js +62 -0
  8. package/dist/commands/agent/owners.js +3 -3
  9. package/dist/commands/agent/pull.js +8 -12
  10. package/dist/commands/agent/save.js +5 -6
  11. package/dist/commands/agent/search.js +5 -4
  12. package/dist/commands/agent/test.js +9 -6
  13. package/dist/commands/agent/update.js +9 -1
  14. package/dist/commands/agent/versions.js +5 -4
  15. package/dist/commands/agent/workspaces.js +5 -4
  16. package/dist/commands/auth/login.js +1 -3
  17. package/dist/commands/chat.d.ts +9 -0
  18. package/dist/commands/chat.js +136 -32
  19. package/dist/commands/config/get.js +4 -4
  20. package/dist/commands/config/list.js +2 -3
  21. package/dist/commands/config/path.js +2 -3
  22. package/dist/commands/config/set.js +12 -12
  23. package/dist/commands/credentials/endpoint-list.js +5 -4
  24. package/dist/commands/credentials/list.js +5 -4
  25. package/dist/commands/credentials/policy-list.js +5 -4
  26. package/dist/commands/doctor.js +5 -5
  27. package/dist/commands/integration/connect.js +2 -2
  28. package/dist/commands/integration/create.js +2 -2
  29. package/dist/commands/integration/get.js +2 -2
  30. package/dist/commands/integration/list.js +5 -4
  31. package/dist/commands/integration/operation/create.js +4 -4
  32. package/dist/commands/integration/operation/list.js +5 -4
  33. package/dist/commands/integration/update.js +2 -2
  34. package/dist/commands/integration/version/build.js +2 -2
  35. package/dist/commands/integration/version/create.js +2 -2
  36. package/dist/commands/integration/version/get.js +2 -2
  37. package/dist/commands/integration/version/list.js +5 -4
  38. package/dist/commands/integration/version/publish.js +2 -2
  39. package/dist/commands/integration/version/test.js +2 -2
  40. package/dist/commands/job/get.js +2 -2
  41. package/dist/commands/session/create.js +1 -1
  42. package/dist/commands/session/events.js +3 -2
  43. package/dist/commands/session/list.js +5 -4
  44. package/dist/commands/session/tasks.js +5 -4
  45. package/dist/commands/setup.d.ts +16 -0
  46. package/dist/commands/setup.js +76 -46
  47. package/dist/commands/trigger/list.js +5 -4
  48. package/dist/commands/trigger/sessions.js +3 -2
  49. package/dist/commands/workspace/agent/list.js +5 -4
  50. package/dist/commands/workspace/context/list.js +5 -4
  51. package/dist/commands/workspace/list.js +5 -4
  52. package/dist/index.js +15 -4
  53. package/dist/lib/api-types.d.ts +4 -0
  54. package/dist/lib/api-types.js +4 -0
  55. package/dist/lib/auth.d.ts +1 -1
  56. package/dist/lib/auth.js +2 -2
  57. package/dist/lib/output-mode.d.ts +9 -2
  58. package/dist/lib/output-mode.js +23 -2
  59. package/dist/lib/output.d.ts +7 -1
  60. package/dist/lib/output.js +36 -5
  61. package/dist/lib/owner-helpers.d.ts +3 -0
  62. package/dist/lib/owner-helpers.js +17 -10
  63. package/dist/lib/session-events.d.ts +13 -2
  64. package/dist/lib/session-events.js +15 -1
  65. package/dist/lib/session-polling.js +9 -3
  66. package/dist/lib/session-resume.d.ts +15 -1
  67. package/dist/lib/session-resume.js +149 -16
  68. package/dist/lib/splash.js +3 -2
  69. package/dist/lib/stdin.d.ts +5 -1
  70. package/dist/lib/stdin.js +8 -1
  71. package/dist/lib/version-helpers.js +24 -8
  72. package/package.json +1 -1
@@ -79,9 +79,9 @@ const MCP_SERVER_CONFIG = {
79
79
  command: 'guild',
80
80
  args: ['mcp'],
81
81
  };
82
- async function setupMcp(options) {
82
+ async function setupMcp(targetDir, options) {
83
83
  const output = createOutputWriter();
84
- const mcpPath = path.join(process.cwd(), '.mcp.json');
84
+ const mcpPath = path.join(targetDir, '.mcp.json');
85
85
  let existing = {};
86
86
  const exists = await fileExists(mcpPath);
87
87
  if (exists) {
@@ -108,55 +108,74 @@ async function setupMcp(options) {
108
108
  }
109
109
  return 'created';
110
110
  }
111
- async function setup(options) {
111
+ /**
112
+ * Run setup in a target directory. Exported so init/clone can call it.
113
+ * When called with `quiet: true`, suppresses progress output (used as a
114
+ * post-init/clone step where the caller handles its own progress UI).
115
+ */
116
+ export async function runSetup(targetDir, options = {}) {
112
117
  const output = createOutputWriter();
113
- if (options.agentsMd && !options.codex) {
118
+ const force = options.force ?? false;
119
+ const claudeMd = options.claudeMd ?? false;
120
+ const codex = options.codex ?? false;
121
+ const agentsMd = options.agentsMd ?? false;
122
+ const mcp = options.mcp ?? true;
123
+ const quiet = options.quiet ?? false;
124
+ if (agentsMd && !codex) {
114
125
  output.error('--agents-md requires --codex', 'Create Codex setup files with:\n guild setup --codex --agents-md');
115
126
  process.exit(1);
116
127
  }
117
- if (options.claudeMd && options.codex) {
128
+ if (claudeMd && codex) {
118
129
  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');
119
130
  process.exit(1);
120
131
  }
121
- const skillFiles = options.codex ? CODEX_SKILL_FILES : CLAUDE_SKILL_FILES;
132
+ const skillFiles = codex ? CODEX_SKILL_FILES : CLAUDE_SKILL_FILES;
122
133
  // Verify source docs exist
123
134
  for (const file of skillFiles) {
124
135
  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);
136
+ if (!quiet) {
137
+ output.error('Could not find Guild CLI docs. Reinstall the CLI: npm install -g @guildai/cli');
138
+ }
139
+ return { filesCreated: 0, filesSkipped: 0 };
127
140
  }
128
141
  }
129
- output.progress('Setting up Guild CLI skills...');
130
- output.progress('');
142
+ if (!quiet) {
143
+ output.progress('Setting up Guild CLI skills...');
144
+ output.progress('');
145
+ }
131
146
  let filesCreated = 0;
132
147
  let filesSkipped = 0;
133
148
  let codexProjectFilesChanged = false;
134
149
  // Copy skill files
135
150
  for (const file of skillFiles) {
136
- const destPath = path.join(process.cwd(), file.dest);
151
+ const destPath = path.join(targetDir, file.dest);
137
152
  const exists = await fileExists(destPath);
138
- if (exists && !options.force) {
139
- output.progress(`${file.label} already exists (use --force to overwrite)`);
153
+ if (exists && !force) {
154
+ if (!quiet) {
155
+ output.progress(`${file.label} already exists (use --force to overwrite)`);
156
+ }
140
157
  filesSkipped++;
141
158
  }
142
159
  else {
143
160
  await fs.mkdir(path.dirname(destPath), { recursive: true });
144
161
  await fs.copyFile(file.src, destPath);
145
- if (exists) {
146
- output.success(`Updated ${file.label}`);
147
- }
148
- else {
149
- output.success(`Created ${file.label}`);
162
+ if (!quiet) {
163
+ if (exists) {
164
+ output.success(`Updated ${file.label}`);
165
+ }
166
+ else {
167
+ output.success(`Created ${file.label}`);
168
+ }
150
169
  }
151
170
  filesCreated++;
152
- if (options.codex) {
171
+ if (codex) {
153
172
  codexProjectFilesChanged = true;
154
173
  }
155
174
  }
156
175
  }
157
- // Handle --mcp flag
158
- if (options.mcp) {
159
- const result = await setupMcp({ force: options.force });
176
+ // Handle MCP config
177
+ if (mcp) {
178
+ const result = await setupMcp(targetDir, { force });
160
179
  if (result === 'created') {
161
180
  filesCreated++;
162
181
  }
@@ -165,53 +184,64 @@ async function setup(options) {
165
184
  }
166
185
  }
167
186
  // Handle CLAUDE.md template
168
- if (options.claudeMd) {
169
- const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
187
+ if (claudeMd) {
188
+ const claudeMdPath = path.join(targetDir, 'CLAUDE.md');
170
189
  const exists = await fileExists(claudeMdPath);
171
190
  if (exists) {
172
- output.progress('CLAUDE.md already exists (not overwriting)');
191
+ if (!quiet) {
192
+ output.progress('CLAUDE.md already exists (not overwriting)');
193
+ }
173
194
  filesSkipped++;
174
195
  }
175
196
  else {
176
197
  await fs.writeFile(claudeMdPath, CLAUDE_MD_TEMPLATE, 'utf-8');
177
- output.success('Created CLAUDE.md');
198
+ if (!quiet) {
199
+ output.success('Created CLAUDE.md');
200
+ }
178
201
  filesCreated++;
179
202
  }
180
203
  }
181
204
  // Handle AGENTS.md template for Codex setup
182
- if (options.agentsMd) {
183
- const agentsMdPath = path.join(process.cwd(), 'AGENTS.md');
205
+ if (agentsMd) {
206
+ const agentsMdPath = path.join(targetDir, 'AGENTS.md');
184
207
  const exists = await fileExists(agentsMdPath);
185
208
  if (exists) {
186
- output.progress('AGENTS.md already exists (not overwriting)');
209
+ if (!quiet) {
210
+ output.progress('AGENTS.md already exists (not overwriting)');
211
+ }
187
212
  filesSkipped++;
188
213
  }
189
214
  else {
190
215
  await fs.writeFile(agentsMdPath, AGENTS_MD_TEMPLATE, 'utf-8');
191
- output.success('Created AGENTS.md');
216
+ if (!quiet) {
217
+ output.success('Created AGENTS.md');
218
+ }
192
219
  filesCreated++;
193
220
  codexProjectFilesChanged = true;
194
221
  }
195
222
  }
196
- // Summary
197
- output.progress('');
198
- if (filesCreated > 0 && filesSkipped === 0) {
199
- if (options.force) {
200
- output.success('Guild CLI skills updated.');
223
+ // Summary (only in standalone mode)
224
+ if (!quiet) {
225
+ output.progress('');
226
+ if (filesCreated > 0 && filesSkipped === 0) {
227
+ if (force) {
228
+ output.success('Guild CLI skills updated.');
229
+ }
230
+ else {
231
+ output.success('Guild CLI skills installed. Your coding assistant can now drive agent development.');
232
+ }
233
+ }
234
+ else if (filesCreated === 0) {
235
+ output.progress('No files were modified. Use --force to overwrite existing files.');
201
236
  }
202
237
  else {
203
- output.success('Guild CLI skills installed. Your coding assistant can now drive agent development.');
238
+ output.success('Guild CLI skills installed.');
239
+ }
240
+ if (codexProjectFilesChanged) {
241
+ output.progress('Restart Codex to pick up the new project instructions.');
204
242
  }
205
243
  }
206
- else if (filesCreated === 0) {
207
- output.progress('No files were modified. Use --force to overwrite existing files.');
208
- }
209
- else {
210
- output.success('Guild CLI skills installed.');
211
- }
212
- if (codexProjectFilesChanged) {
213
- output.progress('Restart Codex to pick up the new project instructions.');
214
- }
244
+ return { filesCreated, filesSkipped };
215
245
  }
216
246
  export function createSetupCommand() {
217
247
  const cmd = new Command('setup');
@@ -223,7 +253,7 @@ export function createSetupCommand() {
223
253
  .option('--agents-md', 'With --codex, also create an AGENTS.md template in the project root', false)
224
254
  .option('--no-mcp', 'Skip MCP server configuration')
225
255
  .action(async (options) => {
226
- await setup(options);
256
+ await runSetup(process.cwd(), options);
227
257
  });
228
258
  return cmd;
229
259
  }
@@ -5,15 +5,16 @@ import { GuildAPIClient } from '../../lib/api-client.js';
5
5
  import { getAuthToken } from '../../lib/auth.js';
6
6
  import { getWorkspaceId } from '../../lib/guild-config.js';
7
7
  import { handleAxiosError } from '../../lib/errors.js';
8
- import { getOutputMode } from '../../lib/output-mode.js';
8
+ import { isMachineReadable } from '../../lib/output-mode.js';
9
9
  import { createOutputWriter, formatTriggerTable } from '../../lib/output.js';
10
+ import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
10
11
  export function createTriggerListCommand() {
11
12
  const cmd = new Command('list');
12
13
  cmd
13
14
  .description('List all triggers in a workspace')
14
15
  .option('--workspace <id>', 'Workspace ID or name')
15
- .option('--limit <number>', 'Number of results to return', '20')
16
- .option('--offset <number>', 'Offset for pagination', '0')
16
+ .option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
17
+ .option('--offset <number>', 'Offset for pagination (default: 0)', '0')
17
18
  .action(async (options) => {
18
19
  const output = createOutputWriter();
19
20
  try {
@@ -38,7 +39,7 @@ export function createTriggerListCommand() {
38
39
  params.append('limit', options.limit);
39
40
  params.append('offset', options.offset);
40
41
  const response = await client.get(`/workspaces/${workspaceId}/triggers?${params.toString()}`);
41
- if (getOutputMode() === 'json') {
42
+ if (isMachineReadable()) {
42
43
  console.log(JSON.stringify(response, null, 2));
43
44
  }
44
45
  else {
@@ -5,13 +5,14 @@ import { GuildAPIClient } from '../../lib/api-client.js';
5
5
  import { getAuthToken } from '../../lib/auth.js';
6
6
  import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
7
7
  import { createOutputWriter } from '../../lib/output.js';
8
+ import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
8
9
  export function createTriggerSessionsCommand() {
9
10
  const cmd = new Command('sessions');
10
11
  cmd
11
12
  .description('List sessions spawned by a trigger')
12
13
  .argument('<trigger-id>', 'Trigger ID')
13
- .option('--limit <number>', 'Number of results to return', '20')
14
- .option('--offset <number>', 'Offset for pagination', '0')
14
+ .option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
15
+ .option('--offset <number>', 'Offset for pagination (default: 0)', '0')
15
16
  .action(async (triggerId, options) => {
16
17
  const output = createOutputWriter();
17
18
  try {
@@ -6,15 +6,16 @@ import { getAuthToken } from '../../../lib/auth.js';
6
6
  import { getWorkspaceId } from '../../../lib/guild-config.js';
7
7
  import { handleAxiosError, ErrorCodes } from '../../../lib/errors.js';
8
8
  import { createOutputWriter, formatWorkspaceAgentTable } from '../../../lib/output.js';
9
- import { getOutputMode } from '../../../lib/output-mode.js';
9
+ import { isMachineReadable } from '../../../lib/output-mode.js';
10
10
  import { resolveWorkspaceId } from '../../../lib/workspace-helpers.js';
11
+ import { DEFAULT_PAGE_LIMIT } from '../../../lib/api-types.js';
11
12
  export function createWorkspaceAgentListCommand() {
12
13
  const cmd = new Command('list');
13
14
  cmd
14
15
  .description('List agents in a workspace')
15
16
  .option('--workspace <id>', 'Workspace ID or name')
16
- .option('--limit <number>', 'Number of results to return', '20')
17
- .option('--offset <number>', 'Offset for pagination', '0')
17
+ .option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
18
+ .option('--offset <number>', 'Offset for pagination (default: 0)', '0')
18
19
  .action(async (options) => {
19
20
  const output = createOutputWriter();
20
21
  try {
@@ -51,7 +52,7 @@ export function createWorkspaceAgentListCommand() {
51
52
  params.append('limit', options.limit);
52
53
  params.append('offset', options.offset);
53
54
  const response = await client.get(`/workspaces/${workspaceId}/workspace_agents?${params.toString()}`);
54
- if (getOutputMode() === 'json') {
55
+ if (isMachineReadable()) {
55
56
  output.data(response);
56
57
  }
57
58
  else {
@@ -3,15 +3,16 @@
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
+ import { isMachineReadable } from '../../../lib/output-mode.js';
7
7
  import { createOutputWriter, formatContextTable } from '../../../lib/output.js';
8
+ import { DEFAULT_PAGE_LIMIT } from '../../../lib/api-types.js';
8
9
  export function createWorkspaceContextListCommand() {
9
10
  const cmd = new Command('list');
10
11
  cmd
11
12
  .description('List context versions for a workspace')
12
13
  .argument('<workspace>', 'Workspace ID or full name (e.g., owner/workspace-name)')
13
- .option('--limit <number>', 'Number of results to return', '20')
14
- .option('--offset <number>', 'Offset for pagination', '0')
14
+ .option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
15
+ .option('--offset <number>', 'Offset for pagination (default: 0)', '0')
15
16
  .action(async (workspaceId, options) => {
16
17
  const output = createOutputWriter();
17
18
  try {
@@ -20,7 +21,7 @@ export function createWorkspaceContextListCommand() {
20
21
  params.append('limit', options.limit);
21
22
  params.append('offset', options.offset);
22
23
  const response = await client.get(`/workspaces/${workspaceId}/contexts?${params.toString()}`);
23
- if (getOutputMode() === 'json') {
24
+ if (isMachineReadable()) {
24
25
  output.data(response);
25
26
  }
26
27
  else {
@@ -3,14 +3,15 @@
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
+ import { isMachineReadable } from '../../lib/output-mode.js';
7
7
  import { createOutputWriter, formatWorkspaceTable } from '../../lib/output.js';
8
+ import { DEFAULT_PAGE_LIMIT } from '../../lib/api-types.js';
8
9
  export function createWorkspaceListCommand() {
9
10
  const cmd = new Command('list');
10
11
  cmd
11
12
  .description('List workspaces')
12
- .option('--limit <number>', 'Number of results to return', '20')
13
- .option('--offset <number>', 'Offset for pagination', '0')
13
+ .option('--limit <number>', `Number of results to return (default: ${DEFAULT_PAGE_LIMIT})`, String(DEFAULT_PAGE_LIMIT))
14
+ .option('--offset <number>', 'Offset for pagination (default: 0)', '0')
14
15
  .option('--owner <name>', 'Filter workspaces by owner name (case-insensitive)')
15
16
  .action(async (options) => {
16
17
  const output = createOutputWriter();
@@ -43,7 +44,7 @@ export function createWorkspaceListCommand() {
43
44
  params.append('offset', options.offset);
44
45
  response = await client.get(`/me/workspaces?${params.toString()}`);
45
46
  }
46
- if (getOutputMode() === 'json') {
47
+ if (isMachineReadable()) {
47
48
  console.log(JSON.stringify(response, null, 2));
48
49
  }
49
50
  else {
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ import { createAgentForkCommand } from './commands/agent/fork.js';
24
24
  import { createAgentPublishCommand } from './commands/agent/publish.js';
25
25
  import { createAgentUnpublishCommand } from './commands/agent/unpublish.js';
26
26
  import { createAgentRevalidateCommand } from './commands/agent/revalidate.js';
27
+ import { createAgentLogsCommand } from './commands/agent/logs.js';
27
28
  import { createAgentSearchCommand } from './commands/agent/search.js';
28
29
  import { createAgentOwnersCommand } from './commands/agent/owners.js';
29
30
  import { createAgentWorkspacesCommand } from './commands/agent/workspaces.js';
@@ -111,8 +112,11 @@ program
111
112
  .description('Guild.ai CLI - Build, test, and deploy AI agents')
112
113
  .version(packageJson.version)
113
114
  .option('--debug', 'Enable debug mode with verbose logging')
114
- .option('--json', 'Output pure JSON format (non-interactive)')
115
+ .option('--mode <format>', 'Output format: interactive (default), json, or jsonl')
116
+ // Backward compat: --json is a hidden alias for --mode json
117
+ .addOption(new Option('--json').default(false).hideHelp())
115
118
  .option('--quiet, -q', 'Suppress progress and log messages')
119
+ .option('--non-interactive', 'Disable interactive prompts (for CI, scripts, and coding agents)')
116
120
  // Dev shortcuts — hidden from help, use env vars GUILD_USE_SHARED / GUILD_USE_LOCAL instead
117
121
  .addOption(new Option('--shared').default(false).hideHelp())
118
122
  .addOption(new Option('--local').default(false).hideHelp())
@@ -135,11 +139,13 @@ program
135
139
  .argument('[prompt...]', 'Optional initial prompt (multiple words)')
136
140
  .option('--agent <identifier>', 'Agent ID or full name, e.g., foo~bar (default: assistant)')
137
141
  .option('--once', 'One-shot mode: send message, wait for response, exit (non-interactive)')
138
- .option('--mode <format>', 'Machine-readable output format: json or jsonl')
139
142
  .option('--workspace <identifier>', 'Workspace ID or full name (e.g., owner/workspace-name)')
140
143
  .option('--no-splash', 'Skip the splash screen animation')
141
144
  .option('--resume <session-id>', 'Resume an existing session')
142
145
  .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)')
146
+ // Accept --mode here so `guild chat --mode json` doesn't error.
147
+ // The actual value is read from process.argv by getOutputMode().
148
+ .addOption(new Option('--mode <format>').hideHelp())
143
149
  .addHelpText('after', '\nTo chat with a local agent under development: guild agent chat')
144
150
  .action(async (promptArgs, options) => {
145
151
  const { handleChatAction } = await import('./commands/chat.js');
@@ -170,12 +176,14 @@ agentCmd
170
176
  .argument('[prompt...]', 'Optional initial prompt for the agent')
171
177
  .option('--path <dir>', 'Path to agent directory (defaults to current directory)')
172
178
  .option('--workspace <identifier>', 'Workspace ID or full name (e.g., owner~workspace-name)')
173
- .option('--mode <format>', 'Input mode: json (one-shot) or jsonl (line-by-line)')
174
179
  .option('--agent-version <id>', 'Chat with a specific version (UUID or version number)')
175
180
  .option('--no-splash', 'Skip the splash screen animation')
176
181
  .option('--resume <session-id>', 'Resume an existing session')
177
182
  .option('--open', 'Open session in web dashboard')
178
183
  .option('--no-cache', 'Skip ephemeral build cache (force a fresh build)')
184
+ // Accept --mode here so `guild agent chat --mode json` doesn't error.
185
+ // The actual value is read from process.argv by getOutputMode().
186
+ .addOption(new Option('--mode <format>').hideHelp())
179
187
  .addHelpText('after', '\nTo chat with a published agent by name: guild chat --agent owner~agent-name')
180
188
  .action(async (promptArgs, options) => {
181
189
  const { handleAgentChatAction } = await import('./commands/agent/chat.js');
@@ -190,13 +198,15 @@ agentCmd
190
198
  .command('test')
191
199
  .description('Test agent in interactive REPL session')
192
200
  .option('--workspace <identifier>', 'Workspace ID or full name (e.g., owner/workspace-name)')
193
- .option('--mode <format>', 'Input mode: json (one-shot) or jsonl (line-by-line)')
194
201
  .option('--agent-version <id>', 'Test a specific version (UUID or version number)')
195
202
  .option('--resume <session-id>', 'Resume an existing test session')
196
203
  .option('--open', 'Open session in web dashboard')
197
204
  .option('--events <types>', 'Event types to stream (default: all). Shorthands: none, user, system, all, or comma-separated type names')
198
205
  .option('--bundle <file>', 'Path to a pre-built gzip+base64 bundle file')
199
206
  .option('--no-cache', 'Skip ephemeral build cache (force a fresh build)')
207
+ // Accept --mode here so `guild agent test --mode json` doesn't error.
208
+ // The actual value is read from process.argv by getOutputMode().
209
+ .addOption(new Option('--mode <format>').hideHelp())
200
210
  .action(async (options) => {
201
211
  const { handleAgentTestAction } = await import('./commands/agent/test.js');
202
212
  await handleAgentTestAction(options);
@@ -204,6 +214,7 @@ agentCmd
204
214
  agentCmd.addCommand(createAgentPublishCommand());
205
215
  agentCmd.addCommand(createAgentUnpublishCommand());
206
216
  agentCmd.addCommand(createAgentRevalidateCommand());
217
+ agentCmd.addCommand(createAgentLogsCommand());
207
218
  agentCmd.addCommand(createAgentSearchCommand());
208
219
  agentCmd.addCommand(createAgentOwnersCommand());
209
220
  agentCmd.addCommand(createAgentWorkspacesCommand());
@@ -159,6 +159,10 @@ export interface Pagination {
159
159
  offset: number;
160
160
  has_more: boolean;
161
161
  }
162
+ /** Default page size for standard list endpoints (matches backend). */
163
+ export declare const DEFAULT_PAGE_LIMIT = 20;
164
+ /** Default page size for high-volume endpoints (events, tasks, operations). */
165
+ export declare const DEFAULT_PAGE_LIMIT_LARGE = 100;
162
166
  /**
163
167
  * Generic paginated response wrapper.
164
168
  * All list endpoints return { items: T[], pagination: Pagination }
@@ -1,5 +1,9 @@
1
1
  // Copyright 2026 Guild.ai
2
2
  // SPDX-License-Identifier: Apache-2.0
3
+ /** Default page size for standard list endpoints (matches backend). */
4
+ export const DEFAULT_PAGE_LIMIT = 20;
5
+ /** Default page size for high-volume endpoints (events, tasks, operations). */
6
+ export const DEFAULT_PAGE_LIMIT_LARGE = 100;
3
7
  // Import and re-export generated types (from cli/scripts/sync-types-from-python.py)
4
8
  import { WEBHOOK_SERVICES, TIME_TRIGGER_FREQUENCIES, } from './generated-types.js';
5
9
  export { WEBHOOK_SERVICES, TIME_TRIGGER_FREQUENCIES, };
@@ -46,7 +46,7 @@ export declare function pollForToken(authUrl: string, code: string, interval: nu
46
46
  * @param returnLabel - Optional friendly label for return button (e.g., "VSCode")
47
47
  * @returns true if successful, false otherwise
48
48
  */
49
- export declare function login(returnUrl?: string, returnLabel?: string, nonInteractive?: boolean): Promise<boolean>;
49
+ export declare function login(returnUrl?: string, returnLabel?: string): Promise<boolean>;
50
50
  /**
51
51
  * Perform logout
52
52
  */
package/dist/lib/auth.js CHANGED
@@ -191,12 +191,12 @@ export async function pollForToken(authUrl, code, interval) {
191
191
  * @param returnLabel - Optional friendly label for return button (e.g., "VSCode")
192
192
  * @returns true if successful, false otherwise
193
193
  */
194
- export async function login(returnUrl, returnLabel, nonInteractive) {
194
+ export async function login(returnUrl, returnLabel) {
195
195
  const authUrl = getGuildcoreUrl();
196
196
  try {
197
197
  console.log(chalk.bold('\nGuild.ai Authentication'));
198
198
  const deviceCode = await startDeviceFlow(authUrl, returnUrl, returnLabel);
199
- const skipBrowser = nonInteractive || !isInteractive();
199
+ const skipBrowser = !isInteractive();
200
200
  if (skipBrowser) {
201
201
  console.log(`\nVerification code: ${deviceCode.user_code}`);
202
202
  console.log(`Open to authenticate: ${deviceCode.verification_uri_complete}\n`);
@@ -1,11 +1,18 @@
1
- export type OutputMode = 'interactive' | 'json';
1
+ export type OutputMode = 'interactive' | 'json' | 'jsonl';
2
2
  /**
3
3
  * Detect output mode from CLI flags or config
4
4
  *
5
- * Checks --json flag and config. CLI flag overrides config.
5
+ * Priority: --mode <value> > --json (backward compat) > config
6
6
  * Does NOT auto-detect pipes (user must request JSON explicitly).
7
7
  */
8
8
  export declare function getOutputMode(): OutputMode;
9
+ /**
10
+ * Check if the current output mode is machine-readable (json or jsonl).
11
+ *
12
+ * Use this in list/get commands instead of `getOutputMode() === 'json'`
13
+ * so that both --mode json and --mode jsonl trigger non-interactive output.
14
+ */
15
+ export declare function isMachineReadable(): boolean;
9
16
  /**
10
17
  * Check if quiet mode is enabled (CLI flag or config)
11
18
  *
@@ -4,21 +4,42 @@
4
4
  * Output mode detection for the CLI
5
5
  *
6
6
  * Interactive mode (default): Colors, tables, spinners, interactive
7
- * JSON mode (--json): Pure JSON, non-interactive, machine-readable
7
+ * JSON mode (--mode json or --json): Pure JSON, non-interactive, machine-readable
8
+ * JSONL mode (--mode jsonl): Line-delimited JSON for streaming
8
9
  */
9
10
  import { getConfigFlag } from './config-cache.js';
10
11
  /**
11
12
  * Detect output mode from CLI flags or config
12
13
  *
13
- * Checks --json flag and config. CLI flag overrides config.
14
+ * Priority: --mode <value> > --json (backward compat) > config
14
15
  * Does NOT auto-detect pipes (user must request JSON explicitly).
15
16
  */
16
17
  export function getOutputMode() {
18
+ // Check --mode <value> first (primary flag)
19
+ const modeIndex = process.argv.indexOf('--mode');
20
+ if (modeIndex !== -1 && modeIndex + 1 < process.argv.length) {
21
+ const value = process.argv[modeIndex + 1];
22
+ if (value === 'json' || value === 'jsonl') {
23
+ return value;
24
+ }
25
+ // --mode interactive falls through to default
26
+ }
27
+ // Backward compat: --json is equivalent to --mode json
17
28
  if (process.argv.includes('--json') || getConfigFlag('json')) {
18
29
  return 'json';
19
30
  }
20
31
  return 'interactive';
21
32
  }
33
+ /**
34
+ * Check if the current output mode is machine-readable (json or jsonl).
35
+ *
36
+ * Use this in list/get commands instead of `getOutputMode() === 'json'`
37
+ * so that both --mode json and --mode jsonl trigger non-interactive output.
38
+ */
39
+ export function isMachineReadable() {
40
+ const mode = getOutputMode();
41
+ return mode === 'json' || mode === 'jsonl';
42
+ }
22
43
  /**
23
44
  * Check if quiet mode is enabled (CLI flag or config)
24
45
  *
@@ -1,5 +1,5 @@
1
1
  import { type Spinner } from './progress.js';
2
- import type { Agent, AgentVersion, Credentials, CredentialsPolicy, Context, Integration, IntegrationVersion, JobStep, Pagination, Session, Task, Workspace, WorkspaceAgent, Trigger } from './api-types.js';
2
+ import type { Agent, AgentVersion, Credentials, CredentialsPolicy, Context, Integration, IntegrationVersion, JobStep, Pagination, Session, Task, ValidationStep, Workspace, WorkspaceAgent, Trigger } from './api-types.js';
3
3
  /**
4
4
  * Format an agent list as a human-readable table.
5
5
  * Shared by agent list and agent search commands.
@@ -57,6 +57,12 @@ export declare function formatPoliciesTable(policies: CredentialsPolicy[], pagin
57
57
  * Used by job get command.
58
58
  */
59
59
  export declare function formatJobStepTable(steps: JobStep[]): void;
60
+ /**
61
+ * Format validation step logs as human-readable output.
62
+ * Prints each step's name, colored status, and full log content.
63
+ * Used by the `guild agent logs` command.
64
+ */
65
+ export declare function formatValidationLogs(steps: ValidationStep[]): void;
60
66
  /**
61
67
  * Output writer interface for consistent CLI output
62
68
  *
@@ -195,7 +195,7 @@ export function formatVersionTable(versions, pagination) {
195
195
  ? chalk.red
196
196
  : chalk.dim;
197
197
  table.addRow({
198
- id: v.id.substring(0, 8),
198
+ id: v.id,
199
199
  version: v.version_number || '-',
200
200
  status: v.status,
201
201
  validation: validationColor(v.validation_status || '-'),
@@ -225,7 +225,7 @@ export function formatContextTable(contexts, pagination) {
225
225
  });
226
226
  contexts.forEach((ctx) => {
227
227
  table.addRow({
228
- id: truncate(ctx.id, 12),
228
+ id: ctx.id,
229
229
  status: ctx.status,
230
230
  type: ctx.type || '-',
231
231
  created: ctx.created_at ? formatRelativeTime(ctx.created_at) : '',
@@ -256,7 +256,7 @@ export function formatWorkspaceAgentTable(agents) {
256
256
  const agentUrl = wa.agent.full_name ? `${base}/agents/${wa.agent.full_name}` : '';
257
257
  table.addRow({
258
258
  name: agentUrl ? hyperlink(name, agentUrl) : name,
259
- version: wa.agent_version.version_number || wa.agent_version.id.substring(0, 8),
259
+ version: wa.agent_version.version_number || wa.agent_version.id,
260
260
  auto_update: wa.should_autoupdate ? chalk.green('yes') : chalk.dim('no'),
261
261
  });
262
262
  });
@@ -353,7 +353,7 @@ export function formatTaskTable(tasks, pagination) {
353
353
  ? chalk.yellow
354
354
  : chalk.dim;
355
355
  table.addRow({
356
- id: truncate(task.id, 13),
356
+ id: task.id,
357
357
  name,
358
358
  status: statusColor(task.status),
359
359
  tokens: task.token_usage ? task.token_usage.total_tokens.toLocaleString() : '-',
@@ -506,6 +506,35 @@ export function formatJobStepTable(steps) {
506
506
  });
507
507
  table.printTable();
508
508
  }
509
+ /**
510
+ * Format validation step logs as human-readable output.
511
+ * Prints each step's name, colored status, and full log content.
512
+ * Used by the `guild agent logs` command.
513
+ */
514
+ export function formatValidationLogs(steps) {
515
+ if (steps.length === 0) {
516
+ console.log(chalk.dim('No steps found'));
517
+ return;
518
+ }
519
+ const hr = chalk.dim('─'.repeat(60));
520
+ steps.forEach((step, index) => {
521
+ if (index > 0) {
522
+ console.log(hr);
523
+ }
524
+ const statusColor = step.status === 'SUCCEEDED'
525
+ ? chalk.green
526
+ : step.status === 'FAILED' || step.status === 'ERRORED'
527
+ ? chalk.red
528
+ : step.status === 'RUNNING'
529
+ ? chalk.yellow
530
+ : chalk.dim;
531
+ console.log(`${chalk.bold(step.name)} ${statusColor(step.status)}`);
532
+ if (step.content) {
533
+ console.log();
534
+ console.log(step.content);
535
+ }
536
+ });
537
+ }
509
538
  /**
510
539
  * Human-friendly output writer
511
540
  *
@@ -573,7 +602,9 @@ export class JSONOutputWriter {
573
602
  */
574
603
  export function createOutputWriter() {
575
604
  const mode = getOutputMode();
576
- return mode === 'json' ? new JSONOutputWriter() : new InteractiveOutputWriter();
605
+ return mode === 'interactive'
606
+ ? new InteractiveOutputWriter()
607
+ : new JSONOutputWriter();
577
608
  }
578
609
  /**
579
610
  * Create a no-op spinner (for quiet/JSON modes)
@@ -13,6 +13,9 @@ export interface ResolveOwnerOptions {
13
13
  ownerFlag?: string;
14
14
  client: GuildAPIClient;
15
15
  interactive: boolean;
16
+ /** When true, error if multiple accounts and no explicit owner in non-interactive mode.
17
+ * When false (default), fall back to current user. */
18
+ requireExplicitOwner?: boolean;
16
19
  }
17
20
  export declare function resolveOwnerId(options: ResolveOwnerOptions): Promise<OwnerChoice>;
18
21
  //# sourceMappingURL=owner-helpers.d.ts.map