UNPKG

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
"use strict"; 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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