forest-cli
Version:
The Lumberjacks' toolbelt is the Forest CLI which makes easy to manage your back office application directly from the terminal.
215 lines • 18.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.planShellUpdate = exports.findWorkflowMatches = exports.parseWorkflowSpec = void 0;
const workflow_bpmn_1 = require("./workflow-bpmn");
const TOP_LEVEL_FIELDS = [
'collection',
'id',
'name',
'position',
'segments',
'start',
'steps',
'version',
];
const STEP_FIELDS = [
'auto',
'autoComplete',
'branches',
'id',
'inboxId',
'mcpServerId',
'next',
'prompt',
'title',
'type',
];
const BRANCH_FIELDS = ['answer', 'color', 'next'];
/**
* Primitive type of each whitelisted field (per level). Checked at parse time
* so a wrongly-typed value (e.g. `mcpServerId: 123`) fails with a clean
* `WorkflowSpecError` instead of crashing inside the BPMN compiler.
* `steps`/`branches` (arrays of objects), `segments` (array of strings) and
* the upsert extras `id`/`position`/`version` have dedicated checks.
*/
const TOP_LEVEL_FIELD_TYPES = {
collection: 'string',
name: 'string',
start: 'string',
};
const STEP_FIELD_TYPES = {
auto: 'boolean',
autoComplete: 'boolean',
id: 'string',
inboxId: 'string',
mcpServerId: 'string',
next: 'string',
prompt: 'string',
title: 'string',
type: 'string',
};
const BRANCH_FIELD_TYPES = {
answer: 'string',
color: 'string',
next: 'string',
};
/** Mirrors the server patch whitelist (`patch-rules.ts` NUM_OR_UUID): a workflow id is numeric or a UUID. */
const WORKFLOW_ID_RE = /^([0-9]+|[0-9a-fA-F-]{36})$/;
/** Case-insensitive Levenshtein distance, for "did you mean" suggestions. */
function editDistance(from, to) {
const a = from.toLowerCase();
const b = to.toLowerCase();
let previous = Array.from({ length: b.length + 1 }, (unused, j) => j);
for (let i = 1; i <= a.length; i += 1) {
const current = [i];
for (let j = 1; j <= b.length; j += 1) {
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
}
previous = current;
}
return previous[b.length];
}
function unknownFieldError(key, validFields, where) {
const [best] = validFields
.map(candidate => ({ candidate, distance: editDistance(key, candidate) }))
.sort((left, right) => left.distance - right.distance);
const hint = best && best.distance <= 2
? `did you mean \`${best.candidate}\`?`
: `valid fields: ${validFields.join(', ')}.`;
return new workflow_bpmn_1.WorkflowSpecError(`Unknown field "${key}"${where} — ${hint}`);
}
function assertKnownFields(value, validFields, where) {
Object.keys(value).forEach(key => {
if (!validFields.includes(key))
throw unknownFieldError(key, validFields, where);
});
}
function assertFieldTypes(value, types, where) {
Object.entries(types).forEach(([key, expected]) => {
const actual = value[key];
if (actual !== undefined && typeof actual !== expected) {
throw new workflow_bpmn_1.WorkflowSpecError(`\`${key}\` must be a ${expected}${where} (got ${JSON.stringify(actual)}).`);
}
});
}
function assertBranchesShape(branches, stepWhere) {
if (branches === undefined)
return;
if (!Array.isArray(branches)) {
throw new workflow_bpmn_1.WorkflowSpecError(`\`branches\` must be an array${stepWhere} (got ${JSON.stringify(branches)}).`);
}
branches.forEach((branch, index) => {
if (!branch || typeof branch !== 'object' || Array.isArray(branch)) {
throw new workflow_bpmn_1.WorkflowSpecError(`\`branches[${index}]\` must be a JSON object${stepWhere}.`);
}
assertKnownFields(branch, BRANCH_FIELDS, stepWhere);
assertFieldTypes(branch, BRANCH_FIELD_TYPES, stepWhere);
});
}
function assertStepsShape(steps) {
if (!Array.isArray(steps))
return; // validateWorkflowSpec produces the canonical error.
steps.forEach((step, index) => {
if (!step || typeof step !== 'object' || Array.isArray(step)) {
throw new workflow_bpmn_1.WorkflowSpecError(`\`steps[${index}]\` must be a JSON object.`);
}
const record = step;
const stepWhere = ` in step "${record.id ?? `#${index}`}"`;
assertKnownFields(record, STEP_FIELDS, stepWhere);
assertFieldTypes(record, STEP_FIELD_TYPES, stepWhere);
assertBranchesShape(record.branches, stepWhere);
});
}
function assertTopLevelShape(spec) {
assertFieldTypes(spec, TOP_LEVEL_FIELD_TYPES, '');
if (spec.segments !== undefined &&
(!Array.isArray(spec.segments) ||
spec.segments.some(segment => typeof segment !== 'string'))) {
throw new workflow_bpmn_1.WorkflowSpecError(`\`segments\` must be an array of segment ids (strings) (got ${JSON.stringify(spec.segments)}).`);
}
}
function assertUpsertExtras(spec) {
if (spec.version !== undefined && spec.version !== 1) {
throw new workflow_bpmn_1.WorkflowSpecError(`Unsupported spec \`version\` ${JSON.stringify(spec.version)} — this toolbelt supports version 1 (or omit it).`);
}
if (spec.id !== undefined && (typeof spec.id !== 'string' || !WORKFLOW_ID_RE.test(spec.id))) {
throw new workflow_bpmn_1.WorkflowSpecError(`\`id\` must be an existing workflow id — a number or a UUID (got ${JSON.stringify(spec.id)}). Omit it to match by name + collection.`);
}
if (spec.position !== undefined &&
(typeof spec.position !== 'number' || !Number.isInteger(spec.position) || spec.position < 0)) {
throw new workflow_bpmn_1.WorkflowSpecError(`\`position\` must be a non-negative integer (got ${JSON.stringify(spec.position)}).`);
}
}
/**
* Parse the raw JSON of a `workflow apply` spec, strictly: clean JSON errors,
* top-level/step/branch fields are whitelisted (typo-safe: "did you mean?")
* and type-checked, `version` is absent-or-1 and `id`/`position` are
* format-checked. Semantic
* validation of the step graph stays in `validateWorkflowSpec` (shared with
* the layout path, which must remain lenient about extra keys).
*/
function parseWorkflowSpec(raw) {
let parsed;
try {
parsed = JSON.parse(raw);
}
catch (error) {
throw new workflow_bpmn_1.WorkflowSpecError(`Invalid JSON in spec: ${error instanceof Error ? error.message : String(error)}`);
}
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new workflow_bpmn_1.WorkflowSpecError('The spec must be a JSON object: { name, collection, steps, id?, segments?, position?, start?, version? }.');
}
const spec = parsed;
assertKnownFields(parsed, TOP_LEVEL_FIELDS, '');
assertTopLevelShape(parsed);
assertStepsShape(spec.steps);
assertUpsertExtras(spec);
return spec;
}
exports.parseWorkflowSpec = parseWorkflowSpec;
/**
* The workflows the spec designates, in remote order: all of them by explicit
* `id`, else by name + collection. More than one match means the environment
* holds duplicates — the caller warns and updates the first.
*/
function findWorkflowMatches(existing, spec) {
if (spec.id)
return existing.filter(workflow => String(workflow.id) === spec.id);
return existing.filter(workflow => workflow.name === spec.name && workflow.collectionId === spec.collection);
}
exports.findWorkflowMatches = findWorkflowMatches;
/**
* The metadata `replace` ops an update needs so the spec stays the source of
* truth: `name` and `segments` are always converged (an omitted `segments`
* means "no segments"); `position` only when the spec pins one — the remote
* ordering is otherwise left alone.
*/
function planShellUpdate(current, spec) {
const changes = [];
const base = `/workflows/${current.id}`;
if (spec.name !== undefined && spec.name !== current.name) {
changes.push({
field: 'name',
label: `name: "${current.name}" → "${spec.name}"`,
op: { op: 'replace', path: `${base}/name`, value: spec.name },
});
}
const segments = spec.segments ?? [];
if (JSON.stringify(segments) !== JSON.stringify(current.segmentIds ?? [])) {
changes.push({
field: 'segments',
label: `segments: [${(current.segmentIds ?? []).join(', ')}] → [${segments.join(', ')}]`,
op: { op: 'replace', path: `${base}/segmentIds`, value: segments },
});
}
if (spec.position !== undefined && spec.position !== current.position) {
changes.push({
field: 'position',
label: `position: ${current.position ?? '?'} → ${spec.position}`,
op: { op: 'replace', path: `${base}/position`, value: spec.position },
});
}
return changes;
}
exports.planShellUpdate = planShellUpdate;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2Zsb3ctYXBwbHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvbGF5b3V0L3dvcmtmbG93LWFwcGx5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQVVBLG1EQUFvRDtBQTBCcEQsTUFBTSxnQkFBZ0IsR0FBRztJQUN2QixZQUFZO0lBQ1osSUFBSTtJQUNKLE1BQU07SUFDTixVQUFVO0lBQ1YsVUFBVTtJQUNWLE9BQU87SUFDUCxPQUFPO0lBQ1AsU0FBUztDQUNWLENBQUM7QUFFRixNQUFNLFdBQVcsR0FBRztJQUNsQixNQUFNO0lBQ04sY0FBYztJQUNkLFVBQVU7SUFDVixJQUFJO0lBQ0osU0FBUztJQUNULGFBQWE7SUFDYixNQUFNO0lBQ04sUUFBUTtJQUNSLE9BQU87SUFDUCxNQUFNO0NBQ1AsQ0FBQztBQUVGLE1BQU0sYUFBYSxHQUFHLENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztBQUVsRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLHFCQUFxQixHQUF5QztJQUNsRSxVQUFVLEVBQUUsUUFBUTtJQUNwQixJQUFJLEVBQUUsUUFBUTtJQUNkLEtBQUssRUFBRSxRQUFRO0NBQ2hCLENBQUM7QUFFRixNQUFNLGdCQUFnQixHQUF5QztJQUM3RCxJQUFJLEVBQUUsU0FBUztJQUNmLFlBQVksRUFBRSxTQUFTO0lBQ3ZCLEVBQUUsRUFBRSxRQUFRO0lBQ1osT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLFFBQVE7SUFDckIsSUFBSSxFQUFFLFFBQVE7SUFDZCxNQUFNLEVBQUUsUUFBUTtJQUNoQixLQUFLLEVBQUUsUUFBUTtJQUNmLElBQUksRUFBRSxRQUFRO0NBQ2YsQ0FBQztBQUVGLE1BQU0sa0JBQWtCLEdBQXlDO0lBQy9ELE1BQU0sRUFBRSxRQUFRO0lBQ2hCLEtBQUssRUFBRSxRQUFRO0lBQ2YsSUFBSSxFQUFFLFFBQVE7Q0FDZixDQUFDO0FBRUYsNkdBQTZHO0FB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