@agentled/cli
Version:
CLI for Agentled — manage workflows, apps, and knowledge from the command line. Zero context-window cost for AI agents.
229 lines • 11.1 kB
JavaScript
import { readFileSync } from 'node:fs';
import { AgentledClient } from '../client.js';
import { printError, printOutput } from '../utils/output.js';
function readJson(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;
return JSON.parse(raw);
}
function parseCsvList(value) {
if (value === undefined)
return undefined;
return value
.split(',')
.map((item) => item.trim())
.filter(Boolean);
}
function parseJsonObject(value, label) {
if (value === undefined)
return undefined;
try {
const parsed = JSON.parse(value);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new Error(`${label} must be a JSON object`);
}
return parsed;
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Invalid ${label}: ${message}`);
}
}
function parseJsonArray(value, label) {
if (value === undefined)
return undefined;
try {
const parsed = JSON.parse(value);
if (!Array.isArray(parsed) || parsed.some((item) => !item || typeof item !== 'object' || Array.isArray(item))) {
throw new Error(`${label} must be a JSON array of objects`);
}
return parsed;
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Invalid ${label}: ${message}`);
}
}
function viewPayloadFromOptions(opts) {
return {
name: opts.name,
key: opts.key,
workspaceSlug: opts.workspaceSlug,
navLabel: opts.navLabel,
description: opts.description,
status: opts.status,
source: opts.source,
viewType: opts.viewType,
iconName: opts.iconName,
ownerUserId: opts.ownerUserId,
collaboratorUserIds: parseCsvList(opts.collaboratorUserIds),
useCaseIds: parseCsvList(opts.useCaseIds),
workflowIds: parseCsvList(opts.workflowIds),
executionIds: parseCsvList(opts.executionIds),
approvalIds: parseCsvList(opts.approvalIds),
agentIds: parseCsvList(opts.agentIds),
routineIds: parseCsvList(opts.routineIds),
knowledgeTextKeys: parseCsvList(opts.knowledgeTextKeys),
knowledgeListKeys: parseCsvList(opts.knowledgeListKeys),
dataSourceIds: parseCsvList(opts.dataSourceIds),
externalSourceIds: parseCsvList(opts.externalSourceIds),
dataSources: parseJsonArray(opts.dataSources, 'dataSources'),
filters: parseJsonObject(opts.filters, 'filters'),
transforms: parseJsonObject(opts.transforms, 'transforms'),
layout: parseJsonObject(opts.layout, 'layout'),
actions: parseJsonArray(opts.actions, 'actions'),
refreshPolicy: parseJsonObject(opts.refreshPolicy, 'refreshPolicy'),
config: parseJsonObject(opts.config, 'config'),
validation: parseJsonObject(opts.validation, 'validation'),
metadata: parseJsonObject(opts.metadata, 'metadata'),
placement: parseJsonObject(opts.placement, 'placement'),
pinned: opts.pinned === true ? true : opts.unpinned === true ? false : undefined,
};
}
function removeUndefined(payload) {
return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));
}
function addViewMutationOptions(command, mode) {
command
.option('--name <name>', mode === 'create'
? 'Workspace view display name (required unless --input/--file provides name)'
: 'Workspace view display name')
.option('--key <key>', 'Stable workspace-local key, e.g. linkedin-operating-view')
.option('--workspace-slug <slug>', 'Optional workspace slug for readable IDs')
.option('--nav-label <label>', 'Short sidebar/navigation label; name remains the full page title')
.option('--description <text>', 'View description')
.option('--status <status>', 'draft, active, paused, or archived')
.option('--source <source>', 'agent, user, system, template, or imported')
.option('--view-type <type>', 'dashboard, list, funnel, approval_queue, report, or custom')
.option('--icon-name <name>', 'Lucide icon name')
.option('--owner-user-id <id>', 'Owner user ID')
.option('--collaborator-user-ids <ids>', 'Comma-separated collaborator user IDs')
.option('--use-case-ids <ids>', 'Comma-separated linked WorkspaceUseCase IDs')
.option('--workflow-ids <ids>', 'Comma-separated linked workflow IDs')
.option('--execution-ids <ids>', 'Comma-separated linked execution IDs')
.option('--approval-ids <ids>', 'Comma-separated linked approval IDs')
.option('--agent-ids <ids>', 'Comma-separated linked agent IDs')
.option('--routine-ids <ids>', 'Comma-separated linked routine IDs')
.option('--knowledge-text-keys <keys>', 'Comma-separated linked KG text keys')
.option('--knowledge-list-keys <keys>', 'Comma-separated linked KG list keys')
.option('--data-source-ids <ids>', 'Comma-separated linked data source IDs')
.option('--external-source-ids <ids>', 'Comma-separated linked external source IDs')
.option('--data-sources <json>', 'WorkspaceViewDataSource[] JSON; supports KG, workflow, approvals, agents, routines, external API, and custom sources')
.option('--filters <json>', 'Filter manifest JSON object')
.option('--transforms <json>', 'Transform manifest JSON object')
.option('--layout <json>', 'ConfigLayout JSON object used by the Config renderer')
.option('--actions <json>', 'WorkspaceViewAction[] JSON; write/send actions still require approval')
.option('--refresh-policy <json>', 'Refresh policy JSON object')
.option('--config <json>', 'Additional config JSON object')
.option('--validation <json>', 'Validation metadata JSON object')
.option('--metadata <json>', 'Additional metadata JSON object')
.option('--placement <json>', 'Sidebar placement JSON object, e.g. {"type":"workflow","workflowId":"pipeline-1"}')
.option('--pinned', 'Pin the view as a workspace-level operating surface')
.option('--unpinned', 'Unpin the view');
}
export function registerWorkspaceViewCommands(program) {
const views = program
.command('workspace-views')
.alias('views')
.description('Manage saved workspace views over KG, workflows, approvals, agents, routines, and external data');
views
.command('list')
.description('List workspace views and their source/action guidance')
.option('--status <status>', 'Filter by status: draft, active, paused, archived')
.option('--limit <n>', 'Maximum rows to return', parseInt)
.option('--format <fmt>', 'Output format', 'json')
.action(async (opts) => {
try {
const result = await new AgentledClient().listWorkspaceViews({
status: opts.status,
limit: opts.limit,
});
printOutput(result, opts.format);
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
printError(message);
}
});
const createCommand = views
.command('create')
.description('Create a saved workspace view manifest without running workflows or mutating source rows')
.option('--input <json>', 'Full create payload JSON (overrides CLI flags)')
.option('--file <path>', 'Path to JSON create payload file')
.option('--format <fmt>', 'Output format', 'json');
addViewMutationOptions(createCommand, 'create');
createCommand.action(async (opts) => {
try {
const payload = opts.input || opts.file
? readJson(opts, 'workspace view payload')
: removeUndefined(viewPayloadFromOptions(opts));
if (!payload.name)
throw new Error('Provide a view name via --name, --input, or --file');
if (!payload.dataSources)
throw new Error('Provide dataSources via --data-sources, --input, or --file');
if (!payload.layout)
throw new Error('Provide layout via --layout, --input, or --file');
const result = await new AgentledClient().createWorkspaceView(payload);
printOutput(result, opts.format);
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
printError(message);
}
});
views
.command('get <id>')
.description('Get a workspace view by stored id or key, including agent read/safety guidance')
.option('--format <fmt>', 'Output format', 'json')
.action(async (id, opts) => {
try {
const result = await new AgentledClient().getWorkspaceView(id);
printOutput(result, opts.format);
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
printError(message);
}
});
const updateCommand = views
.command('update <id>')
.description('Update a workspace view manifest by stored id or key')
.option('--input <json>', 'Full update payload JSON (overrides CLI flags)')
.option('--file <path>', 'Path to JSON update payload file')
.option('--format <fmt>', 'Output format', 'json');
addViewMutationOptions(updateCommand, 'update');
updateCommand.action(async (id, opts) => {
try {
const payload = opts.input || opts.file
? readJson(opts, 'workspace view update payload')
: removeUndefined(viewPayloadFromOptions(opts));
if (Object.keys(payload).length === 0) {
throw new Error('Provide updates via flags, --input, or --file');
}
const result = await new AgentledClient().updateWorkspaceView(id, payload);
printOutput(result, opts.format);
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
printError(message);
}
});
views
.command('archive <id>')
.description('Archive a workspace view without deleting linked data or source rows')
.option('--format <fmt>', 'Output format', 'json')
.action(async (id, opts) => {
try {
const result = await new AgentledClient().archiveWorkspaceView(id);
printOutput(result, opts.format);
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
printError(message);
}
});
}
//# sourceMappingURL=workspace-views.js.map