UNPKG

@agentled/cli

Version:

CLI for Agentled — manage workflows, apps, and knowledge from the command line. Zero context-window cost for AI agents.

321 lines 13.6 kB
import { readFileSync } from 'node:fs'; import { AgentledClient } from '../client.js'; import { printOutput, printError } from '../utils/output.js'; import { findWorkspaceDir, refreshWorkspaceFolder, readWorkspaceMeta } from '../utils/workspace-folder.js'; function readJsonValue(opts, label) { if (!opts.input && !opts.file) { throw new Error(`Provide ${label} via --input '<json>' or --file <path>`); } if (opts.input && opts.file) { throw new Error(`Provide ${label} with either --input or --file, not both`); } const raw = opts.file ? readFileSync(opts.file, 'utf8') : opts.input; try { return JSON.parse(raw); } catch (error) { throw new Error(`Invalid JSON for ${label}: ${error?.message || 'parse failed'}`); } } export function registerWorkspaceCommands(program) { const workspace = program .command('workspace') .alias('ws') .description('Workspace information'); workspace .command('inspect') .description('One-shot workspace orientation: identity, company profile, workflows, KG lists, connected apps, and agents') .option('--format <fmt>', 'Output format (json or table)', 'json') .action(async (opts) => { try { const client = new AgentledClient(); // Fan out all six orientation calls in parallel. const [workspace, companyProfile, workflows, knowledgeLists, connections, agents] = await Promise.allSettled([ client.getWorkspace(), client.getWorkspaceCompanyProfile(), client.listWorkflows(), client.listKnowledgeLists(), client.listConnections(), client.listAgents(), ]); const result = { workspace: workspace.status === 'fulfilled' ? workspace.value : { error: workspace.reason?.message }, companyProfile: companyProfile.status === 'fulfilled' ? companyProfile.value : { error: companyProfile.reason?.message }, workflows: workflows.status === 'fulfilled' ? workflows.value : { error: workflows.reason?.message }, knowledgeLists: knowledgeLists.status === 'fulfilled' ? knowledgeLists.value : { error: knowledgeLists.reason?.message }, connections: connections.status === 'fulfilled' ? connections.value : { error: connections.reason?.message }, agents: agents.status === 'fulfilled' ? agents.value : { error: agents.reason?.message }, }; printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('info') .description('Get workspace details') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const client = new AgentledClient(); const result = await client.getWorkspace(); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('resolve') .description('Resolve an existing workspace without mutation before operator provisioning') .option('--input <json>', 'Workspace resolve request JSON') .option('--file <path>', 'Path to workspace resolve request JSON') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const input = readJsonValue(opts, 'workspace resolve request'); const result = await new AgentledClient().resolveWorkspace(input); printOutput(result, opts.format); } catch (e) { printError(e instanceof Error ? e.message : String(e)); } }); workspace .command('create') .description('Create one setup-only workspace; requires operator:workspace:create scope') .option('--input <json>', 'Workspace create request JSON') .option('--file <path>', 'Path to workspace create request JSON') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const input = readJsonValue(opts, 'workspace create request'); const result = await new AgentledClient().createWorkspace(input); printOutput(result, opts.format); } catch (e) { printError(e instanceof Error ? e.message : String(e)); } }); workspace .command('company-profile') .description('Get editable workspace company profile and company knowledge text') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const client = new AgentledClient(); const result = await client.getWorkspaceCompanyProfile(); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('update-company-profile') .description('Update workspace company profile fields') .option('--input <json>', 'Company profile JSON object') .option('--file <path>', 'Path to JSON file containing a company profile object') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const parsed = readJsonValue(opts, 'company profile'); const company = parsed?.company && typeof parsed.company === 'object' ? parsed.company : parsed; if (!company || typeof company !== 'object' || Array.isArray(company)) { throw new Error('Company profile input must be a JSON object'); } const client = new AgentledClient(); const result = await client.updateWorkspaceCompanyProfile(company); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('pinned-outputs') .description('List output pages pinned to the workspace home/sidebar') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const client = new AgentledClient(); const result = await client.listPinnedOutputs(); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('set-output-pin <workflowId> <outputPagePathname>') .description('Pin or unpin a workflow output page on the workspace home/sidebar') .option('--pin', 'Pin the output page (default)') .option('--unpin', 'Unpin the output page') .option('--label <label>', 'Optional custom sidebar label when pinning') .option('--icon-name <name>', 'Optional lucide icon name when pinning') .option('--format <fmt>', 'Output format', 'json') .action(async (workflowId, outputPagePathname, opts) => { try { if (opts.pin && opts.unpin) { throw new Error('Use either --pin or --unpin, not both'); } const client = new AgentledClient(); const result = await client.setOutputPagePin({ workflowId, outputPagePathname, pinned: opts.unpin ? false : true, label: opts.label, iconName: opts.iconName, }); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('home-recent') .description('Inspect the Home tabs, their default tab, the Recent tab configuration, and the current workspace revision') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const client = new AgentledClient(); const result = await client.inspectHomeRecentTab(); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('configure-home-recent') .description('Configure the display-only Home Recent tab and default Home tab without running workflows') .requiredOption('--expected-workspace-updated-at <timestamp>', 'Workspace revision returned by workspace home-recent') .option('--input <json>', 'Full Home Recent config JSON object') .option('--file <path>', 'Path to a full Home Recent config JSON object') .option('--reset', 'Reset to the default Home Recent configuration') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const modeCount = [ opts.input !== undefined, opts.file !== undefined, opts.reset === true, ].filter(Boolean).length; if (modeCount !== 1) { throw new Error('Use exactly one of --input, --file, or --reset'); } const config = opts.reset ? null : readJsonValue(opts, 'Home Recent configuration'); if (config !== null && (!config || typeof config !== 'object' || Array.isArray(config))) { throw new Error('Home Recent configuration must be a JSON object'); } const client = new AgentledClient(); const result = await client.configureHomeRecentTab({ expectedWorkspaceUpdatedAt: opts.expectedWorkspaceUpdatedAt, config, sourceSurface: 'cli', }); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); // --- Branding --- workspace .command('branding') .description('Get workspace whitelabel branding configuration') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const client = new AgentledClient(); const result = await client.getBranding(); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('update-branding') .description('Update workspace whitelabel branding') .option('--display-name <name>', 'Display name') .option('--logo-url <url>', 'Logo URL') .option('--tagline <text>', 'Tagline') .option('--primary-color <hex>', 'Primary color (light mode)') .option('--primary-color-dark <hex>', 'Primary color (dark mode)') .option('--favicon-url <url>', 'Favicon URL') .option('--hide-badge', 'Hide "Powered by" badge') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const branding = {}; if (opts.displayName) branding.displayName = opts.displayName; if (opts.logoUrl) branding.logoUrl = opts.logoUrl; if (opts.tagline) branding.tagline = opts.tagline; if (opts.primaryColor) branding.primaryColor = opts.primaryColor; if (opts.primaryColorDark) branding.primaryColorDark = opts.primaryColorDark; if (opts.faviconUrl) branding.faviconUrl = opts.faviconUrl; if (opts.hideBadge !== undefined) branding.hideBadge = true; if (Object.keys(branding).length === 0) { printError('Provide at least one branding field to update'); return; } const client = new AgentledClient(); const result = await client.updateBranding(branding); printOutput(result, opts.format); } catch (e) { printError(e.message); } }); workspace .command('sync') .description('Refresh the local workspace folder cache (apps.json + models.json) and bundled docs (SKILL.md, GOTCHAS.md). Run this after a CLI upgrade or when workspace apps change.') .option('--format <fmt>', 'Output format', 'json') .action(async (opts) => { try { const wsDir = findWorkspaceDir(); if (!wsDir) { printError('No agentled workspace folder found. Run `agentled init` first.'); return; } const client = new AgentledClient(); const [appsList, modelsList] = await Promise.allSettled([ client.listApps(), client.listModels(), ]); refreshWorkspaceFolder(wsDir, { appsList: appsList.status === 'fulfilled' ? appsList.value : undefined, modelsList: modelsList.status === 'fulfilled' ? modelsList.value : undefined, }); printOutput({ workspaceDir: wsDir, meta: readWorkspaceMeta(wsDir), refreshed: { apps: appsList.status === 'fulfilled', models: modelsList.status === 'fulfilled', docs: true, }, }, (opts.format ?? 'json')); } catch (e) { printError(e instanceof Error ? e.message : String(e)); } }); } //# sourceMappingURL=workspace.js.map