@guildai/cli 0.5.9 → 0.5.11

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 (38) hide show
  1. package/README.md +28 -1
  2. package/dist/commands/agent/init.js +24 -3
  3. package/dist/commands/container/destroy.d.ts +3 -0
  4. package/dist/commands/container/destroy.js +48 -0
  5. package/dist/commands/container/events.d.ts +3 -0
  6. package/dist/commands/container/events.js +44 -0
  7. package/dist/commands/container/exec.d.ts +3 -0
  8. package/dist/commands/container/exec.js +64 -0
  9. package/dist/commands/container/get.d.ts +3 -0
  10. package/dist/commands/container/get.js +33 -0
  11. package/dist/commands/container/list.d.ts +3 -0
  12. package/dist/commands/container/list.js +48 -0
  13. package/dist/commands/container-image/create.d.ts +3 -0
  14. package/dist/commands/container-image/create.js +41 -0
  15. package/dist/commands/container-image/get.d.ts +3 -0
  16. package/dist/commands/container-image/get.js +33 -0
  17. package/dist/commands/container-image/list.d.ts +3 -0
  18. package/dist/commands/container-image/list.js +44 -0
  19. package/dist/commands/job/get.d.ts +3 -0
  20. package/dist/commands/job/get.js +44 -0
  21. package/dist/commands/job/step-get.d.ts +3 -0
  22. package/dist/commands/job/step-get.js +40 -0
  23. package/dist/commands/setup.js +11 -4
  24. package/dist/commands/trigger/create.js +4 -0
  25. package/dist/commands/trigger/update.js +4 -0
  26. package/dist/index.js +28 -0
  27. package/dist/lib/api-types.d.ts +135 -0
  28. package/dist/lib/generated-types.d.ts +1 -1
  29. package/dist/lib/generated-types.js +1 -0
  30. package/dist/lib/output.d.ts +21 -16
  31. package/dist/lib/output.js +184 -1
  32. package/dist/lib/session-events.d.ts +1 -0
  33. package/dist/lib/table.d.ts +22 -0
  34. package/dist/lib/table.js +60 -0
  35. package/docs/CLI_WORKFLOW.md +6 -0
  36. package/docs/DESIGN.md +2 -0
  37. package/docs/skills/agent-dev.md +6 -0
  38. package/package.json +2 -3
@@ -20,6 +20,7 @@ export function createTriggerUpdateCommand() {
20
20
  .option('--time <time>', 'Time of day in HH:MM format (for time triggers)')
21
21
  .option('--days-of-week <days>', 'Days of week, comma-separated (for time triggers)')
22
22
  .option('--days-of-month <days>', 'Days of month, comma-separated (for time triggers)')
23
+ .option('--minutes-of-hour <minutes>', 'Minutes of hour, comma-separated (0-59, for HOURLY triggers)')
23
24
  .option('--input <json>', 'Agent input as JSON object (for time triggers)')
24
25
  .action(async (triggerId, options) => {
25
26
  const output = createOutputWriter();
@@ -66,6 +67,9 @@ export function createTriggerUpdateCommand() {
66
67
  if (options.daysOfMonth !== undefined) {
67
68
  body.days_of_month = options.daysOfMonth;
68
69
  }
70
+ if (options.minutesOfHour !== undefined) {
71
+ body.minutes_of_hour = options.minutesOfHour;
72
+ }
69
73
  if (options.input !== undefined) {
70
74
  try {
71
75
  body.agent_input = JSON.parse(options.input);
package/dist/index.js CHANGED
@@ -60,6 +60,16 @@ import { createSessionEventsCommand } from './commands/session/events.js';
60
60
  import { createSessionTasksCommand } from './commands/session/tasks.js';
61
61
  import { createSessionCreateCommand } from './commands/session/create.js';
62
62
  import { createSessionSendCommand } from './commands/session/send.js';
63
+ import { createContainerGetCommand } from './commands/container/get.js';
64
+ import { createContainerListCommand } from './commands/container/list.js';
65
+ import { createContainerEventsCommand } from './commands/container/events.js';
66
+ import { createContainerExecCommand } from './commands/container/exec.js';
67
+ import { createContainerDestroyCommand } from './commands/container/destroy.js';
68
+ import { createContainerImageListCommand } from './commands/container-image/list.js';
69
+ import { createContainerImageGetCommand } from './commands/container-image/get.js';
70
+ import { createContainerImageCreateCommand } from './commands/container-image/create.js';
71
+ import { createJobGetCommand } from './commands/job/get.js';
72
+ import { createJobStepGetCommand } from './commands/job/step-get.js';
63
73
  import { createConfigListCommand } from './commands/config/list.js';
64
74
  import { createConfigGetCommand } from './commands/config/get.js';
65
75
  import { createConfigSetCommand } from './commands/config/set.js';
@@ -208,6 +218,20 @@ triggerCmd.addCommand(createTriggerUpdateCommand());
208
218
  triggerCmd.addCommand(createTriggerActivateCommand());
209
219
  triggerCmd.addCommand(createTriggerDeactivateCommand());
210
220
  triggerCmd.addCommand(createTriggerSessionsCommand());
221
+ // Container command group
222
+ const containerCmd = program.command('container').description('Container management');
223
+ containerCmd.addCommand(createContainerListCommand());
224
+ containerCmd.addCommand(createContainerGetCommand());
225
+ containerCmd.addCommand(createContainerEventsCommand());
226
+ containerCmd.addCommand(createContainerExecCommand());
227
+ containerCmd.addCommand(createContainerDestroyCommand());
228
+ // Container image command group
229
+ const containerImageCmd = program
230
+ .command('container-image')
231
+ .description('Container image management');
232
+ containerImageCmd.addCommand(createContainerImageCreateCommand());
233
+ containerImageCmd.addCommand(createContainerImageListCommand());
234
+ containerImageCmd.addCommand(createContainerImageGetCommand());
211
235
  // Session command group
212
236
  const sessionCmd = program.command('session').description('Session management');
213
237
  sessionCmd.addCommand(createSessionListCommand());
@@ -216,6 +240,10 @@ sessionCmd.addCommand(createSessionEventsCommand());
216
240
  sessionCmd.addCommand(createSessionTasksCommand());
217
241
  sessionCmd.addCommand(createSessionCreateCommand());
218
242
  sessionCmd.addCommand(createSessionSendCommand());
243
+ // Job command group
244
+ const jobCmd = program.command('job').description('Job management');
245
+ jobCmd.addCommand(createJobGetCommand());
246
+ jobCmd.addCommand(createJobStepGetCommand());
219
247
  // Config command group
220
248
  const configCmd = program
221
249
  .command('config')
@@ -315,6 +315,141 @@ export interface Organization {
315
315
  viewer_role: 'ADMIN' | 'MEMBER' | null;
316
316
  }
317
317
  export type OrganizationListResponse = PaginatedResponse<Organization>;
318
+ /**
319
+ * Session entity from API responses.
320
+ * Used by: session list, container list (as owner)
321
+ */
322
+ export interface Session {
323
+ id: string;
324
+ session_type: 'chat' | 'agent_test' | 'time' | 'webhook';
325
+ name?: string;
326
+ workspace?: {
327
+ id: string;
328
+ name: string;
329
+ };
330
+ created_at: string;
331
+ updated_at: string;
332
+ }
333
+ export type ContainerStatus = 'STARTING' | 'RUNNING' | 'ERRORED' | 'DESTROYED';
334
+ /**
335
+ * Container image entity from the API.
336
+ */
337
+ export interface ContainerImage {
338
+ id: string;
339
+ name: string;
340
+ image_name: string;
341
+ tag: string;
342
+ is_public: boolean;
343
+ created_at: string;
344
+ updated_at: string;
345
+ }
346
+ /**
347
+ * The actor that created the container (user or task agent).
348
+ */
349
+ export interface ContainerActor {
350
+ id: string;
351
+ entity_type: string;
352
+ name?: string;
353
+ full_name?: string;
354
+ }
355
+ /**
356
+ * Container entity from the API.
357
+ * Used by: container list
358
+ */
359
+ export interface Container {
360
+ id: string;
361
+ status: ContainerStatus;
362
+ owner: Session;
363
+ created_by: ContainerActor;
364
+ image: ContainerImage;
365
+ created_at: string;
366
+ updated_at: string;
367
+ }
368
+ export type ContainerListResponse = PaginatedResponse<Container>;
369
+ /**
370
+ * Container image as returned in list responses.
371
+ */
372
+ export interface ContainerImageListItem {
373
+ id: string;
374
+ name: string;
375
+ image_name: string;
376
+ tag: string;
377
+ is_public: boolean;
378
+ created_at: string;
379
+ updated_at: string;
380
+ }
381
+ export type ContainerImageListResponse = PaginatedResponse<ContainerImageListItem>;
382
+ export type ContainerEventStatus = 'PENDING' | 'ERROR' | 'SUCCESS';
383
+ /**
384
+ * Base fields shared by all container events.
385
+ */
386
+ export interface ContainerEventBase {
387
+ id: string;
388
+ entity_type: string;
389
+ actor: ContainerActor;
390
+ status: ContainerEventStatus;
391
+ completed_at: string | null;
392
+ error: string | null;
393
+ created_at: string;
394
+ updated_at: string;
395
+ }
396
+ export interface ContainerEventCreate extends ContainerEventBase {
397
+ entity_type: 'EntContainerEventCreate';
398
+ is_local: boolean;
399
+ }
400
+ export interface ContainerEventDestroy extends ContainerEventBase {
401
+ entity_type: 'EntContainerEventDestroy';
402
+ found: boolean | null;
403
+ }
404
+ export interface ContainerEventCommand extends ContainerEventBase {
405
+ entity_type: 'EntContainerEventCommand';
406
+ command: string;
407
+ return_code: number | null;
408
+ stdout: string | null;
409
+ stderr: string | null;
410
+ }
411
+ export type ContainerEvent = ContainerEventCreate | ContainerEventDestroy | ContainerEventCommand;
412
+ export type ContainerEventListResponse = PaginatedResponse<ContainerEvent>;
413
+ export type JobType = 'VALIDATION' | 'PUBLISH' | 'PUBLISH_PRE_CHECK';
414
+ export type JobStatus = 'PENDING' | 'RUNNING' | 'SUCCEEDED' | 'FAILED' | 'ERRORED' | 'CANCELLED';
415
+ export type JobStepStatus = 'PENDING' | 'RUNNING' | 'SUCCEEDED' | 'FAILED' | 'SKIPPED' | 'ERRORED';
416
+ /**
417
+ * Job entity from the API.
418
+ * Used by: job get
419
+ */
420
+ export interface Job {
421
+ id: string;
422
+ target_id: string;
423
+ job_type: JobType;
424
+ status: JobStatus;
425
+ started_at: string | null;
426
+ completed_at: string | null;
427
+ error_message: string | null;
428
+ created_at: string;
429
+ updated_at: string;
430
+ }
431
+ /**
432
+ * Job step entity from the API.
433
+ * Used by: job get (steps table)
434
+ */
435
+ export interface JobStep {
436
+ id: string;
437
+ job: Job;
438
+ name: string;
439
+ status: JobStepStatus;
440
+ started_at: string | null;
441
+ completed_at: string | null;
442
+ content: string | null;
443
+ created_at: string;
444
+ updated_at: string;
445
+ }
446
+ /**
447
+ * Response from GET /jobs/:id/steps.
448
+ */
449
+ export interface JobStepsResponse {
450
+ job_id: string;
451
+ steps: JobStep[];
452
+ }
318
453
  /**
319
454
  * Contents of guild.json file in agent directories.
320
455
  */
@@ -1,5 +1,5 @@
1
1
  export declare const WEBHOOK_SERVICES: readonly ["AZURE_DEVOPS", "BITBUCKET", "CYPRESS", "GITHUB", "GOOGLE_DOCS", "GOOGLE_COMPUTE", "GOOGLE_LOGGING", "JIRA", "LINEAR", "NEWRELIC", "NOTION", "SLACK", "TESTRAIL", "ZENDESK"];
2
2
  export type WebhookService = (typeof WEBHOOK_SERVICES)[number];
3
- export declare const TIME_TRIGGER_FREQUENCIES: readonly ["HOURLY", "DAILY", "WEEKLY", "MONTHLY"];
3
+ export declare const TIME_TRIGGER_FREQUENCIES: readonly ["HOURLY", "DAILY", "WEEKLY", "MONTHLY", "CRON"];
4
4
  export type TimeTriggerFrequency = (typeof TIME_TRIGGER_FREQUENCIES)[number];
5
5
  //# sourceMappingURL=generated-types.d.ts.map
@@ -29,5 +29,6 @@ export const TIME_TRIGGER_FREQUENCIES = [
29
29
  'DAILY',
30
30
  'WEEKLY',
31
31
  'MONTHLY',
32
+ 'CRON',
32
33
  ];
33
34
  //# sourceMappingURL=generated-types.js.map
@@ -1,19 +1,5 @@
1
1
  import { type Spinner } from './progress.js';
2
- import type { Agent, AgentVersion, Context, Pagination, Workspace, WorkspaceAgent, Trigger } from './api-types.js';
3
- /**
4
- * Session type from API responses
5
- */
6
- interface Session {
7
- id: string;
8
- session_type: 'chat' | 'agent_test' | 'time' | 'webhook';
9
- name?: string;
10
- workspace?: {
11
- id: string;
12
- name: string;
13
- };
14
- created_at: string;
15
- updated_at: string;
16
- }
2
+ import type { Agent, AgentVersion, Container, ContainerEvent, ContainerImageListItem, Context, JobStep, Pagination, Session, Workspace, WorkspaceAgent, Trigger } from './api-types.js';
17
3
  /**
18
4
  * Format an agent list as a human-readable table.
19
5
  * Shared by agent list and agent search commands.
@@ -49,6 +35,26 @@ export declare function formatSessionTable(sessions: Session[], pagination: Pagi
49
35
  * Used by trigger list command.
50
36
  */
51
37
  export declare function formatTriggerTable(triggers: Trigger[], pagination: Pagination): void;
38
+ /**
39
+ * Format a container list as a human-readable table.
40
+ * Used by container list command.
41
+ */
42
+ export declare function formatContainerTable(containers: Container[], pagination: Pagination): void;
43
+ /**
44
+ * Format a container image list as a human-readable table.
45
+ * Used by container-image list command.
46
+ */
47
+ export declare function formatContainerImageTable(images: ContainerImageListItem[], pagination: Pagination): void;
48
+ /**
49
+ * Format a container event list as a human-readable table.
50
+ * Used by container events command.
51
+ */
52
+ export declare function formatContainerEventTable(events: ContainerEvent[], pagination: Pagination): void;
53
+ /**
54
+ * Format job steps as a human-readable table.
55
+ * Used by job get command.
56
+ */
57
+ export declare function formatJobStepTable(steps: JobStep[]): void;
52
58
  /**
53
59
  * Output writer interface for consistent CLI output
54
60
  *
@@ -108,5 +114,4 @@ export declare class JSONOutputWriter implements OutputWriter {
108
114
  * Create output writer based on current mode
109
115
  */
110
116
  export declare function createOutputWriter(): OutputWriter;
111
- export {};
112
117
  //# sourceMappingURL=output.d.ts.map
@@ -1,7 +1,7 @@
1
1
  // Copyright 2026 Guild.ai
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import chalk from 'chalk';
4
- import { Table } from 'console-table-printer';
4
+ import { Table } from './table.js';
5
5
  import { getOutputMode, isQuietMode } from './output-mode.js';
6
6
  import { createSpinner } from './progress.js';
7
7
  import { brand, hyperlink } from './colors.js';
@@ -313,6 +313,189 @@ export function formatTriggerTable(triggers, pagination) {
313
313
  console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} triggers`));
314
314
  }
315
315
  }
316
+ /**
317
+ * Format a container list as a human-readable table.
318
+ * Used by container list command.
319
+ */
320
+ export function formatContainerTable(containers, pagination) {
321
+ if (containers.length === 0) {
322
+ console.log(chalk.dim('No containers found'));
323
+ return;
324
+ }
325
+ const table = new Table({
326
+ columns: [
327
+ { name: 'id', title: 'ID', alignment: 'left' },
328
+ { name: 'status', title: 'STATUS', alignment: 'left' },
329
+ { name: 'image', title: 'IMAGE', alignment: 'left' },
330
+ { name: 'tag', title: 'TAG', alignment: 'left' },
331
+ { name: 'created', title: 'CREATED', alignment: 'left' },
332
+ ],
333
+ });
334
+ containers.forEach((container) => {
335
+ const statusColor = container.status === 'RUNNING'
336
+ ? chalk.green
337
+ : container.status === 'ERRORED'
338
+ ? chalk.red
339
+ : container.status === 'DESTROYED'
340
+ ? chalk.dim
341
+ : chalk.yellow;
342
+ table.addRow({
343
+ id: container.id,
344
+ status: statusColor(container.status),
345
+ image: container.image?.name || '-',
346
+ tag: container.image?.tag || '-',
347
+ created: container.created_at ? formatRelativeTime(container.created_at) : '',
348
+ });
349
+ });
350
+ table.printTable();
351
+ const showing = Math.min(pagination.limit, containers.length);
352
+ if (pagination.has_more) {
353
+ const nextOffset = pagination.offset + pagination.limit;
354
+ console.log(`\nShowing ${showing} of ${pagination.total_count} containers. ` +
355
+ chalk.dim(`Use --offset ${nextOffset} to see more.`));
356
+ }
357
+ else if (pagination.total_count > showing) {
358
+ console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} containers`));
359
+ }
360
+ }
361
+ /**
362
+ * Format a container image list as a human-readable table.
363
+ * Used by container-image list command.
364
+ */
365
+ export function formatContainerImageTable(images, pagination) {
366
+ if (images.length === 0) {
367
+ console.log(chalk.dim('No container images found'));
368
+ return;
369
+ }
370
+ const table = new Table({
371
+ columns: [
372
+ { name: 'id', title: 'ID', alignment: 'left' },
373
+ { name: 'name', title: 'NAME', alignment: 'left' },
374
+ { name: 'image', title: 'IMAGE', alignment: 'left' },
375
+ { name: 'tag', title: 'TAG', alignment: 'left' },
376
+ { name: 'public', title: 'PUBLIC', alignment: 'left' },
377
+ ],
378
+ });
379
+ images.forEach((image) => {
380
+ table.addRow({
381
+ id: image.id,
382
+ name: image.name,
383
+ image: image.image_name,
384
+ tag: image.tag,
385
+ public: image.is_public ? chalk.green('yes') : chalk.dim('no'),
386
+ });
387
+ });
388
+ table.printTable();
389
+ const showing = Math.min(pagination.limit, images.length);
390
+ if (pagination.has_more) {
391
+ const nextOffset = pagination.offset + pagination.limit;
392
+ console.log(`\nShowing ${showing} of ${pagination.total_count} images. ` +
393
+ chalk.dim(`Use --offset ${nextOffset} to see more.`));
394
+ }
395
+ else if (pagination.total_count > showing) {
396
+ console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} images`));
397
+ }
398
+ }
399
+ /**
400
+ * Derive a human-readable event type label from entity_type.
401
+ */
402
+ function formatEventType(entityType) {
403
+ if (entityType === 'EntContainerEventCreate')
404
+ return 'create';
405
+ if (entityType === 'EntContainerEventDestroy')
406
+ return 'destroy';
407
+ if (entityType === 'EntContainerEventCommand')
408
+ return 'command';
409
+ return entityType;
410
+ }
411
+ /**
412
+ * Format a container event list as a human-readable table.
413
+ * Used by container events command.
414
+ */
415
+ export function formatContainerEventTable(events, pagination) {
416
+ if (events.length === 0) {
417
+ console.log(chalk.dim('No events found'));
418
+ return;
419
+ }
420
+ const table = new Table({
421
+ columns: [
422
+ { name: 'id', title: 'ID', alignment: 'left' },
423
+ { name: 'type', title: 'TYPE', alignment: 'left', color: 'cyan' },
424
+ { name: 'status', title: 'STATUS', alignment: 'left' },
425
+ { name: 'actor', title: 'ACTOR', alignment: 'left' },
426
+ { name: 'detail', title: 'DETAIL', alignment: 'left' },
427
+ { name: 'created', title: 'CREATED', alignment: 'left' },
428
+ ],
429
+ });
430
+ events.forEach((event) => {
431
+ const statusColor = event.status === 'SUCCESS'
432
+ ? chalk.green
433
+ : event.status === 'ERROR'
434
+ ? chalk.red
435
+ : chalk.yellow;
436
+ let detail = '';
437
+ if (event.entity_type === 'EntContainerEventCommand') {
438
+ detail = truncate(event.command, 30);
439
+ }
440
+ else if (event.status === 'ERROR' && event.error) {
441
+ detail = truncate(event.error, 30);
442
+ }
443
+ table.addRow({
444
+ id: event.id,
445
+ type: formatEventType(event.entity_type),
446
+ status: statusColor(event.status),
447
+ actor: event.actor?.name || event.actor?.full_name || '-',
448
+ detail,
449
+ created: event.created_at ? formatRelativeTime(event.created_at) : '',
450
+ });
451
+ });
452
+ table.printTable();
453
+ const showing = Math.min(pagination.limit, events.length);
454
+ if (pagination.has_more) {
455
+ const nextOffset = pagination.offset + pagination.limit;
456
+ console.log(`\nShowing ${showing} of ${pagination.total_count} events. ` +
457
+ chalk.dim(`Use --offset ${nextOffset} to see more.`));
458
+ }
459
+ else if (pagination.total_count > showing) {
460
+ console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} events`));
461
+ }
462
+ }
463
+ /**
464
+ * Format job steps as a human-readable table.
465
+ * Used by job get command.
466
+ */
467
+ export function formatJobStepTable(steps) {
468
+ if (steps.length === 0) {
469
+ console.log(chalk.dim('No steps found'));
470
+ return;
471
+ }
472
+ const table = new Table({
473
+ columns: [
474
+ { name: 'name', title: 'STEP', alignment: 'left' },
475
+ { name: 'status', title: 'STATUS', alignment: 'left' },
476
+ { name: 'started', title: 'STARTED', alignment: 'left' },
477
+ { name: 'completed', title: 'COMPLETED', alignment: 'left' },
478
+ ],
479
+ });
480
+ steps.forEach((step) => {
481
+ const statusColor = step.status === 'SUCCEEDED'
482
+ ? chalk.green
483
+ : step.status === 'FAILED' || step.status === 'ERRORED'
484
+ ? chalk.red
485
+ : step.status === 'RUNNING'
486
+ ? chalk.yellow
487
+ : step.status === 'SKIPPED'
488
+ ? chalk.dim
489
+ : chalk.white;
490
+ table.addRow({
491
+ name: step.name,
492
+ status: statusColor(step.status),
493
+ started: step.started_at ? formatRelativeTime(step.started_at) : '-',
494
+ completed: step.completed_at ? formatRelativeTime(step.completed_at) : '-',
495
+ });
496
+ });
497
+ table.printTable();
498
+ }
316
499
  /**
317
500
  * Human-friendly output writer
318
501
  *
@@ -85,6 +85,7 @@ export interface RuntimeWaitingEvent extends BaseEvent {
85
85
  export interface RuntimeErrorEvent extends BaseEvent {
86
86
  type: 'runtime_error';
87
87
  content: string;
88
+ stack: string | null;
88
89
  }
89
90
  export interface RuntimeDoneEvent extends BaseEvent {
90
91
  type: 'runtime_done';
@@ -0,0 +1,22 @@
1
+ interface ColumnConfig {
2
+ name: string;
3
+ title: string;
4
+ alignment?: 'left';
5
+ color?: string;
6
+ }
7
+ /**
8
+ * Minimal table renderer using string-width@7 for ANSI-aware column sizing.
9
+ * Handles OSC8 hyperlink sequences correctly (string-width uses strip-ansi@7).
10
+ */
11
+ export declare class Table {
12
+ private columns;
13
+ private rows;
14
+ constructor(config: {
15
+ columns: ColumnConfig[];
16
+ });
17
+ addRow(row: Record<string, string>): void;
18
+ render(): string;
19
+ printTable(): void;
20
+ }
21
+ export {};
22
+ //# sourceMappingURL=table.d.ts.map
@@ -0,0 +1,60 @@
1
+ // Copyright 2026 Guild.ai
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import chalk from 'chalk';
4
+ import stringWidth from 'string-width';
5
+ /**
6
+ * Minimal table renderer using string-width@7 for ANSI-aware column sizing.
7
+ * Handles OSC8 hyperlink sequences correctly (string-width uses strip-ansi@7).
8
+ */
9
+ export class Table {
10
+ columns;
11
+ rows = [];
12
+ constructor(config) {
13
+ this.columns = config.columns;
14
+ }
15
+ addRow(row) {
16
+ const sanitized = {};
17
+ for (const [k, v] of Object.entries(row)) {
18
+ sanitized[k] = v.replace(/[\r\n]+/g, ' ').trim();
19
+ }
20
+ this.rows.push(sanitized);
21
+ }
22
+ render() {
23
+ const widths = this.columns.map((col) => {
24
+ const headerWidth = stringWidth(col.title);
25
+ const maxData = this.rows.reduce((max, row) => Math.max(max, stringWidth(row[col.name] ?? '')), 0);
26
+ return Math.max(headerWidth, maxData);
27
+ });
28
+ const pad = (text, width) => {
29
+ const visible = stringWidth(text);
30
+ return visible >= width ? text : text + ' '.repeat(width - visible);
31
+ };
32
+ const top = '┌' + widths.map((w) => '─'.repeat(w + 2)).join('┬') + '┐';
33
+ const mid = '├' + widths.map((w) => '─'.repeat(w + 2)).join('┼') + '┤';
34
+ const bot = '└' + widths.map((w) => '─'.repeat(w + 2)).join('┴') + '┘';
35
+ const header = '│' +
36
+ this.columns
37
+ .map((col, i) => ' ' + chalk.bold(pad(col.title, widths[i])) + ' ')
38
+ .join('│') +
39
+ '│';
40
+ const dataRows = this.rows.map((row) => '│' +
41
+ this.columns
42
+ .map((col, i) => {
43
+ const val = row[col.name] ?? '';
44
+ const padded = pad(val, widths[i]);
45
+ if (col.color && col.color in chalk) {
46
+ return (' ' +
47
+ chalk[col.color](padded) +
48
+ ' ');
49
+ }
50
+ return ' ' + padded + ' ';
51
+ })
52
+ .join('│') +
53
+ '│');
54
+ return [top, header, mid, ...dataRows, bot].join('\n');
55
+ }
56
+ printTable() {
57
+ console.log(this.render());
58
+ }
59
+ }
60
+ //# sourceMappingURL=table.js.map
@@ -7,6 +7,12 @@ description: Agent development using the Guild CLI. Activated when user mentions
7
7
 
8
8
  For local agent development using the Guild CLI. This workflow manages agent code via the Guild git server.
9
9
 
10
+ ## MCP vs CLI
11
+
12
+ If Guild MCP tools are available (check for tools prefixed with `guild_`), use them for **read operations**: searching agents, listing workspaces, reading contexts, checking sessions, viewing credentials. MCP tools are faster and don't require shell execution.
13
+
14
+ Use the **CLI** (via Bash) for **local development operations**: `guild agent create`, `guild agent save`, `guild agent test`, `guild agent pull`, `guild agent clone`. These involve the local filesystem and git, which MCP can't do.
15
+
10
16
  ## CRITICAL: Always Use the Guild CLI
11
17
 
12
18
  **NEVER manually create agent files or use raw git commands.**
package/docs/DESIGN.md CHANGED
@@ -190,6 +190,8 @@ Environments are Docker containers managed by GuildCore. The CLI provides a simp
190
190
 
191
191
  The CLI integrates with AI coding assistants like Claude Code, Cursor, and others. Run `guild setup` to install Guild skills into your project.
192
192
 
193
+ The CLI also exposes a [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server via `guild mcp`. This gives coding assistants direct access to Guild's API — searching agents, managing workspaces, reading contexts, and starting sessions — without leaving the editor. `guild setup` configures it by default; use `--no-mcp` to skip.
194
+
193
195
  **Typical Workflow:**
194
196
 
195
197
  1. Initialize agent: `guild agent init --name my-agent --template LLM`
@@ -7,6 +7,12 @@ description: Local agent development using the Guild CLI. Activated when user me
7
7
 
8
8
  Build agents for Guild using the CLI. **Always use the Guild CLI for agent operations - never use raw git commands.**
9
9
 
10
+ ## MCP vs CLI
11
+
12
+ If Guild MCP tools are available (check for tools prefixed with `guild_`), use them for **read operations**: searching agents, listing workspaces, reading contexts, checking sessions, viewing credentials. MCP tools are faster and don't require shell execution.
13
+
14
+ Use the **CLI** (via Bash) for **local development operations**: `guild agent create`, `guild agent save`, `guild agent test`, `guild agent pull`, `guild agent clone`. These involve the local filesystem and git, which MCP can't do.
15
+
10
16
  ## When to Use This
11
17
 
12
18
  Activate when user:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guildai/cli",
3
- "version": "0.5.9",
3
+ "version": "0.5.11",
4
4
  "description": "Guild.ai CLI - Build, test, and deploy AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -59,9 +59,7 @@
59
59
  "@napi-rs/keyring": "^1.2.0",
60
60
  "axios": "^1.13.2",
61
61
  "chalk": "^5.3.0",
62
- "cli-table3": "^0.6.5",
63
62
  "commander": "^12.1.0",
64
- "console-table-printer": "^2.15.0",
65
63
  "dotenv": "^16.4.7",
66
64
  "execa": "^9.6.1",
67
65
  "ink": "^5.0.1",
@@ -76,6 +74,7 @@
76
74
  "react": "^18.3.1",
77
75
  "sharp": "^0.34.5",
78
76
  "shell-quote": "^1.8.2",
77
+ "string-width": "^7.2.0",
79
78
  "svg-pathdata": "^8.0.0",
80
79
  "svgdom": "^0.1.22",
81
80
  "ws": "^8.18.0",