@guildai/cli 0.5.0 → 0.5.2
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/README.md +14 -8
- package/dist/commands/agent/owners.js +2 -2
- package/dist/commands/agent/save.js +1 -1
- package/dist/commands/config/set.js +2 -2
- package/dist/commands/trigger/create.js +2 -2
- package/dist/commands/workspace/agent/add.js +1 -1
- package/dist/commands/workspace/agent/remove.js +3 -3
- package/dist/commands/workspace/select.js +33 -16
- package/dist/lib/api-client.d.ts +8 -0
- package/dist/lib/api-client.js +22 -0
- package/dist/lib/api-types.d.ts +4 -4
- package/dist/lib/output.js +5 -4
- package/dist/lib/owner-helpers.js +7 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,17 +58,23 @@ guild auth status # Check authentication status
|
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
60
|
guild agent init --name my-agent # Initialize a new agent
|
|
61
|
+
guild agent clone <agent-id> # Clone agent locally
|
|
61
62
|
guild agent save # Push commits and create a version
|
|
62
63
|
guild agent save -A --message "..." # Stage+commit+push in one step
|
|
63
|
-
guild agent
|
|
64
|
-
guild agent
|
|
65
|
-
guild agent
|
|
66
|
-
guild agent
|
|
67
|
-
guild agent
|
|
68
|
-
guild agent
|
|
69
|
-
guild agent code
|
|
70
|
-
guild agent clone <agent-id> # Clone agent locally
|
|
64
|
+
guild agent pull # Pull remote changes
|
|
65
|
+
guild agent test # Test agent interactively
|
|
66
|
+
guild agent test --ephemeral # Test unsaved changes
|
|
67
|
+
guild agent chat "message" # Send a single message
|
|
68
|
+
guild agent get [agent-id] # Get agent details
|
|
69
|
+
guild agent versions [agent-id] # List versions
|
|
70
|
+
guild agent code [agent-id] # View latest published source
|
|
71
71
|
guild agent list # List all agents
|
|
72
|
+
guild agent grep <pattern> # Search agent source code
|
|
73
|
+
guild agent publish # Publish latest draft version
|
|
74
|
+
guild agent unpublish # Remove from catalog
|
|
75
|
+
guild agent revalidate # Re-run validation
|
|
76
|
+
guild agent update # Update agent metadata
|
|
77
|
+
guild agent owners # List accounts that can own agents
|
|
72
78
|
guild agent tags list # List tags
|
|
73
79
|
guild agent tags add <tag...> # Add tags
|
|
74
80
|
guild agent tags remove <tag...> # Remove tags
|
|
@@ -13,7 +13,7 @@ export function createAgentOwnersCommand() {
|
|
|
13
13
|
const client = new GuildAPIClient();
|
|
14
14
|
const [me, orgs, globalConfig] = await Promise.all([
|
|
15
15
|
client.get('/me'),
|
|
16
|
-
client.
|
|
16
|
+
client.fetchAll('/me/organizations'),
|
|
17
17
|
loadGlobalConfig(),
|
|
18
18
|
]);
|
|
19
19
|
const defaultOwnerId = globalConfig?.default_owner;
|
|
@@ -24,7 +24,7 @@ export function createAgentOwnersCommand() {
|
|
|
24
24
|
type: 'user',
|
|
25
25
|
is_default: defaultOwnerId === me.id,
|
|
26
26
|
},
|
|
27
|
-
...orgs.
|
|
27
|
+
...orgs.map((org) => ({
|
|
28
28
|
id: org.id,
|
|
29
29
|
name: org.name,
|
|
30
30
|
type: 'organization',
|
|
@@ -258,7 +258,7 @@ export function createAgentSaveCommand() {
|
|
|
258
258
|
output.progress('');
|
|
259
259
|
output.progress('Version details:');
|
|
260
260
|
output.progress(` ID: ${version.id}`);
|
|
261
|
-
output.progress(` SHA: ${version.sha.substring(0, 12)}`);
|
|
261
|
+
output.progress(` SHA: ${version.sha ? version.sha.substring(0, 12) : '-'}`);
|
|
262
262
|
output.progress(` Status: ${version.status}`);
|
|
263
263
|
if (version.published_at) {
|
|
264
264
|
output.progress(` Published at: ${version.published_at}`);
|
|
@@ -56,8 +56,8 @@ async function resolveOwnerName(ownerId) {
|
|
|
56
56
|
if (me.id === ownerId) {
|
|
57
57
|
return me.name;
|
|
58
58
|
}
|
|
59
|
-
const orgs = await client.
|
|
60
|
-
const org = orgs.
|
|
59
|
+
const orgs = await client.fetchAll('/me/organizations');
|
|
60
|
+
const org = orgs.find((o) => o.id === ownerId);
|
|
61
61
|
return org?.name;
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
@@ -50,8 +50,8 @@ export function createTriggerCreateCommand() {
|
|
|
50
50
|
}
|
|
51
51
|
const client = new GuildAPIClient();
|
|
52
52
|
// Find workspace_agent_id from agent identifier
|
|
53
|
-
const
|
|
54
|
-
const workspaceAgent =
|
|
53
|
+
const allWorkspaceAgents = await client.fetchAll(`/workspaces/${workspaceId}/workspace_agents`);
|
|
54
|
+
const workspaceAgent = allWorkspaceAgents.find((wa) => wa.agent.full_name === options.agent ||
|
|
55
55
|
wa.agent.name === options.agent ||
|
|
56
56
|
wa.agent.id === options.agent);
|
|
57
57
|
if (!workspaceAgent) {
|
|
@@ -58,7 +58,7 @@ export function createWorkspaceAgentAddCommand() {
|
|
|
58
58
|
// Display success
|
|
59
59
|
const versionDisplay = response.agent_version.version_number
|
|
60
60
|
? `v${response.agent_version.version_number}`
|
|
61
|
-
: response.agent_version.sha
|
|
61
|
+
: (response.agent_version.sha?.slice(0, 7) ?? '-');
|
|
62
62
|
const workspaceName = response.workspace?.name || 'workspace';
|
|
63
63
|
output.success(`Added ${response.agent.full_name} to workspace "${workspaceName}"`, {
|
|
64
64
|
Agent: response.agent.full_name,
|
|
@@ -30,10 +30,10 @@ export function createWorkspaceAgentRemoveCommand() {
|
|
|
30
30
|
}
|
|
31
31
|
workspaceId = resolved.workspaceId;
|
|
32
32
|
}
|
|
33
|
-
// List workspace agents to find the one to remove
|
|
34
|
-
const
|
|
33
|
+
// List all workspace agents to find the one to remove
|
|
34
|
+
const allWorkspaceAgents = await client.fetchAll(`/workspaces/${workspaceId}/workspace_agents`);
|
|
35
35
|
// Find the agent by identifier (match full_name, name, agent id, or workspace_agent id)
|
|
36
|
-
const workspaceAgent =
|
|
36
|
+
const workspaceAgent = allWorkspaceAgents.find((wa) => wa.id === agentIdentifier ||
|
|
37
37
|
wa.agent.full_name === agentIdentifier ||
|
|
38
38
|
wa.agent.name === agentIdentifier ||
|
|
39
39
|
wa.agent.id === agentIdentifier);
|
|
@@ -18,6 +18,16 @@ function formatWorkspaceDisplay(workspace) {
|
|
|
18
18
|
}
|
|
19
19
|
return base;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Match a workspace against a search argument (case-insensitive name, full_name, or exact ID).
|
|
23
|
+
*/
|
|
24
|
+
function matchesWorkspaceArg(w, arg) {
|
|
25
|
+
return (w.name === arg ||
|
|
26
|
+
w.name.toLowerCase() === arg.toLowerCase() ||
|
|
27
|
+
w.full_name === arg ||
|
|
28
|
+
w.full_name?.toLowerCase() === arg.toLowerCase() ||
|
|
29
|
+
w.id === arg);
|
|
30
|
+
}
|
|
21
31
|
export function createWorkspaceSelectCommand() {
|
|
22
32
|
const cmd = new Command('select');
|
|
23
33
|
cmd
|
|
@@ -27,24 +37,25 @@ export function createWorkspaceSelectCommand() {
|
|
|
27
37
|
const output = createOutputWriter();
|
|
28
38
|
try {
|
|
29
39
|
const client = new GuildAPIClient();
|
|
30
|
-
//
|
|
31
|
-
const workspaces = await client.get('/me/workspaces?filter=all');
|
|
32
|
-
if (workspaces.items.length === 0) {
|
|
33
|
-
output.error('No workspaces found.', 'Create a workspace first:\n guild workspace create <name>');
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
// If a workspace argument was provided, find and select it directly
|
|
40
|
+
// If a workspace argument was provided, use server-side search to find it
|
|
37
41
|
if (workspaceArg) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
// Use search param to narrow results server-side, then exact-match client-side.
|
|
43
|
+
// The backend searches only the "name" column via ILIKE, so full_name (owner/name)
|
|
44
|
+
// and ID lookups may not return results. Extract just the name part for search,
|
|
45
|
+
// and if still no match, fall back to fetching the full list.
|
|
46
|
+
const searchTerm = workspaceArg.includes('/')
|
|
47
|
+
? workspaceArg.split('/').pop()
|
|
48
|
+
: workspaceArg;
|
|
49
|
+
const searchResults = await client.get(`/me/workspaces?filter=all&search=${encodeURIComponent(searchTerm)}&limit=100`);
|
|
50
|
+
let workspace = searchResults.items.find((w) => matchesWorkspaceArg(w, workspaceArg));
|
|
51
|
+
// Search didn't find it (could be an ID lookup, or search term didn't match).
|
|
52
|
+
// Fall back to fetching all workspaces via pagination.
|
|
43
53
|
if (!workspace) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
const allWorkspaces = await client.fetchAll('/me/workspaces?filter=all');
|
|
55
|
+
workspace = allWorkspaces.find((w) => matchesWorkspaceArg(w, workspaceArg));
|
|
56
|
+
}
|
|
57
|
+
if (!workspace) {
|
|
58
|
+
output.error(`Workspace "${workspaceArg}" not found.`, 'Run: guild workspace list');
|
|
48
59
|
process.exit(1);
|
|
49
60
|
}
|
|
50
61
|
const target = await saveWorkspaceConfig(workspace.id, workspace.name);
|
|
@@ -56,6 +67,12 @@ export function createWorkspaceSelectCommand() {
|
|
|
56
67
|
}
|
|
57
68
|
return;
|
|
58
69
|
}
|
|
70
|
+
// Interactive mode: fetch workspaces for selection
|
|
71
|
+
const workspaces = await client.get('/me/workspaces?filter=all');
|
|
72
|
+
if (workspaces.items.length === 0) {
|
|
73
|
+
output.error('No workspaces found.', 'Create a workspace first:\n guild workspace create <name>');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
59
76
|
// Resolve the currently selected workspace (if any)
|
|
60
77
|
const current = await getWorkspaceId();
|
|
61
78
|
const currentIndex = current
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -50,5 +50,13 @@ export declare class GuildAPIClient {
|
|
|
50
50
|
* Make a DELETE request
|
|
51
51
|
*/
|
|
52
52
|
delete<T = unknown>(endpoint: string, config?: AxiosRequestConfig): Promise<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Fetch all items from a paginated endpoint by paging through results.
|
|
55
|
+
* Use for display commands or ID-based lookups where you need the complete list.
|
|
56
|
+
*
|
|
57
|
+
* @param endpoint - API endpoint path (may include query params)
|
|
58
|
+
* @returns Flat array of all items across all pages
|
|
59
|
+
*/
|
|
60
|
+
fetchAll<T>(endpoint: string): Promise<T[]>;
|
|
53
61
|
}
|
|
54
62
|
//# sourceMappingURL=api-client.d.ts.map
|
package/dist/lib/api-client.js
CHANGED
|
@@ -121,5 +121,27 @@ export class GuildAPIClient {
|
|
|
121
121
|
async delete(endpoint, config) {
|
|
122
122
|
return this.request('DELETE', endpoint, config);
|
|
123
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Fetch all items from a paginated endpoint by paging through results.
|
|
126
|
+
* Use for display commands or ID-based lookups where you need the complete list.
|
|
127
|
+
*
|
|
128
|
+
* @param endpoint - API endpoint path (may include query params)
|
|
129
|
+
* @returns Flat array of all items across all pages
|
|
130
|
+
*/
|
|
131
|
+
async fetchAll(endpoint) {
|
|
132
|
+
const PAGE_SIZE = 100;
|
|
133
|
+
const allItems = [];
|
|
134
|
+
let offset = 0;
|
|
135
|
+
while (true) {
|
|
136
|
+
const separator = endpoint.includes('?') ? '&' : '?';
|
|
137
|
+
const url = `${endpoint}${separator}limit=${PAGE_SIZE}&offset=${offset}`;
|
|
138
|
+
const response = await this.get(url);
|
|
139
|
+
allItems.push(...response.items);
|
|
140
|
+
offset += response.pagination.limit;
|
|
141
|
+
if (!response.pagination.has_more)
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
return allItems;
|
|
145
|
+
}
|
|
124
146
|
}
|
|
125
147
|
//# sourceMappingURL=api-client.js.map
|
package/dist/lib/api-types.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export interface WorkspaceAgent {
|
|
|
63
63
|
};
|
|
64
64
|
agent_version: {
|
|
65
65
|
id: string;
|
|
66
|
-
sha: string;
|
|
66
|
+
sha: string | null;
|
|
67
67
|
version_number: string | null;
|
|
68
68
|
};
|
|
69
69
|
workspace?: {
|
|
@@ -83,7 +83,7 @@ export interface AgentVersion {
|
|
|
83
83
|
id: string;
|
|
84
84
|
agent_id?: string;
|
|
85
85
|
author_id?: string;
|
|
86
|
-
sha: string;
|
|
86
|
+
sha: string | null;
|
|
87
87
|
summary: string;
|
|
88
88
|
status: string;
|
|
89
89
|
validation_status?: string;
|
|
@@ -170,7 +170,7 @@ export type AgentListResponse = PaginatedResponse<Agent>;
|
|
|
170
170
|
export type WorkspaceListResponse = PaginatedResponse<Workspace>;
|
|
171
171
|
export type VersionListResponse = PaginatedResponse<AgentVersion>;
|
|
172
172
|
export type ContextListResponse = PaginatedResponse<Context>;
|
|
173
|
-
export type WorkspaceAgentListResponse =
|
|
173
|
+
export type WorkspaceAgentListResponse = PaginatedResponse<WorkspaceAgent>;
|
|
174
174
|
/**
|
|
175
175
|
* Response from creating a new agent.
|
|
176
176
|
*/
|
|
@@ -227,7 +227,7 @@ export interface TriggerWorkspaceAgent {
|
|
|
227
227
|
};
|
|
228
228
|
agent_version: {
|
|
229
229
|
id: string;
|
|
230
|
-
sha: string;
|
|
230
|
+
sha: string | null;
|
|
231
231
|
version_number: string | null;
|
|
232
232
|
};
|
|
233
233
|
}
|
package/dist/lib/output.js
CHANGED
|
@@ -102,7 +102,7 @@ export function formatVersionTable(versions, pagination) {
|
|
|
102
102
|
? chalk.red
|
|
103
103
|
: chalk.dim;
|
|
104
104
|
table.addRow({
|
|
105
|
-
sha: v.sha.slice(0, 7),
|
|
105
|
+
sha: v.sha ? v.sha.slice(0, 7) : '-',
|
|
106
106
|
version: v.version_number || '-',
|
|
107
107
|
status: v.status,
|
|
108
108
|
validation: validationColor(v.validation_status || '-'),
|
|
@@ -176,7 +176,8 @@ export function formatWorkspaceAgentTable(agents) {
|
|
|
176
176
|
agents.forEach((wa) => {
|
|
177
177
|
table.addRow({
|
|
178
178
|
name: wa.agent.full_name || wa.agent.name,
|
|
179
|
-
version: wa.agent_version.version_number ||
|
|
179
|
+
version: wa.agent_version.version_number ||
|
|
180
|
+
(wa.agent_version.sha ? wa.agent_version.sha.slice(0, 7) : '-'),
|
|
180
181
|
auto_update: wa.should_autoupdate ? chalk.green('yes') : chalk.dim('no'),
|
|
181
182
|
});
|
|
182
183
|
});
|
|
@@ -238,7 +239,7 @@ export function formatSessionTable(sessions, pagination) {
|
|
|
238
239
|
});
|
|
239
240
|
sessions.forEach((session) => {
|
|
240
241
|
table.addRow({
|
|
241
|
-
id:
|
|
242
|
+
id: session.id,
|
|
242
243
|
type: session.session_type,
|
|
243
244
|
name: session.name ? truncate(session.name, 30) : '-',
|
|
244
245
|
workspace: session.workspace?.name || '',
|
|
@@ -281,7 +282,7 @@ export function formatTriggerTable(triggers, pagination) {
|
|
|
281
282
|
? chalk.dim('inactive')
|
|
282
283
|
: chalk.green('active');
|
|
283
284
|
table.addRow({
|
|
284
|
-
id:
|
|
285
|
+
id: trigger.id,
|
|
285
286
|
type: trigger.type,
|
|
286
287
|
agent: trigger.agent?.full_name || trigger.agent?.name || '',
|
|
287
288
|
status,
|
|
@@ -27,8 +27,8 @@ export async function resolveOwnerId(options) {
|
|
|
27
27
|
if (me.id === ownerFlag) {
|
|
28
28
|
return { id: me.id, name: me.name, type: 'user' };
|
|
29
29
|
}
|
|
30
|
-
const orgs = await client.
|
|
31
|
-
const org = orgs.
|
|
30
|
+
const orgs = await client.fetchAll('/me/organizations');
|
|
31
|
+
const org = orgs.find((o) => o.id === ownerFlag);
|
|
32
32
|
if (org) {
|
|
33
33
|
return { id: org.id, name: org.name, type: 'organization' };
|
|
34
34
|
}
|
|
@@ -43,8 +43,8 @@ export async function resolveOwnerId(options) {
|
|
|
43
43
|
if (me.id === envOwnerId) {
|
|
44
44
|
return { id: me.id, name: me.name, type: 'user' };
|
|
45
45
|
}
|
|
46
|
-
const orgs = await client.
|
|
47
|
-
const org = orgs.
|
|
46
|
+
const orgs = await client.fetchAll('/me/organizations');
|
|
47
|
+
const org = orgs.find((o) => o.id === envOwnerId);
|
|
48
48
|
if (org) {
|
|
49
49
|
return { id: org.id, name: org.name, type: 'organization' };
|
|
50
50
|
}
|
|
@@ -63,9 +63,9 @@ export async function resolveOwnerId(options) {
|
|
|
63
63
|
}
|
|
64
64
|
// Priority 4: Fetch user + orgs
|
|
65
65
|
const me = await client.get('/me');
|
|
66
|
-
const orgs = await client.
|
|
66
|
+
const orgs = await client.fetchAll('/me/organizations');
|
|
67
67
|
// No orgs → use current user
|
|
68
|
-
if (orgs.
|
|
68
|
+
if (orgs.length === 0) {
|
|
69
69
|
debug('No organizations found, using current user as owner');
|
|
70
70
|
return { id: me.id, name: me.name, type: 'user' };
|
|
71
71
|
}
|
|
@@ -80,7 +80,7 @@ export async function resolveOwnerId(options) {
|
|
|
80
80
|
name: `${me.name} (personal)`,
|
|
81
81
|
value: { id: me.id, name: me.name, type: 'user' },
|
|
82
82
|
},
|
|
83
|
-
...orgs.
|
|
83
|
+
...orgs.map((org) => ({
|
|
84
84
|
name: org.name,
|
|
85
85
|
value: { id: org.id, name: org.name, type: 'organization' },
|
|
86
86
|
})),
|