@guildai/cli 0.3.17 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent/clone.js +2 -28
- package/dist/commands/agent/list.js +8 -2
- package/dist/commands/agent/save.js +7 -2
- package/dist/commands/agent/search.js +8 -2
- package/dist/commands/agent/versions.js +8 -2
- package/dist/commands/agent/workspaces.d.ts +3 -0
- package/dist/commands/agent/workspaces.js +51 -0
- package/dist/commands/workspace/agent/list.js +7 -6
- package/dist/commands/workspace/context/list.js +8 -2
- package/dist/index.js +2 -0
- package/dist/lib/agent-helpers.js +2 -2
- package/dist/lib/generated-types.d.ts +1 -1
- package/dist/lib/generated-types.js +1 -0
- package/dist/lib/npmrc.js +9 -1
- package/dist/lib/output.d.ts +18 -4
- package/dist/lib/output.js +108 -15
- package/docs/getting-started.md +1 -1
- package/docs/output-format.md +1 -1
- package/docs/skills/agent-dev.md +18 -17
- package/package.json +1 -1
|
@@ -4,25 +4,9 @@ import { GuildAPIClient } from '../../lib/api-client.js';
|
|
|
4
4
|
import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
|
|
5
5
|
import * as fs from 'fs/promises';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
-
import * as readline from 'readline';
|
|
8
7
|
import { getAuthenticatedUrl } from '../../lib/auth.js';
|
|
9
8
|
import { runGit, GitError, formatGitError } from '../../lib/git.js';
|
|
10
9
|
import { createOutputWriter } from '../../lib/output.js';
|
|
11
|
-
async function promptForDirectory(suggestedDir) {
|
|
12
|
-
const rl = readline.createInterface({
|
|
13
|
-
input: process.stdin,
|
|
14
|
-
output: process.stdout,
|
|
15
|
-
});
|
|
16
|
-
return new Promise((resolve) => {
|
|
17
|
-
rl.question(`Target directory (default: ${suggestedDir}): `, (answer) => {
|
|
18
|
-
rl.close();
|
|
19
|
-
resolve(answer.trim() || suggestedDir);
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
function isInteractive() {
|
|
24
|
-
return process.stdin.isTTY === true;
|
|
25
|
-
}
|
|
26
10
|
async function isDirectoryEmpty(dirPath) {
|
|
27
11
|
try {
|
|
28
12
|
const files = await fs.readdir(dirPath);
|
|
@@ -51,18 +35,8 @@ export function createAgentCloneCommand() {
|
|
|
51
35
|
process.exit(1);
|
|
52
36
|
}
|
|
53
37
|
output.progress(`✓ Fetched agent '${agent.name}' (${agent.id})`);
|
|
54
|
-
// Determine target directory
|
|
55
|
-
|
|
56
|
-
if (!targetDir) {
|
|
57
|
-
if (isInteractive()) {
|
|
58
|
-
const suggestedDir = `./${agent.name}`;
|
|
59
|
-
targetDir = await promptForDirectory(suggestedDir);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
output.error('Error: Target directory required in non-interactive mode', `Provide a directory:\n guild agent clone ${agentId} --directory ./my-agent\n\nOr run interactively to be prompted.`);
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
38
|
+
// Determine target directory (default to agent name, like git clone)
|
|
39
|
+
const targetDir = options.directory || agent.name;
|
|
66
40
|
// Check if directory exists and is not empty
|
|
67
41
|
const dirExists = await fs
|
|
68
42
|
.access(targetDir)
|
|
@@ -3,7 +3,8 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
4
4
|
import { getAuthToken } from '../../lib/auth.js';
|
|
5
5
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
6
|
-
import {
|
|
6
|
+
import { getOutputMode } from '../../lib/output-mode.js';
|
|
7
|
+
import { createOutputWriter, formatAgentTable } from '../../lib/output.js';
|
|
7
8
|
const SORT_MAP = {
|
|
8
9
|
updated: 'updated_at',
|
|
9
10
|
newest: 'created_at',
|
|
@@ -42,7 +43,12 @@ export function createAgentListCommand() {
|
|
|
42
43
|
params.append('sort_by', sortField);
|
|
43
44
|
}
|
|
44
45
|
const response = await client.get(`/agents?${params.toString()}`);
|
|
45
|
-
|
|
46
|
+
if (getOutputMode() === 'json') {
|
|
47
|
+
output.data(response);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
formatAgentTable(response.items, response.pagination);
|
|
51
|
+
}
|
|
46
52
|
}
|
|
47
53
|
catch (error) {
|
|
48
54
|
const formattedError = handleAxiosError(error);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
4
4
|
import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
|
|
5
|
+
import { getOutputMode } from '../../lib/output-mode.js';
|
|
5
6
|
import { createOutputWriter } from '../../lib/output.js';
|
|
6
7
|
import * as fs from 'fs/promises';
|
|
7
8
|
import * as path from 'path';
|
|
@@ -254,8 +255,12 @@ export function createAgentSaveCommand() {
|
|
|
254
255
|
output.progress('To publish this version:');
|
|
255
256
|
output.progress(' guild agent save --message "..." --publish');
|
|
256
257
|
}
|
|
257
|
-
// Output JSON to stdout
|
|
258
|
-
|
|
258
|
+
// Output JSON to stdout only in --json mode.
|
|
259
|
+
// In interactive mode the progress messages above already
|
|
260
|
+
// show version details; dumping raw JSON is noise.
|
|
261
|
+
if (getOutputMode() === 'json') {
|
|
262
|
+
output.data({ version });
|
|
263
|
+
}
|
|
259
264
|
}
|
|
260
265
|
catch (error) {
|
|
261
266
|
if (error instanceof GitError) {
|
|
@@ -3,7 +3,8 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
4
4
|
import { getAuthToken } from '../../lib/auth.js';
|
|
5
5
|
import { handleAxiosError } from '../../lib/errors.js';
|
|
6
|
-
import {
|
|
6
|
+
import { getOutputMode } from '../../lib/output-mode.js';
|
|
7
|
+
import { createOutputWriter, formatAgentTable } from '../../lib/output.js';
|
|
7
8
|
const SORT_MAP = {
|
|
8
9
|
updated: 'updated_at',
|
|
9
10
|
newest: 'created_at',
|
|
@@ -40,7 +41,12 @@ export function createAgentSearchCommand() {
|
|
|
40
41
|
params.append('sort_by', sortField);
|
|
41
42
|
}
|
|
42
43
|
const response = await client.get(`/agents?${params.toString()}`);
|
|
43
|
-
|
|
44
|
+
if (getOutputMode() === 'json') {
|
|
45
|
+
output.data(response);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
formatAgentTable(response.items, response.pagination);
|
|
49
|
+
}
|
|
44
50
|
}
|
|
45
51
|
catch (error) {
|
|
46
52
|
const formattedError = handleAxiosError(error);
|
|
@@ -4,7 +4,8 @@ import { GuildAPIClient } from '../../lib/api-client.js';
|
|
|
4
4
|
import { getGuildcoreUrl } from '../../lib/config.js';
|
|
5
5
|
import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
|
|
6
6
|
import { getAgentId } from '../../lib/agent-helpers.js';
|
|
7
|
-
import {
|
|
7
|
+
import { getOutputMode } from '../../lib/output-mode.js';
|
|
8
|
+
import { createOutputWriter, formatVersionTable } from '../../lib/output.js';
|
|
8
9
|
export function createAgentVersionsCommand() {
|
|
9
10
|
const cmd = new Command('versions');
|
|
10
11
|
cmd
|
|
@@ -22,7 +23,12 @@ export function createAgentVersionsCommand() {
|
|
|
22
23
|
const offset = parseInt(options.offset, 10);
|
|
23
24
|
try {
|
|
24
25
|
const result = await client.get(`/agents/${agentId}/versions?limit=${limit}&offset=${offset}`);
|
|
25
|
-
|
|
26
|
+
if (getOutputMode() === 'json') {
|
|
27
|
+
output.data(result);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
formatVersionTable(result.items, result.pagination);
|
|
31
|
+
}
|
|
26
32
|
}
|
|
27
33
|
catch (error) {
|
|
28
34
|
const formattedError = handleAxiosError(error);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Copyright (c) 2026 Guild.ai All Rights Reserved
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { GuildAPIClient } from '../../lib/api-client.js';
|
|
4
|
+
import { getGuildcoreUrl } from '../../lib/config.js';
|
|
5
|
+
import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
|
|
6
|
+
import { getAgentId } from '../../lib/agent-helpers.js';
|
|
7
|
+
import { createOutputWriter, formatWorkspaceTable } from '../../lib/output.js';
|
|
8
|
+
import { getOutputMode } from '../../lib/output-mode.js';
|
|
9
|
+
export function createAgentWorkspacesCommand() {
|
|
10
|
+
const cmd = new Command('workspaces');
|
|
11
|
+
cmd
|
|
12
|
+
.description('List workspaces that use an agent')
|
|
13
|
+
.argument('[identifier]', 'Agent ID or full name (e.g., owner/agent-name)')
|
|
14
|
+
.option('--limit <number>', 'Maximum number of workspaces to return', '20')
|
|
15
|
+
.option('--offset <number>', 'Number of workspaces to skip', '0')
|
|
16
|
+
.action(async (agentIdArg, options) => {
|
|
17
|
+
const output = createOutputWriter();
|
|
18
|
+
const { agentId } = await getAgentId(agentIdArg);
|
|
19
|
+
const baseUrl = getGuildcoreUrl();
|
|
20
|
+
const client = new GuildAPIClient({ baseUrl });
|
|
21
|
+
const limit = parseInt(options.limit, 10);
|
|
22
|
+
const offset = parseInt(options.offset, 10);
|
|
23
|
+
try {
|
|
24
|
+
const result = await client.get(`/agents/${agentId}/workspaces?limit=${limit}&offset=${offset}`);
|
|
25
|
+
if (getOutputMode() === 'json') {
|
|
26
|
+
output.data(result);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
formatWorkspaceTable(result.items, result.pagination);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const formattedError = handleAxiosError(error);
|
|
34
|
+
if (formattedError.code === ErrorCodes.AUTH_REQUIRED) {
|
|
35
|
+
output.error('Not logged in.', 'Please authenticate first:\n guild auth login');
|
|
36
|
+
}
|
|
37
|
+
else if (formattedError.code === ErrorCodes.CONN_REFUSED) {
|
|
38
|
+
output.error('Cannot connect to Guild servers');
|
|
39
|
+
}
|
|
40
|
+
else if (formattedError.code === ErrorCodes.NOT_FOUND) {
|
|
41
|
+
output.error(`Agent not found: ${agentId}`, 'Check the agent ID:\n guild agent list');
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
output.error(`Failed to list workspaces: ${formattedError.details}`);
|
|
45
|
+
}
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return cmd;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=workspaces.js.map
|
|
@@ -4,7 +4,8 @@ import { GuildAPIClient } from '../../../lib/api-client.js';
|
|
|
4
4
|
import { getAuthToken } from '../../../lib/auth.js';
|
|
5
5
|
import { getWorkspaceId } from '../../../lib/guild-config.js';
|
|
6
6
|
import { handleAxiosError, ErrorCodes } from '../../../lib/errors.js';
|
|
7
|
-
import { createOutputWriter } from '../../../lib/output.js';
|
|
7
|
+
import { createOutputWriter, formatWorkspaceAgentTable } from '../../../lib/output.js';
|
|
8
|
+
import { getOutputMode } from '../../../lib/output-mode.js';
|
|
8
9
|
export function createWorkspaceAgentListCommand() {
|
|
9
10
|
const cmd = new Command('list');
|
|
10
11
|
cmd
|
|
@@ -36,12 +37,12 @@ export function createWorkspaceAgentListCommand() {
|
|
|
36
37
|
params.append('limit', options.limit);
|
|
37
38
|
params.append('offset', options.offset);
|
|
38
39
|
const response = await client.get(`/workspaces/${workspaceId}/workspace_agents?${params.toString()}`);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
if (getOutputMode() === 'json') {
|
|
41
|
+
output.data(response);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
formatWorkspaceAgentTable(response.items);
|
|
43
45
|
}
|
|
44
|
-
output.data(response);
|
|
45
46
|
}
|
|
46
47
|
catch (error) {
|
|
47
48
|
const formattedError = handleAxiosError(error);
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { GuildAPIClient } from '../../../lib/api-client.js';
|
|
4
4
|
import { handleAxiosError, ErrorCodes } from '../../../lib/errors.js';
|
|
5
|
-
import {
|
|
5
|
+
import { getOutputMode } from '../../../lib/output-mode.js';
|
|
6
|
+
import { createOutputWriter, formatContextTable } from '../../../lib/output.js';
|
|
6
7
|
export function createWorkspaceContextListCommand() {
|
|
7
8
|
const cmd = new Command('list');
|
|
8
9
|
cmd
|
|
@@ -18,7 +19,12 @@ export function createWorkspaceContextListCommand() {
|
|
|
18
19
|
params.append('limit', options.limit);
|
|
19
20
|
params.append('offset', options.offset);
|
|
20
21
|
const response = await client.get(`/workspaces/${workspaceId}/contexts?${params.toString()}`);
|
|
21
|
-
|
|
22
|
+
if (getOutputMode() === 'json') {
|
|
23
|
+
output.data(response);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
formatContextTable(response.items, response.pagination);
|
|
27
|
+
}
|
|
22
28
|
}
|
|
23
29
|
catch (error) {
|
|
24
30
|
const formattedError = handleAxiosError(error);
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ import { createAgentUnpublishCommand } from './commands/agent/unpublish.js';
|
|
|
28
28
|
import { createAgentRevalidateCommand } from './commands/agent/revalidate.js';
|
|
29
29
|
import { createAgentSearchCommand } from './commands/agent/search.js';
|
|
30
30
|
import { createAgentOwnersCommand } from './commands/agent/owners.js';
|
|
31
|
+
import { createAgentWorkspacesCommand } from './commands/agent/workspaces.js';
|
|
31
32
|
import { createAgentTagsListCommand } from './commands/agent/tags/list.js';
|
|
32
33
|
import { createAgentTagsAddCommand } from './commands/agent/tags/add.js';
|
|
33
34
|
import { createAgentTagsRemoveCommand } from './commands/agent/tags/remove.js';
|
|
@@ -131,6 +132,7 @@ agentCmd.addCommand(createAgentUnpublishCommand());
|
|
|
131
132
|
agentCmd.addCommand(createAgentRevalidateCommand());
|
|
132
133
|
agentCmd.addCommand(createAgentSearchCommand());
|
|
133
134
|
agentCmd.addCommand(createAgentOwnersCommand());
|
|
135
|
+
agentCmd.addCommand(createAgentWorkspacesCommand());
|
|
134
136
|
// Agent tags subcommand group
|
|
135
137
|
const tagsCmd = agentCmd.command('tags').description('Manage agent tags');
|
|
136
138
|
tagsCmd.addCommand(createAgentTagsListCommand());
|
|
@@ -66,8 +66,8 @@ export async function readAgentFiles(cwd) {
|
|
|
66
66
|
const content = await fs.readFile(fullPath, 'utf-8');
|
|
67
67
|
files.push({ path: filePath, content });
|
|
68
68
|
}
|
|
69
|
-
const
|
|
70
|
-
const missing = REQUIRED_AGENT_FILES.filter((
|
|
69
|
+
const filePaths = files.map((f) => f.path);
|
|
70
|
+
const missing = REQUIRED_AGENT_FILES.filter((req) => !filePaths.some((fp) => fp === req || fp.endsWith(`/${req}`)));
|
|
71
71
|
if (missing.length > 0) {
|
|
72
72
|
throw new Error(`Missing required files: ${missing.join(', ')}`);
|
|
73
73
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const WEBHOOK_SERVICES: readonly ["AZURE_DEVOPS", "BITBUCKET", "CYPRESS", "GITHUB", "GOOGLE_DOCS", "JIRA", "LINEAR", "NEWRELIC", "NOTION", "SLACK", "TESTRAIL", "ZENDESK"];
|
|
1
|
+
export declare const WEBHOOK_SERVICES: readonly ["AZURE_DEVOPS", "BITBUCKET", "CYPRESS", "GITHUB", "GOOGLE_DOCS", "GOOGLE_LOGGING", "JIRA", "LINEAR", "NEWRELIC", "NOTION", "SLACK", "TESTRAIL", "ZENDESK"];
|
|
2
2
|
export type WebhookService = (typeof WEBHOOK_SERVICES)[number];
|
|
3
3
|
export declare const TIME_TRIGGER_FREQUENCIES: readonly ["HOURLY", "DAILY", "WEEKLY", "MONTHLY"];
|
|
4
4
|
export type TimeTriggerFrequency = (typeof TIME_TRIGGER_FREQUENCIES)[number];
|
package/dist/lib/npmrc.js
CHANGED
|
@@ -17,6 +17,7 @@ export async function configureNpmrc() {
|
|
|
17
17
|
}
|
|
18
18
|
try {
|
|
19
19
|
await execa('npm', [
|
|
20
|
+
'--workspaces=false',
|
|
20
21
|
'config',
|
|
21
22
|
'set',
|
|
22
23
|
'--location',
|
|
@@ -36,7 +37,14 @@ export async function cleanupNpmrc() {
|
|
|
36
37
|
const keys = [...SCOPES.map((s) => `${s}:registry`), `${scope}:_authToken`];
|
|
37
38
|
for (const key of keys) {
|
|
38
39
|
try {
|
|
39
|
-
await execa('npm', [
|
|
40
|
+
await execa('npm', [
|
|
41
|
+
'--workspaces=false',
|
|
42
|
+
'config',
|
|
43
|
+
'delete',
|
|
44
|
+
'--location',
|
|
45
|
+
'user',
|
|
46
|
+
key,
|
|
47
|
+
]);
|
|
40
48
|
}
|
|
41
49
|
catch {
|
|
42
50
|
// Key may not exist, that's fine
|
package/dist/lib/output.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Spinner } from './progress.js';
|
|
2
|
-
import type { Agent, Pagination, Workspace, Trigger } from './api-types.js';
|
|
2
|
+
import type { Agent, AgentVersion, Context, Pagination, Workspace, WorkspaceAgent, Trigger } from './api-types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Session type from API responses
|
|
5
5
|
*/
|
|
@@ -19,6 +19,21 @@ interface Session {
|
|
|
19
19
|
* Shared by agent list and agent search commands.
|
|
20
20
|
*/
|
|
21
21
|
export declare function formatAgentTable(agents: Agent[], pagination: Pagination): void;
|
|
22
|
+
/**
|
|
23
|
+
* Format an agent version list as a human-readable table.
|
|
24
|
+
* Used by agent versions command.
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatVersionTable(versions: AgentVersion[], pagination: Pagination): void;
|
|
27
|
+
/**
|
|
28
|
+
* Format a context list as a human-readable table.
|
|
29
|
+
* Used by workspace context list command.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatContextTable(contexts: Context[], pagination: Pagination): void;
|
|
32
|
+
/**
|
|
33
|
+
* Format a workspace agent list as a human-readable table.
|
|
34
|
+
* Used by workspace agent list command.
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatWorkspaceAgentTable(agents: WorkspaceAgent[]): void;
|
|
22
37
|
/**
|
|
23
38
|
* Format a workspace list as a human-readable table.
|
|
24
39
|
* Used by workspace list command.
|
|
@@ -38,7 +53,7 @@ export declare function formatTriggerTable(triggers: Trigger[], pagination: Pagi
|
|
|
38
53
|
* Output writer interface for consistent CLI output
|
|
39
54
|
*
|
|
40
55
|
* Implementations:
|
|
41
|
-
* -
|
|
56
|
+
* - InteractiveOutputWriter: Colors, tables, spinners for interactive use
|
|
42
57
|
* - JSONOutputWriter: Pure JSON for scripting and automation
|
|
43
58
|
*/
|
|
44
59
|
export interface OutputWriter {
|
|
@@ -69,9 +84,8 @@ export interface OutputWriter {
|
|
|
69
84
|
* Uses colors, symbols, and formatting for readability.
|
|
70
85
|
* Progress goes to stderr.
|
|
71
86
|
*/
|
|
72
|
-
export declare class
|
|
87
|
+
export declare class InteractiveOutputWriter implements OutputWriter {
|
|
73
88
|
data(value: unknown): void;
|
|
74
|
-
private isAgentListResponse;
|
|
75
89
|
success(message: string, details?: Record<string, unknown>): void;
|
|
76
90
|
error(message: string, details?: string): void;
|
|
77
91
|
progress(message: string): void;
|
package/dist/lib/output.js
CHANGED
|
@@ -76,6 +76,112 @@ export function formatAgentTable(agents, pagination) {
|
|
|
76
76
|
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} agents`));
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Format an agent version list as a human-readable table.
|
|
81
|
+
* Used by agent versions command.
|
|
82
|
+
*/
|
|
83
|
+
export function formatVersionTable(versions, pagination) {
|
|
84
|
+
if (versions.length === 0) {
|
|
85
|
+
console.log(chalk.dim('No versions found'));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const table = new Table({
|
|
89
|
+
columns: [
|
|
90
|
+
{ name: 'sha', title: 'SHA', alignment: 'left' },
|
|
91
|
+
{ name: 'version', title: 'VERSION', alignment: 'left', color: 'cyan' },
|
|
92
|
+
{ name: 'status', title: 'STATUS', alignment: 'left' },
|
|
93
|
+
{ name: 'validation', title: 'VALIDATION', alignment: 'left' },
|
|
94
|
+
{ name: 'summary', title: 'SUMMARY', alignment: 'left' },
|
|
95
|
+
{ name: 'created', title: 'CREATED', alignment: 'left' },
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
versions.forEach((v) => {
|
|
99
|
+
const validationColor = v.validation_status === 'PASSED'
|
|
100
|
+
? chalk.green
|
|
101
|
+
: v.validation_status === 'FAILED'
|
|
102
|
+
? chalk.red
|
|
103
|
+
: chalk.dim;
|
|
104
|
+
table.addRow({
|
|
105
|
+
sha: v.sha.slice(0, 7),
|
|
106
|
+
version: v.version_number || '-',
|
|
107
|
+
status: v.status,
|
|
108
|
+
validation: validationColor(v.validation_status || '-'),
|
|
109
|
+
summary: truncate(v.summary || '', 30),
|
|
110
|
+
created: v.created_at ? formatRelativeTime(v.created_at) : '',
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
table.printTable();
|
|
114
|
+
const showing = Math.min(pagination.limit, versions.length);
|
|
115
|
+
if (pagination.has_more) {
|
|
116
|
+
const nextOffset = pagination.offset + pagination.limit;
|
|
117
|
+
console.log(`\nShowing ${showing} of ${pagination.total_count} versions. ` +
|
|
118
|
+
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
119
|
+
}
|
|
120
|
+
else if (pagination.total_count > showing) {
|
|
121
|
+
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} versions`));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Format a context list as a human-readable table.
|
|
126
|
+
* Used by workspace context list command.
|
|
127
|
+
*/
|
|
128
|
+
export function formatContextTable(contexts, pagination) {
|
|
129
|
+
if (contexts.length === 0) {
|
|
130
|
+
console.log(chalk.dim('No contexts found'));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const table = new Table({
|
|
134
|
+
columns: [
|
|
135
|
+
{ name: 'id', title: 'ID', alignment: 'left' },
|
|
136
|
+
{ name: 'status', title: 'STATUS', alignment: 'left', color: 'cyan' },
|
|
137
|
+
{ name: 'type', title: 'TYPE', alignment: 'left' },
|
|
138
|
+
{ name: 'created', title: 'CREATED', alignment: 'left' },
|
|
139
|
+
],
|
|
140
|
+
});
|
|
141
|
+
contexts.forEach((ctx) => {
|
|
142
|
+
table.addRow({
|
|
143
|
+
id: truncate(ctx.id, 12),
|
|
144
|
+
status: ctx.status,
|
|
145
|
+
type: ctx.type || '-',
|
|
146
|
+
created: ctx.created_at ? formatRelativeTime(ctx.created_at) : '',
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
table.printTable();
|
|
150
|
+
const showing = Math.min(pagination.limit, contexts.length);
|
|
151
|
+
if (pagination.has_more) {
|
|
152
|
+
const nextOffset = pagination.offset + pagination.limit;
|
|
153
|
+
console.log(`\nShowing ${showing} of ${pagination.total_count} contexts. ` +
|
|
154
|
+
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
155
|
+
}
|
|
156
|
+
else if (pagination.total_count > showing) {
|
|
157
|
+
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} contexts`));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Format a workspace agent list as a human-readable table.
|
|
162
|
+
* Used by workspace agent list command.
|
|
163
|
+
*/
|
|
164
|
+
export function formatWorkspaceAgentTable(agents) {
|
|
165
|
+
if (agents.length === 0) {
|
|
166
|
+
console.log(chalk.dim('No agents installed in this workspace'));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const table = new Table({
|
|
170
|
+
columns: [
|
|
171
|
+
{ name: 'name', title: 'NAME', alignment: 'left' },
|
|
172
|
+
{ name: 'version', title: 'VERSION', alignment: 'left', color: 'cyan' },
|
|
173
|
+
{ name: 'auto_update', title: 'AUTO-UPDATE', alignment: 'left' },
|
|
174
|
+
],
|
|
175
|
+
});
|
|
176
|
+
agents.forEach((wa) => {
|
|
177
|
+
table.addRow({
|
|
178
|
+
name: wa.agent.full_name || wa.agent.name,
|
|
179
|
+
version: wa.agent_version.version_number || wa.agent_version.sha.slice(0, 7),
|
|
180
|
+
auto_update: wa.should_autoupdate ? chalk.green('yes') : chalk.dim('no'),
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
table.printTable();
|
|
184
|
+
}
|
|
79
185
|
/**
|
|
80
186
|
* Format a workspace list as a human-readable table.
|
|
81
187
|
* Used by workspace list command.
|
|
@@ -199,23 +305,10 @@ export function formatTriggerTable(triggers, pagination) {
|
|
|
199
305
|
* Uses colors, symbols, and formatting for readability.
|
|
200
306
|
* Progress goes to stderr.
|
|
201
307
|
*/
|
|
202
|
-
export class
|
|
308
|
+
export class InteractiveOutputWriter {
|
|
203
309
|
data(value) {
|
|
204
|
-
// Special handling for agent list responses
|
|
205
|
-
if (this.isAgentListResponse(value)) {
|
|
206
|
-
formatAgentTable(value.items, value.pagination);
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
// Fallback to pretty JSON for other data
|
|
210
310
|
console.log(JSON.stringify(value, null, 2));
|
|
211
311
|
}
|
|
212
|
-
isAgentListResponse(value) {
|
|
213
|
-
return (typeof value === 'object' &&
|
|
214
|
-
value !== null &&
|
|
215
|
-
'items' in value &&
|
|
216
|
-
'pagination' in value &&
|
|
217
|
-
Array.isArray(value.items));
|
|
218
|
-
}
|
|
219
312
|
success(message, details) {
|
|
220
313
|
process.stderr.write(chalk.green('✓') + ' ' + message + '\n');
|
|
221
314
|
if (details) {
|
|
@@ -273,7 +366,7 @@ export class JSONOutputWriter {
|
|
|
273
366
|
*/
|
|
274
367
|
export function createOutputWriter() {
|
|
275
368
|
const mode = getOutputMode();
|
|
276
|
-
return mode === 'json' ? new JSONOutputWriter() : new
|
|
369
|
+
return mode === 'json' ? new JSONOutputWriter() : new InteractiveOutputWriter();
|
|
277
370
|
}
|
|
278
371
|
/**
|
|
279
372
|
* Create a no-op spinner (for quiet/JSON modes)
|
package/docs/getting-started.md
CHANGED
|
@@ -316,7 +316,7 @@ guild agent code # View source of latest version
|
|
|
316
316
|
|
|
317
317
|
## Key Rules
|
|
318
318
|
|
|
319
|
-
- Agent code lives
|
|
319
|
+
- Agent code lives in `agent.ts` (typically at the project root, but can be in a subdirectory like `src/`).
|
|
320
320
|
- Don't add `@guildai/agents-sdk`, `zod`, or `@guildai-services/*` to `package.json`. The runtime provides them. Only add third-party packages you actually use.
|
|
321
321
|
- Always call tools through `task.tools.<name>(args)`. Never access services directly.
|
|
322
322
|
- Always use `guild agent save` to commit and `guild agent pull` to sync. Don't use raw git commands.
|
package/docs/output-format.md
CHANGED
|
@@ -46,7 +46,7 @@ interface OutputWriter {
|
|
|
46
46
|
|
|
47
47
|
Two implementations:
|
|
48
48
|
|
|
49
|
-
- `
|
|
49
|
+
- `InteractiveOutputWriter` - Colors, symbols, formatted output
|
|
50
50
|
- `JSONOutputWriter` - Pure JSON
|
|
51
51
|
|
|
52
52
|
Commands use `createOutputWriter()` to get the right implementation based on flags.
|
package/docs/skills/agent-dev.md
CHANGED
|
@@ -489,10 +489,23 @@ async function onToolResults(
|
|
|
489
489
|
|
|
490
490
|
### Slack-Specific Patterns
|
|
491
491
|
|
|
492
|
-
When posting to Slack, convert markdown to Slack's mrkdwn format
|
|
492
|
+
When posting to Slack, convert markdown to Slack's mrkdwn format. Use an inline converter
|
|
493
|
+
(`slackify-markdown` is CJS and breaks in the ESM agent runtime):
|
|
493
494
|
|
|
494
495
|
```typescript
|
|
495
|
-
|
|
496
|
+
// Simple markdown-to-Slack-mrkdwn converter (inline — do NOT use slackify-markdown)
|
|
497
|
+
function slackifyMarkdown(md: string): string {
|
|
498
|
+
return md
|
|
499
|
+
.replace(/\*\*(.+?)\*\*/g, '*$1*') // bold: **text** → *text*
|
|
500
|
+
.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, '_$1_') // italic: *text* → _text_
|
|
501
|
+
.replace(/~~(.+?)~~/g, '~$1~') // strikethrough
|
|
502
|
+
.replace(/^### (.+)$/gm, '*$1*') // h3 → bold
|
|
503
|
+
.replace(/^## (.+)$/gm, '*$1*') // h2 → bold
|
|
504
|
+
.replace(/^# (.+)$/gm, '*$1*') // h1 → bold
|
|
505
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<$2|$1>') // links
|
|
506
|
+
.replace(/^> (.+)$/gm, '> $1') // blockquotes (same syntax)
|
|
507
|
+
.replace(/`([^`]+)`/g, '`$1`'); // inline code (same syntax)
|
|
508
|
+
}
|
|
496
509
|
|
|
497
510
|
// In your agent:
|
|
498
511
|
const responseText = '## Summary\n- Item 1\n- Item 2';
|
|
@@ -504,16 +517,6 @@ await task.tools.slack_chat_post_message({
|
|
|
504
517
|
});
|
|
505
518
|
```
|
|
506
519
|
|
|
507
|
-
Add `slackify-markdown` to `package.json` dependencies:
|
|
508
|
-
|
|
509
|
-
```json
|
|
510
|
-
{
|
|
511
|
-
"dependencies": {
|
|
512
|
-
"slackify-markdown": "^4.5.0"
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
```
|
|
516
|
-
|
|
517
520
|
---
|
|
518
521
|
|
|
519
522
|
## Anti-Hallucination Guide
|
|
@@ -620,9 +623,7 @@ export default agent({ run: async (input, task) => { ... } })
|
|
|
620
623
|
"version": "1.0.0",
|
|
621
624
|
"author": "Guild.ai",
|
|
622
625
|
"type": "module",
|
|
623
|
-
"dependencies": {
|
|
624
|
-
"slackify-markdown": "^4.5.0"
|
|
625
|
-
},
|
|
626
|
+
"dependencies": {},
|
|
626
627
|
"devDependencies": {
|
|
627
628
|
"typescript": "^5.0.0"
|
|
628
629
|
}
|
|
@@ -632,7 +633,7 @@ export default agent({ run: async (input, task) => { ... } })
|
|
|
632
633
|
**Important:**
|
|
633
634
|
|
|
634
635
|
- Do NOT add `@guildai/agents-sdk`, `@guildai-services/*`, or `zod` to dependencies. The runtime provides them.
|
|
635
|
-
- DO add third-party packages your agent uses (e.g., `slackify-markdown`)
|
|
636
|
+
- DO add third-party ESM-compatible packages your agent uses to `dependencies`. Note: CJS-only packages (e.g., `slackify-markdown`) will break in the ESM agent runtime — use inline alternatives instead.
|
|
636
637
|
- `devDependencies` is for build tools only.
|
|
637
638
|
|
|
638
639
|
## Versioning
|
|
@@ -649,7 +650,7 @@ After `guild agent create` + `guild agent init`:
|
|
|
649
650
|
my-agent/
|
|
650
651
|
├── .git/ # Git repo (remote is Guild server)
|
|
651
652
|
├── .gitignore # Includes guild.json
|
|
652
|
-
├── agent.ts # Your agent code (
|
|
653
|
+
├── agent.ts # Your agent code (default location; can also be in src/)
|
|
653
654
|
├── package.json # Dependencies
|
|
654
655
|
├── tsconfig.json # TypeScript config
|
|
655
656
|
└── guild.json # Agent ID (gitignored, local only)
|