runwork 0.4.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-types/core-agent.d.ts +8 -0
- package/bundled-types/core-base-agent.d.ts +4 -0
- package/bundled-types/core-types.d.ts +101 -0
- package/bundled-types/core-workspace.d.ts +10 -0
- package/bundled-types/index.d.ts +2 -0
- package/bundled-types/shared/core-types.d.ts +101 -0
- package/bundled-types/shared/shared/core-types.d.ts +101 -0
- package/bundled-types/task-delegation/index.d.ts +50 -0
- package/bundled-types/task-delegation/sandbox-bridge.d.ts +88 -0
- package/bundled-types/task-delegation/session-manager.d.ts +86 -0
- package/bundled-types/task-delegation/stream-parser.d.ts +25 -0
- package/bundled-types/task-delegation/task-delegation/index.d.ts +30 -0
- package/bundled-types/task-delegation/task-delegation/sandbox-bridge.d.ts +88 -0
- package/bundled-types/task-delegation/task-delegation/session-manager.d.ts +86 -0
- package/bundled-types/task-delegation/task-delegation/stream-parser.d.ts +25 -0
- package/bundled-types/task-delegation/task-delegation/types.d.ts +165 -0
- package/bundled-types/task-delegation/types.d.ts +336 -0
- package/bundled-types/task-delegation.d.ts +2 -0
- package/dist/__tests__/curl-parser.test.d.ts +1 -0
- package/dist/__tests__/curl-parser.test.js +250 -0
- package/dist/__tests__/types-manager.test.js +22 -18
- package/dist/agents/claude-code.d.ts +10 -0
- package/dist/agents/claude-code.js +50 -0
- package/dist/agents/claude-desktop.d.ts +10 -0
- package/dist/agents/claude-desktop.js +141 -0
- package/dist/agents/codex.d.ts +10 -0
- package/dist/agents/codex.js +45 -0
- package/dist/agents/copilot-cli.d.ts +10 -0
- package/dist/agents/copilot-cli.js +46 -0
- package/dist/agents/copilot-vscode.d.ts +10 -0
- package/dist/agents/copilot-vscode.js +37 -0
- package/dist/agents/cursor.d.ts +10 -0
- package/dist/agents/cursor.js +55 -0
- package/dist/agents/detect.d.ts +4 -0
- package/dist/agents/detect.js +43 -0
- package/dist/agents/gemini.d.ts +10 -0
- package/dist/agents/gemini.js +47 -0
- package/dist/agents/types.d.ts +35 -0
- package/dist/agents/types.js +13 -0
- package/dist/agents/utils/json-config.d.ts +14 -0
- package/dist/agents/utils/json-config.js +42 -0
- package/dist/agents/utils/toml-config.d.ts +8 -0
- package/dist/agents/utils/toml-config.js +27 -0
- package/dist/agents/windsurf.d.ts +10 -0
- package/dist/agents/windsurf.js +50 -0
- package/dist/api/client.d.ts +97 -1
- package/dist/api/client.js +199 -0
- package/dist/auth/store.js +18 -0
- package/dist/commands/agents.d.ts +2 -0
- package/dist/commands/agents.js +160 -0
- package/dist/commands/api-keys.d.ts +2 -0
- package/dist/commands/api-keys.js +95 -0
- package/dist/commands/apps.d.ts +2 -0
- package/dist/commands/apps.js +82 -0
- package/dist/commands/components.d.ts +2 -0
- package/dist/commands/components.js +43 -0
- package/dist/commands/endpoints.d.ts +2 -0
- package/dist/commands/endpoints.js +188 -0
- package/dist/commands/entities.d.ts +2 -0
- package/dist/commands/entities.js +198 -0
- package/dist/commands/files.d.ts +2 -0
- package/dist/commands/files.js +192 -0
- package/dist/commands/info.d.ts +1 -0
- package/dist/commands/info.js +71 -127
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +10 -8
- package/dist/commands/integrations.js +105 -12
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/mcp.js +117 -0
- package/dist/commands/schedules.d.ts +2 -0
- package/dist/commands/schedules.js +221 -0
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.js +199 -0
- package/dist/commands/skills.d.ts +2 -0
- package/dist/commands/skills.js +134 -0
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.js +146 -0
- package/dist/commands/workflows.d.ts +2 -0
- package/dist/commands/workflows.js +187 -0
- package/dist/generated/bundled-types.js +35 -33
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/index.js +26 -0
- package/dist/logs/tailer.js +41 -1
- package/dist/types.d.ts +204 -0
- package/dist/ui/banner.js +7 -6
- package/dist/utils/app-info.d.ts +66 -0
- package/dist/utils/app-info.js +150 -0
- package/dist/utils/curl-parser.d.ts +12 -0
- package/dist/utils/curl-parser.js +44 -0
- package/dist/utils/data-input.d.ts +1 -0
- package/dist/utils/data-input.js +38 -0
- package/dist/workspace/resolve.d.ts +19 -0
- package/dist/workspace/resolve.js +100 -0
- package/package.json +3 -2
package/dist/api/client.js
CHANGED
|
@@ -154,4 +154,203 @@ export class ApiClient {
|
|
|
154
154
|
getGitRemoteUrl(workspaceId, appId) {
|
|
155
155
|
return `${this.baseUrl}/api/git/${workspaceId}/${appId}`;
|
|
156
156
|
}
|
|
157
|
+
// --- Workspace Chat API (skills & MCP) ---
|
|
158
|
+
async listWorkspaceSkills(workspaceId) {
|
|
159
|
+
const res = await this.request(`/api/workspace-chat/${workspaceId}/skills`);
|
|
160
|
+
return res.data.skills;
|
|
161
|
+
}
|
|
162
|
+
async listExternalSkills(workspaceId) {
|
|
163
|
+
const res = await this.request(`/api/workspace-chat/${workspaceId}/external-skills`);
|
|
164
|
+
return res.data.skills;
|
|
165
|
+
}
|
|
166
|
+
async importExternalSkill(workspaceId, skill) {
|
|
167
|
+
const res = await this.request(`/api/workspace-chat/${workspaceId}/external-skills`, { method: 'POST', body: JSON.stringify(skill) });
|
|
168
|
+
return res.data.skill;
|
|
169
|
+
}
|
|
170
|
+
async updateExternalSkill(workspaceId, skillId, skill) {
|
|
171
|
+
const res = await this.request(`/api/workspace-chat/${workspaceId}/external-skills/${skillId}`, { method: 'PUT', body: JSON.stringify(skill) });
|
|
172
|
+
return res.data.skill;
|
|
173
|
+
}
|
|
174
|
+
async getAppSkillContent(workspaceId, appId) {
|
|
175
|
+
const res = await this.request(`/api/workspace-chat/${workspaceId}/apps/${appId}/skill`);
|
|
176
|
+
return res.data.skill;
|
|
177
|
+
}
|
|
178
|
+
async listMcpServers(workspaceId) {
|
|
179
|
+
const res = await this.request(`/api/workspace-chat/${workspaceId}/mcp-servers`);
|
|
180
|
+
return res.data.servers;
|
|
181
|
+
}
|
|
182
|
+
async addMcpServer(workspaceId, server) {
|
|
183
|
+
const res = await this.request(`/api/workspace-chat/${workspaceId}/mcp-servers`, { method: 'POST', body: JSON.stringify(server) });
|
|
184
|
+
return res.data.server;
|
|
185
|
+
}
|
|
186
|
+
async removeMcpServer(workspaceId, serverId) {
|
|
187
|
+
await this.request(`/api/workspace-chat/${workspaceId}/mcp-servers/${serverId}`, { method: 'DELETE' });
|
|
188
|
+
}
|
|
189
|
+
// --- Workspace Registry: Entities ---
|
|
190
|
+
async listEntities(workspaceId) {
|
|
191
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/entities`);
|
|
192
|
+
return res.data.entities;
|
|
193
|
+
}
|
|
194
|
+
async listEntityRecords(workspaceId, entityName, opts) {
|
|
195
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/entities/${encodeURIComponent(entityName)}/list`, {
|
|
196
|
+
method: 'POST',
|
|
197
|
+
body: JSON.stringify({
|
|
198
|
+
limit: opts?.limit,
|
|
199
|
+
cursor: opts?.cursor,
|
|
200
|
+
deploymentMode: opts?.deploymentMode,
|
|
201
|
+
}),
|
|
202
|
+
});
|
|
203
|
+
return res.data;
|
|
204
|
+
}
|
|
205
|
+
async getEntityRecord(workspaceId, entityName, recordId) {
|
|
206
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/entities/${encodeURIComponent(entityName)}/${encodeURIComponent(recordId)}`);
|
|
207
|
+
return res.data;
|
|
208
|
+
}
|
|
209
|
+
async createEntityRecord(workspaceId, entityName, data) {
|
|
210
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/entities/${encodeURIComponent(entityName)}`, { method: 'POST', body: JSON.stringify({ data }) });
|
|
211
|
+
return res.data;
|
|
212
|
+
}
|
|
213
|
+
async updateEntityRecord(workspaceId, entityName, recordId, data) {
|
|
214
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/entities/${encodeURIComponent(entityName)}/${encodeURIComponent(recordId)}`, { method: 'PUT', body: JSON.stringify({ data }) });
|
|
215
|
+
return res.data;
|
|
216
|
+
}
|
|
217
|
+
async deleteEntityRecord(workspaceId, entityName, recordId) {
|
|
218
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/entities/${encodeURIComponent(entityName)}/${encodeURIComponent(recordId)}`, { method: 'DELETE' });
|
|
219
|
+
return res.data;
|
|
220
|
+
}
|
|
221
|
+
// --- Workspace Registry: Workflows ---
|
|
222
|
+
async listWorkflows(workspaceId) {
|
|
223
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/workflows?includeStatus=true`);
|
|
224
|
+
return res.data.workflows;
|
|
225
|
+
}
|
|
226
|
+
async triggerWorkflow(workspaceId, opts) {
|
|
227
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/workflows/trigger`, { method: 'POST', body: JSON.stringify(opts) });
|
|
228
|
+
return res.data;
|
|
229
|
+
}
|
|
230
|
+
async listWorkflowInstances(workspaceId, appId, opts) {
|
|
231
|
+
const params = new URLSearchParams({ appId });
|
|
232
|
+
if (opts?.workflowName)
|
|
233
|
+
params.set('workflowName', opts.workflowName);
|
|
234
|
+
if (opts?.status)
|
|
235
|
+
params.set('status', opts.status);
|
|
236
|
+
if (opts?.limit)
|
|
237
|
+
params.set('limit', String(opts.limit));
|
|
238
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/workflows/instances?${params}`);
|
|
239
|
+
return res.data;
|
|
240
|
+
}
|
|
241
|
+
async getWorkflowInstance(workspaceId, instanceId, appId) {
|
|
242
|
+
const params = appId ? `?appId=${appId}` : '';
|
|
243
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/workflows/instances/${encodeURIComponent(instanceId)}${params}`);
|
|
244
|
+
return res.data;
|
|
245
|
+
}
|
|
246
|
+
// --- Workspace Registry: Schedules ---
|
|
247
|
+
async listSchedules(workspaceId) {
|
|
248
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/schedules?includeStatus=true`);
|
|
249
|
+
return res.data.schedules;
|
|
250
|
+
}
|
|
251
|
+
async triggerSchedule(workspaceId, opts) {
|
|
252
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/schedules/trigger`, { method: 'POST', body: JSON.stringify(opts) });
|
|
253
|
+
return res.data;
|
|
254
|
+
}
|
|
255
|
+
async getScheduleHistory(workspaceId, appId) {
|
|
256
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/schedules/history?appId=${appId}`);
|
|
257
|
+
return res.data;
|
|
258
|
+
}
|
|
259
|
+
async getScheduleStatus(workspaceId, appId) {
|
|
260
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/schedules/status?appId=${appId}`);
|
|
261
|
+
return res.data;
|
|
262
|
+
}
|
|
263
|
+
async pauseSchedule(workspaceId, scheduleName, appId) {
|
|
264
|
+
await this.request(`/api/workspaces/${workspaceId}/schedules/${encodeURIComponent(scheduleName)}/pause?appId=${appId}`, { method: 'POST' });
|
|
265
|
+
}
|
|
266
|
+
async resumeSchedule(workspaceId, scheduleName, appId) {
|
|
267
|
+
await this.request(`/api/workspaces/${workspaceId}/schedules/${encodeURIComponent(scheduleName)}/resume?appId=${appId}`, { method: 'POST' });
|
|
268
|
+
}
|
|
269
|
+
// --- Workspace Registry: Endpoints ---
|
|
270
|
+
async listEndpoints(workspaceId) {
|
|
271
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/endpoints`);
|
|
272
|
+
return res.data.endpoints;
|
|
273
|
+
}
|
|
274
|
+
// --- Workspace Registry: File Storage ---
|
|
275
|
+
async listFileStorages(workspaceId) {
|
|
276
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/file-storages`);
|
|
277
|
+
return res.data.fileStorages;
|
|
278
|
+
}
|
|
279
|
+
async listBucketFiles(workspaceId, bucketName, opts) {
|
|
280
|
+
const params = new URLSearchParams();
|
|
281
|
+
if (opts?.prefix)
|
|
282
|
+
params.set('prefix', opts.prefix);
|
|
283
|
+
if (opts?.delimiter)
|
|
284
|
+
params.set('delimiter', opts.delimiter);
|
|
285
|
+
const query = params.toString();
|
|
286
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/file-storages/${encodeURIComponent(bucketName)}/files${query ? `?${query}` : ''}`);
|
|
287
|
+
return res.data;
|
|
288
|
+
}
|
|
289
|
+
async getPresignedUrl(workspaceId, bucketName, opts) {
|
|
290
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/file-storages/${encodeURIComponent(bucketName)}/presign`, { method: 'POST', body: JSON.stringify(opts) });
|
|
291
|
+
return res.data;
|
|
292
|
+
}
|
|
293
|
+
async deleteBucketFile(workspaceId, bucketName, key) {
|
|
294
|
+
await this.request(`/api/workspaces/${workspaceId}/file-storages/${encodeURIComponent(bucketName)}/files?key=${encodeURIComponent(key)}`, { method: 'DELETE' });
|
|
295
|
+
}
|
|
296
|
+
// --- Workspace Registry: Components ---
|
|
297
|
+
async listComponents(workspaceId) {
|
|
298
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/components`);
|
|
299
|
+
return res.data.components;
|
|
300
|
+
}
|
|
301
|
+
// --- Workspace Registry: API Keys ---
|
|
302
|
+
async listApiKeys(workspaceId) {
|
|
303
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/api-keys`);
|
|
304
|
+
return res.data.apiKeys;
|
|
305
|
+
}
|
|
306
|
+
async createApiKey(workspaceId, opts) {
|
|
307
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/api-keys`, { method: 'POST', body: JSON.stringify(opts) });
|
|
308
|
+
return res.data;
|
|
309
|
+
}
|
|
310
|
+
// --- Workspace Registry: Agents ---
|
|
311
|
+
async listAgents(workspaceId) {
|
|
312
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/agents`);
|
|
313
|
+
return res.data.agents;
|
|
314
|
+
}
|
|
315
|
+
async getAgentStatus(workspaceId, agentName, appId) {
|
|
316
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/agents/status`, { method: 'POST', body: JSON.stringify({ agentName, appId }) });
|
|
317
|
+
return res.data;
|
|
318
|
+
}
|
|
319
|
+
async listAgentExecutions(workspaceId) {
|
|
320
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/agent-executions`);
|
|
321
|
+
return res.data.executions;
|
|
322
|
+
}
|
|
323
|
+
async getAgentExecutionStream(workspaceId, sessionId) {
|
|
324
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/agent-executions/${encodeURIComponent(sessionId)}/stream`);
|
|
325
|
+
return res.data.stream;
|
|
326
|
+
}
|
|
327
|
+
// --- Integrations: Proxy Call ---
|
|
328
|
+
async callIntegrationProxy(integrationDbId, method, path, opts) {
|
|
329
|
+
const targetPath = opts?.query ? `${path}?${opts.query}` : path;
|
|
330
|
+
const url = `${this.baseUrl}/api/proxy/integrations${targetPath}`;
|
|
331
|
+
const headers = {
|
|
332
|
+
'X-Workspace-Integration-Id': integrationDbId,
|
|
333
|
+
...Object.fromEntries(Object.entries(opts?.headers || {})),
|
|
334
|
+
};
|
|
335
|
+
if (this.apiKey) {
|
|
336
|
+
headers['Authorization'] = `Bearer ${this.apiKey}`;
|
|
337
|
+
}
|
|
338
|
+
if (opts?.body) {
|
|
339
|
+
headers['Content-Type'] = 'application/json';
|
|
340
|
+
}
|
|
341
|
+
const response = await fetch(url, {
|
|
342
|
+
method,
|
|
343
|
+
headers,
|
|
344
|
+
body: opts?.body ? JSON.stringify(opts.body) : undefined,
|
|
345
|
+
});
|
|
346
|
+
if (!response.ok) {
|
|
347
|
+
const body = await response.text();
|
|
348
|
+
throw new Error(`Integration proxy error ${response.status}: ${body}`);
|
|
349
|
+
}
|
|
350
|
+
const contentType = response.headers.get('content-type') || '';
|
|
351
|
+
if (contentType.includes('application/json')) {
|
|
352
|
+
return response.json();
|
|
353
|
+
}
|
|
354
|
+
return response.text();
|
|
355
|
+
}
|
|
157
356
|
}
|
package/dist/auth/store.js
CHANGED
|
@@ -4,6 +4,24 @@ import { homedir } from 'os';
|
|
|
4
4
|
const RUNWORK_DIR = join(homedir(), '.runwork');
|
|
5
5
|
const CREDENTIALS_FILE = join(RUNWORK_DIR, '.credentials');
|
|
6
6
|
export function getCredentials() {
|
|
7
|
+
// Support env var auth for sandbox agent sessions
|
|
8
|
+
// RUNWORK_API_KEY is a JWT proxy token set by the platform when running agents in sandbox
|
|
9
|
+
if (process.env.RUNWORK_API_KEY) {
|
|
10
|
+
let baseUrl = 'https://runwork.ai';
|
|
11
|
+
if (process.env.WORKSPACE_API_URL) {
|
|
12
|
+
try {
|
|
13
|
+
baseUrl = new URL(process.env.WORKSPACE_API_URL).origin;
|
|
14
|
+
}
|
|
15
|
+
catch { /* use default */ }
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
apiKey: process.env.RUNWORK_API_KEY,
|
|
19
|
+
email: 'agent@runwork.ai',
|
|
20
|
+
baseUrl,
|
|
21
|
+
defaultWorkspaceId: process.env.WORKSPACE_ID,
|
|
22
|
+
defaultWorkspaceName: undefined,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
7
25
|
if (!existsSync(CREDENTIALS_FILE))
|
|
8
26
|
return null;
|
|
9
27
|
try {
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { requireAuth } from '../auth/store.js';
|
|
3
|
+
import { ApiClient } from '../api/client.js';
|
|
4
|
+
import { resolveWorkspace, resolveApp } from '../workspace/resolve.js';
|
|
5
|
+
import { shouldOutputJson, jsonOut } from '../utils/output.js';
|
|
6
|
+
function truncate(text, max) {
|
|
7
|
+
if (!text)
|
|
8
|
+
return '';
|
|
9
|
+
const first = text.split('\n')[0];
|
|
10
|
+
if (first.length <= max)
|
|
11
|
+
return first;
|
|
12
|
+
return first.slice(0, max - 3) + '...';
|
|
13
|
+
}
|
|
14
|
+
const listCommand = new Command('list')
|
|
15
|
+
.description('List agents in workspace')
|
|
16
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
17
|
+
.option('--app <id>', 'Filter by app name or ID')
|
|
18
|
+
.action(async (opts, command) => {
|
|
19
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
20
|
+
const credentials = requireAuth();
|
|
21
|
+
const client = new ApiClient(credentials);
|
|
22
|
+
const { workspaceId, workspaceName } = await resolveWorkspace(client, opts);
|
|
23
|
+
try {
|
|
24
|
+
let agents = await client.listAgents(workspaceId);
|
|
25
|
+
if (opts.app) {
|
|
26
|
+
agents = agents.filter(a => a.appId === opts.app || a.appName === opts.app);
|
|
27
|
+
}
|
|
28
|
+
if (useJson) {
|
|
29
|
+
jsonOut({ agents });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (agents.length === 0) {
|
|
33
|
+
console.log('No agents found in this workspace.');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(`\nWorkspace: ${workspaceName || workspaceId}\n`);
|
|
37
|
+
console.log(' ' +
|
|
38
|
+
'Name'.padEnd(24) +
|
|
39
|
+
'Type'.padEnd(16) +
|
|
40
|
+
'App'.padEnd(20) +
|
|
41
|
+
'Description'.padEnd(42) +
|
|
42
|
+
'Integrations'.padEnd(20) +
|
|
43
|
+
'Entities'.padEnd(20) +
|
|
44
|
+
'Mode');
|
|
45
|
+
console.log(' ' + '-'.repeat(140));
|
|
46
|
+
for (const a of agents) {
|
|
47
|
+
const name = a.agentName.padEnd(24);
|
|
48
|
+
const type = a.type.padEnd(16);
|
|
49
|
+
const app = truncate(a.appName, 18).padEnd(20);
|
|
50
|
+
const desc = truncate(a.description, 40).padEnd(42);
|
|
51
|
+
const integrations = (a.integrations?.join(', ') || '').padEnd(20);
|
|
52
|
+
const entities = (a.entities?.join(', ') || '').padEnd(20);
|
|
53
|
+
const mode = a.deploymentMode || '';
|
|
54
|
+
console.log(` ${name}${type}${app}${desc}${integrations}${entities}${mode}`);
|
|
55
|
+
}
|
|
56
|
+
console.log('');
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
console.error('Failed to list agents:', err instanceof Error ? err.message : err);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const statusCommand = new Command('status')
|
|
64
|
+
.description('Get status of a specific agent')
|
|
65
|
+
.argument('<name>', 'Agent name')
|
|
66
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
67
|
+
.option('--app <id>', 'App name or ID (required)')
|
|
68
|
+
.action(async (name, opts, command) => {
|
|
69
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
70
|
+
const credentials = requireAuth();
|
|
71
|
+
const client = new ApiClient(credentials);
|
|
72
|
+
const { workspaceId } = await resolveWorkspace(client, opts);
|
|
73
|
+
const { appId } = await resolveApp(client, workspaceId, opts);
|
|
74
|
+
try {
|
|
75
|
+
const status = await client.getAgentStatus(workspaceId, name, appId);
|
|
76
|
+
if (useJson) {
|
|
77
|
+
jsonOut({ status });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
console.log(JSON.stringify(status, null, 2));
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
console.error('Failed to get agent status:', err instanceof Error ? err.message : err);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const executionsCommand = new Command('executions')
|
|
88
|
+
.description('List agent execution history for workspace')
|
|
89
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
90
|
+
.action(async (opts, command) => {
|
|
91
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
92
|
+
const credentials = requireAuth();
|
|
93
|
+
const client = new ApiClient(credentials);
|
|
94
|
+
const { workspaceId } = await resolveWorkspace(client, opts);
|
|
95
|
+
try {
|
|
96
|
+
const executions = await client.listAgentExecutions(workspaceId);
|
|
97
|
+
if (useJson) {
|
|
98
|
+
jsonOut({ executions });
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (executions.length === 0) {
|
|
102
|
+
console.log('No agent executions found.');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
console.log(' ' +
|
|
106
|
+
'Session ID'.padEnd(36) +
|
|
107
|
+
'Agent'.padEnd(22) +
|
|
108
|
+
'App'.padEnd(22) +
|
|
109
|
+
'Prompt'.padEnd(52) +
|
|
110
|
+
'Status'.padEnd(12) +
|
|
111
|
+
'Duration'.padEnd(12) +
|
|
112
|
+
'Usage');
|
|
113
|
+
console.log(' ' + '-'.repeat(160));
|
|
114
|
+
for (const e of executions) {
|
|
115
|
+
const sessionId = e.sessionId.padEnd(36);
|
|
116
|
+
const agent = truncate(e.agentName, 20).padEnd(22);
|
|
117
|
+
const app = truncate(e.appId, 20).padEnd(22);
|
|
118
|
+
const prompt = truncate(e.prompt, 50).padEnd(52);
|
|
119
|
+
const status = e.status.padEnd(12);
|
|
120
|
+
const duration = e.durationMs != null ? `${e.durationMs}ms` : '';
|
|
121
|
+
const usage = e.usage
|
|
122
|
+
? `${e.usage.inputTokens}/${e.usage.outputTokens}`
|
|
123
|
+
: '';
|
|
124
|
+
console.log(` ${sessionId}${agent}${app}${prompt}${status}${duration.padEnd(12)}${usage}`);
|
|
125
|
+
}
|
|
126
|
+
console.log('');
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
console.error('Failed to list agent executions:', err instanceof Error ? err.message : err);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
const executionCommand = new Command('execution')
|
|
134
|
+
.description('Get execution stream for a specific session')
|
|
135
|
+
.argument('<sessionId>', 'Session ID')
|
|
136
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
137
|
+
.action(async (sessionId, opts, command) => {
|
|
138
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
139
|
+
const credentials = requireAuth();
|
|
140
|
+
const client = new ApiClient(credentials);
|
|
141
|
+
const { workspaceId } = await resolveWorkspace(client, opts);
|
|
142
|
+
try {
|
|
143
|
+
const stream = await client.getAgentExecutionStream(workspaceId, sessionId);
|
|
144
|
+
if (useJson) {
|
|
145
|
+
jsonOut({ stream });
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
process.stdout.write(stream);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
console.error('Failed to get agent execution stream:', err instanceof Error ? err.message : err);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
export const agentsCommand = new Command('agents')
|
|
156
|
+
.description('Manage workspace agents and execution history')
|
|
157
|
+
.addCommand(listCommand)
|
|
158
|
+
.addCommand(statusCommand)
|
|
159
|
+
.addCommand(executionsCommand)
|
|
160
|
+
.addCommand(executionCommand);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { requireAuth } from '../auth/store.js';
|
|
3
|
+
import { ApiClient } from '../api/client.js';
|
|
4
|
+
import { resolveWorkspace, resolveApp } from '../workspace/resolve.js';
|
|
5
|
+
import { shouldOutputJson, jsonOut } from '../utils/output.js';
|
|
6
|
+
import { promptInput } from '../utils/prompt.js';
|
|
7
|
+
const listCommand = new Command('list')
|
|
8
|
+
.description('List API keys for the workspace')
|
|
9
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
10
|
+
.action(async (opts, command) => {
|
|
11
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
12
|
+
const credentials = requireAuth();
|
|
13
|
+
const client = new ApiClient(credentials);
|
|
14
|
+
const { workspaceId, workspaceName } = await resolveWorkspace(client, opts);
|
|
15
|
+
try {
|
|
16
|
+
const apiKeys = await client.listApiKeys(workspaceId);
|
|
17
|
+
if (useJson) {
|
|
18
|
+
jsonOut({ apiKeys });
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (apiKeys.length === 0) {
|
|
22
|
+
console.log('No API keys found in this workspace.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log(`\nWorkspace: ${workspaceName || workspaceId}\n`);
|
|
26
|
+
console.log(` ${'Name'.padEnd(24)} ${'Key Prefix'.padEnd(16)} ${'App'.padEnd(20)} ${'Active'.padEnd(8)} ${'Requests'.padEnd(10)} ${'Last Used'.padEnd(22)} Created`);
|
|
27
|
+
console.log(' ' + '-'.repeat(112));
|
|
28
|
+
for (const k of apiKeys) {
|
|
29
|
+
const prefix = `${k.keyPrefix}...`;
|
|
30
|
+
const appLabel = k.appId ? k.appId : 'all';
|
|
31
|
+
const active = k.isActive ? 'yes' : 'no';
|
|
32
|
+
const requests = k.requestCount !== undefined ? String(k.requestCount) : '-';
|
|
33
|
+
const lastUsed = k.lastUsedAt ? new Date(k.lastUsedAt).toLocaleString() : '-';
|
|
34
|
+
const created = new Date(k.createdAt).toLocaleString();
|
|
35
|
+
console.log(` ${k.name.padEnd(24)} ${prefix.padEnd(16)} ${appLabel.padEnd(20)} ${active.padEnd(8)} ${requests.padEnd(10)} ${lastUsed.padEnd(22)} ${created}`);
|
|
36
|
+
}
|
|
37
|
+
console.log('');
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
console.error('Failed to list API keys:', err instanceof Error ? err.message : err);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const createCommand = new Command('create')
|
|
45
|
+
.description('Create a new API key')
|
|
46
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
47
|
+
.option('--name <name>', 'API key name')
|
|
48
|
+
.option('--app <id>', 'Restrict key to a specific app (name or ID)')
|
|
49
|
+
.option('--scopes <scopes>', 'Comma-separated list of scopes')
|
|
50
|
+
.action(async (opts, command) => {
|
|
51
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
52
|
+
const credentials = requireAuth();
|
|
53
|
+
const client = new ApiClient(credentials);
|
|
54
|
+
const { workspaceId } = await resolveWorkspace(client, opts);
|
|
55
|
+
let name = opts.name ?? '';
|
|
56
|
+
if (!name) {
|
|
57
|
+
if (process.stdout.isTTY) {
|
|
58
|
+
name = await promptInput('API key name:');
|
|
59
|
+
if (!name) {
|
|
60
|
+
console.error('API key name is required.');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.error('API key name is required. Use --name flag.');
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let appId;
|
|
70
|
+
if (opts.app) {
|
|
71
|
+
const resolved = await resolveApp(client, workspaceId, { app: opts.app });
|
|
72
|
+
appId = resolved.appId;
|
|
73
|
+
}
|
|
74
|
+
const scopes = opts.scopes
|
|
75
|
+
? opts.scopes.split(',').map((s) => s.trim()).filter(Boolean)
|
|
76
|
+
: undefined;
|
|
77
|
+
try {
|
|
78
|
+
const result = await client.createApiKey(workspaceId, { name, appId, scopes });
|
|
79
|
+
if (useJson) {
|
|
80
|
+
jsonOut({ apiKey: result });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.log(`\nAPI key created: ${result.name}`);
|
|
84
|
+
console.log(`\n Key: ${result.key}`);
|
|
85
|
+
console.log(`\n WARNING: Save this key now - it cannot be retrieved again.\n`);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
console.error('Failed to create API key:', err instanceof Error ? err.message : err);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
export const apiKeysCommand = new Command('api-keys')
|
|
93
|
+
.description('Manage workspace API keys')
|
|
94
|
+
.addCommand(listCommand)
|
|
95
|
+
.addCommand(createCommand);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { requireAuth } from '../auth/store.js';
|
|
3
|
+
import { ApiClient } from '../api/client.js';
|
|
4
|
+
import { resolveWorkspace, resolveApp } from '../workspace/resolve.js';
|
|
5
|
+
import { shouldOutputJson, jsonOut } from '../utils/output.js';
|
|
6
|
+
import { fetchAppInfo, printAppInfo } from '../utils/app-info.js';
|
|
7
|
+
import { runCreateFlow } from './init.js';
|
|
8
|
+
const listCommand = new Command('list')
|
|
9
|
+
.description('List apps in workspace')
|
|
10
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
11
|
+
.action(async (opts, command) => {
|
|
12
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
13
|
+
const credentials = requireAuth();
|
|
14
|
+
const client = new ApiClient(credentials);
|
|
15
|
+
const { workspaceId, workspaceName } = await resolveWorkspace(client, opts);
|
|
16
|
+
try {
|
|
17
|
+
const apps = await client.listApps(workspaceId);
|
|
18
|
+
if (useJson) {
|
|
19
|
+
jsonOut({ apps });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (apps.length === 0) {
|
|
23
|
+
console.log('No apps in this workspace.');
|
|
24
|
+
console.log('Create one with: runwork create <name>');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
console.log(`\nWorkspace: ${workspaceName || workspaceId}\n`);
|
|
28
|
+
console.log(` ${'Name'.padEnd(28)} ${'ID'.padEnd(38)} Status`);
|
|
29
|
+
console.log(' ' + '-'.repeat(80));
|
|
30
|
+
for (const app of apps) {
|
|
31
|
+
console.log(` ${(app.name || '').padEnd(28)} ${app.id}`);
|
|
32
|
+
}
|
|
33
|
+
console.log('');
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
console.error('Failed to list apps:', err instanceof Error ? err.message : err);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const createCommand = new Command('create')
|
|
41
|
+
.description('Create a new Runwork app')
|
|
42
|
+
.argument('[name]', 'App name')
|
|
43
|
+
.action(async (name) => {
|
|
44
|
+
await runCreateFlow(name);
|
|
45
|
+
});
|
|
46
|
+
const infoCommand = new Command('info')
|
|
47
|
+
.description('Show detailed app info, preview status, and registries')
|
|
48
|
+
.argument('[app]', 'App ID, name, or slug')
|
|
49
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
50
|
+
.action(async (appArg, opts, command) => {
|
|
51
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
52
|
+
const credentials = requireAuth();
|
|
53
|
+
const client = new ApiClient(credentials);
|
|
54
|
+
const { workspaceId, workspaceName } = await resolveWorkspace(client, opts);
|
|
55
|
+
const { appId, appName } = await resolveApp(client, workspaceId, { app: appArg });
|
|
56
|
+
let appSlug = appName;
|
|
57
|
+
try {
|
|
58
|
+
const appData = await client.getApp(appId);
|
|
59
|
+
appSlug = appData.slug || appName;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Fall back to appName as slug
|
|
63
|
+
}
|
|
64
|
+
const data = await fetchAppInfo(client, {
|
|
65
|
+
appId,
|
|
66
|
+
appName,
|
|
67
|
+
appSlug,
|
|
68
|
+
workspaceId,
|
|
69
|
+
workspaceName,
|
|
70
|
+
baseUrl: credentials.baseUrl || 'https://runwork.ai',
|
|
71
|
+
});
|
|
72
|
+
if (useJson) {
|
|
73
|
+
jsonOut(data);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
printAppInfo(data);
|
|
77
|
+
});
|
|
78
|
+
export const appsCommand = new Command('apps')
|
|
79
|
+
.description('Manage workspace apps')
|
|
80
|
+
.addCommand(listCommand)
|
|
81
|
+
.addCommand(createCommand)
|
|
82
|
+
.addCommand(infoCommand);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { requireAuth } from '../auth/store.js';
|
|
3
|
+
import { ApiClient } from '../api/client.js';
|
|
4
|
+
import { resolveWorkspace } from '../workspace/resolve.js';
|
|
5
|
+
import { shouldOutputJson, jsonOut } from '../utils/output.js';
|
|
6
|
+
const listCommand = new Command('list')
|
|
7
|
+
.description('List components registered in the workspace')
|
|
8
|
+
.option('--workspace <id>', 'Workspace ID')
|
|
9
|
+
.option('--app <id>', 'Filter by app name or ID')
|
|
10
|
+
.action(async (opts, command) => {
|
|
11
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
12
|
+
const credentials = requireAuth();
|
|
13
|
+
const client = new ApiClient(credentials);
|
|
14
|
+
const { workspaceId, workspaceName } = await resolveWorkspace(client, opts);
|
|
15
|
+
try {
|
|
16
|
+
let components = await client.listComponents(workspaceId);
|
|
17
|
+
if (opts.app) {
|
|
18
|
+
components = components.filter(c => c.appId === opts.app || c.appName === opts.app);
|
|
19
|
+
}
|
|
20
|
+
if (useJson) {
|
|
21
|
+
jsonOut({ components });
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (components.length === 0) {
|
|
25
|
+
console.log('No components found in this workspace.');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
console.log(`\nWorkspace: ${workspaceName || workspaceId}\n`);
|
|
29
|
+
console.log(` ${'Component'.padEnd(28)} ${'App'.padEnd(24)} ${'Mode'.padEnd(12)}`);
|
|
30
|
+
console.log(' ' + '-'.repeat(66));
|
|
31
|
+
for (const c of components) {
|
|
32
|
+
console.log(` ${c.componentName.padEnd(28)} ${c.appName.padEnd(24)} ${(c.deploymentMode ?? '').padEnd(12)}`);
|
|
33
|
+
}
|
|
34
|
+
console.log('');
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
console.error('Failed to list components:', err instanceof Error ? err.message : err);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
export const componentsCommand = new Command('components')
|
|
42
|
+
.description('List workspace components')
|
|
43
|
+
.addCommand(listCommand);
|