@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
JavaScript
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