UNPKG

@agentled/cli

Version:

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

194 lines 8.34 kB
import { readFileSync } from 'node:fs'; import { AgentledClient } from '../client.js'; import { printError, printOutput } from '../utils/output.js'; const DEFAULT_PACKAGE_ID = 'vc-deal-flow'; function readJsonInput(options, label) { if (!options.input && !options.file) { throw new Error(`Provide ${label} via --input '<json>' or --file <path>`); } if (options.input && options.file) { throw new Error(`Provide ${label} with either --input or --file, not both`); } const raw = options.file ? readFileSync(options.file, 'utf8') : options.input; const parsed = JSON.parse(raw); if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { throw new Error(`${label} must be a JSON object`); } return parsed; } function target(packageId, version) { return { packageId: packageId || DEFAULT_PACKAGE_ID, ...(version ? { version } : {}), }; } function withTargetOptions(command) { return command .argument('[packageId]', 'Registered package ID', DEFAULT_PACKAGE_ID) .option('--version <version>', 'Optional exact registered package version') .option('--format <fmt>', 'Output format', 'json'); } function previewResolutions(options) { if (!options.resolutions && !options.resolutionsFile) return undefined; if (options.resolutions && options.resolutionsFile) { throw new Error('Provide preview resolutions with either --resolutions or --resolutions-file, not both'); } const raw = options.resolutionsFile ? readFileSync(options.resolutionsFile, 'utf8') : options.resolutions; const parsed = JSON.parse(raw); if (!Array.isArray(parsed)) { throw new Error('Preview resolutions must be a JSON array'); } return parsed.map((entry) => { if (!entry || typeof entry !== 'object' || Array.isArray(entry)) { throw new Error('Each preview resolution must be an object'); } const value = entry; if (typeof value.ref !== 'string' || !value.ref.trim() || (value.decision !== 'adopt' && value.decision !== 'preserve') || typeof value.currentFingerprint !== 'string' || !/^[a-f0-9]{64}$/.test(value.currentFingerprint)) { throw new Error('Each preview resolution requires ref, adopt or preserve decision, and a SHA-256 currentFingerprint'); } return { ref: value.ref.trim(), decision: value.decision, currentFingerprint: value.currentFingerprint, }; }); } function mutationPayload(packageId, options) { const input = readJsonInput(options, 'exact package confirmation'); const preview = input.preview; const confirmation = input.confirmation; const leaseToken = input.leaseToken; if (!preview || typeof preview !== 'object' || Array.isArray(preview)) { throw new Error('Exact package confirmation requires preview'); } if (!confirmation || typeof confirmation !== 'object' || Array.isArray(confirmation)) { throw new Error('Exact package confirmation requires confirmation'); } const approvalReference = confirmation .approvalReference; const bindingHash = confirmation.bindingHash; const planHash = confirmation.planHash; if (typeof approvalReference !== 'string' || !approvalReference.trim() || typeof bindingHash !== 'string' || !bindingHash.trim() || typeof planHash !== 'string' || !planHash.trim() || typeof leaseToken !== 'string' || !leaseToken.trim()) { throw new Error('Exact package confirmation requires approvalReference, bindingHash, planHash, and leaseToken'); } const inputPackageId = typeof input.packageId === 'string' ? input.packageId.trim() : ''; const inputVersion = typeof input.version === 'string' ? input.version.trim() : ''; return { packageId: inputPackageId || packageId || DEFAULT_PACKAGE_ID, ...(inputVersion ? { version: inputVersion } : options.version ? { version: options.version } : {}), preview: preview, confirmation: { approvalReference: approvalReference.trim(), bindingHash: bindingHash.trim(), planHash: planHash.trim(), }, leaseToken: leaseToken.trim(), }; } export function registerWorkspacePackageCommands(program) { const packages = program .command('workspace-packages') .alias('ws-packages') .description('Inspect and install managed workspace packages through the exact paused lifecycle'); withTargetOptions(packages .command('inspect') .description('Inspect eligibility and install state without changing the workspace')) .action(async (packageId, options) => { try { const result = await new AgentledClient() .inspectWorkspacePackage(target(packageId, options.version)); printOutput(result, options.format); } catch (error) { printError(error instanceof Error ? error.message : String(error)); } }); withTargetOptions(packages .command('preview') .description('Create an exact signed, non-mutating package install preview') .requiredOption('--approval-reference <reference>', 'Durable approval or review reference for this exact preview') .option('--resolutions <json>', 'JSON array of fingerprint-bound adopt or preserve decisions') .option('--resolutions-file <path>', 'Path to a JSON array of fingerprint-bound adopt or preserve decisions')) .action(async (packageId, options) => { try { const resolutions = previewResolutions(options); const result = await new AgentledClient().previewWorkspacePackage({ ...target(packageId, options.version), approvalReference: options.approvalReference, ...(resolutions ? { resolutions } : {}), }); printOutput(result, options.format); } catch (error) { printError(error instanceof Error ? error.message : String(error)); } }); withTargetOptions(packages .command('status') .description('Read authoritative package lifecycle state without running installed assets')) .action(async (packageId, options) => { try { const result = await new AgentledClient() .getWorkspacePackageStatus(target(packageId, options.version)); printOutput(result, options.format); } catch (error) { printError(error instanceof Error ? error.message : String(error)); } }); withTargetOptions(packages .command('apply') .description('Apply an exact reviewed preview as paused/draft assets; requires owner/ADMIN and package scope') .option('--input <json>', 'JSON with preview, confirmation, and leaseToken') .option('--file <path>', 'Path to JSON with preview, confirmation, and leaseToken')) .action(async (packageId, options) => { try { const result = await new AgentledClient().applyWorkspacePackage(mutationPayload(packageId, options)); printOutput(result, options.format); } catch (error) { printError(error instanceof Error ? error.message : String(error)); } }); withTargetOptions(packages .command('recover') .description('Resume only pending assets using a fresh exact preview and confirmation') .option('--input <json>', 'JSON with preview, confirmation, and leaseToken') .option('--file <path>', 'Path to JSON with preview, confirmation, and leaseToken')) .action(async (packageId, options) => { try { const result = await new AgentledClient().recoverWorkspacePackage(mutationPayload(packageId, options)); printOutput(result, options.format); } catch (error) { printError(error instanceof Error ? error.message : String(error)); } }); } //# sourceMappingURL=workspace-packages.js.map