@mesh-tech/mesh-cli 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/mesh.js +343 -28
- package/dist/bin/mesh.js.map +3 -3
- package/dist/build-info.json +2 -2
- package/dist/src/commands/workflow.d.ts.map +1 -1
- package/dist/src/commands/workflow.js +26 -9
- package/dist/src/commands/workflow.js.map +1 -1
- package/package.json +3 -3
- package/skills/core/SKILL.md +1 -1
package/dist/bin/mesh.js
CHANGED
|
@@ -21134,7 +21134,9 @@ function computeHappyPath(nodes, edges) {
|
|
|
21134
21134
|
);
|
|
21135
21135
|
const allEndIds = new Set(endNodes.map((n) => n.id));
|
|
21136
21136
|
function bfs(targetIds, allowExceptional) {
|
|
21137
|
-
const queue = [
|
|
21137
|
+
const queue = [
|
|
21138
|
+
{ id: startNode.id, path: [startNode.id] }
|
|
21139
|
+
];
|
|
21138
21140
|
const visited = /* @__PURE__ */ new Set([startNode.id]);
|
|
21139
21141
|
while (queue.length > 0) {
|
|
21140
21142
|
const { id, path: path44 } = queue.shift();
|
|
@@ -21155,7 +21157,8 @@ function computeHappyPath(nodes, edges) {
|
|
|
21155
21157
|
});
|
|
21156
21158
|
for (const neighbor of sorted) {
|
|
21157
21159
|
if (visited.has(neighbor.to)) continue;
|
|
21158
|
-
if (!allowExceptional && (neighbor.isExceptional || neighbor.isTimeout || failureEndIds.has(neighbor.to)))
|
|
21160
|
+
if (!allowExceptional && (neighbor.isExceptional || neighbor.isTimeout || failureEndIds.has(neighbor.to)))
|
|
21161
|
+
continue;
|
|
21159
21162
|
visited.add(neighbor.to);
|
|
21160
21163
|
queue.push({ id: neighbor.to, path: [...path44, neighbor.to] });
|
|
21161
21164
|
}
|
|
@@ -21164,6 +21167,37 @@ function computeHappyPath(nodes, edges) {
|
|
|
21164
21167
|
}
|
|
21165
21168
|
return bfs(successEndIds, false) ?? bfs(allEndIds, false) ?? bfs(allEndIds, true) ?? [];
|
|
21166
21169
|
}
|
|
21170
|
+
function isProcessArtifactProvenance(value) {
|
|
21171
|
+
return typeof value === "object" && value !== null && value.source === "process-artifact";
|
|
21172
|
+
}
|
|
21173
|
+
function childGraphsOf(node) {
|
|
21174
|
+
const graphs = [];
|
|
21175
|
+
const withChild = node;
|
|
21176
|
+
if (withChild.childGraph) graphs.push(withChild.childGraph);
|
|
21177
|
+
const withBacking = node;
|
|
21178
|
+
if (withBacking.backing?.backingGraph) graphs.push(withBacking.backing.backingGraph);
|
|
21179
|
+
return graphs;
|
|
21180
|
+
}
|
|
21181
|
+
function walkProcessNodes(ir, scope = []) {
|
|
21182
|
+
const out = [];
|
|
21183
|
+
for (const node of ir.nodes) {
|
|
21184
|
+
if (isProcessArtifactProvenance(node.provenance)) {
|
|
21185
|
+
out.push({ nodeId: node.id, scope, node, provenance: node.provenance });
|
|
21186
|
+
}
|
|
21187
|
+
for (const child of childGraphsOf(node)) {
|
|
21188
|
+
out.push(...walkProcessNodes(child, [...scope, node.id]));
|
|
21189
|
+
}
|
|
21190
|
+
}
|
|
21191
|
+
return out;
|
|
21192
|
+
}
|
|
21193
|
+
function findProcessNodesByCommand(ir, command) {
|
|
21194
|
+
return walkProcessNodes(ir).filter((m) => m.provenance.bind?.commands?.includes(command));
|
|
21195
|
+
}
|
|
21196
|
+
function findProcessNodesByElementId(ir, elementId, element) {
|
|
21197
|
+
return walkProcessNodes(ir).filter(
|
|
21198
|
+
(m) => m.provenance.elementId === elementId && (element === void 0 || m.provenance.element === element)
|
|
21199
|
+
);
|
|
21200
|
+
}
|
|
21167
21201
|
function cloneWorkflow(workflow) {
|
|
21168
21202
|
return JSON.parse(JSON.stringify(workflow));
|
|
21169
21203
|
}
|
|
@@ -21215,13 +21249,17 @@ function sanitizeMainPath(workflow, mainPath) {
|
|
|
21215
21249
|
}
|
|
21216
21250
|
function getChildGraph(node) {
|
|
21217
21251
|
if ("childGraph" in node && node.childGraph) return node.childGraph;
|
|
21218
|
-
if ("backing" in node && node.backing?.backingGraph)
|
|
21252
|
+
if ("backing" in node && node.backing?.backingGraph)
|
|
21253
|
+
return node.backing.backingGraph;
|
|
21219
21254
|
return null;
|
|
21220
21255
|
}
|
|
21221
21256
|
function setChildGraph(node, childGraph) {
|
|
21222
21257
|
if ("childGraph" in node) return { ...node, childGraph };
|
|
21223
21258
|
if ("backing" in node && node.backing?.backingGraph) {
|
|
21224
|
-
return {
|
|
21259
|
+
return {
|
|
21260
|
+
...node,
|
|
21261
|
+
backing: { ...node.backing, backingGraph: childGraph }
|
|
21262
|
+
};
|
|
21225
21263
|
}
|
|
21226
21264
|
return { ...node, childGraph };
|
|
21227
21265
|
}
|
|
@@ -21378,7 +21416,9 @@ function wrapIntoGroup(workflow, nodeIds, groupId, label, groupType) {
|
|
|
21378
21416
|
let mainBody = inParentMain.length ? inParentMain : nodeIds;
|
|
21379
21417
|
let mainTail = [];
|
|
21380
21418
|
if (successExit) {
|
|
21381
|
-
const exitSources = new Set(
|
|
21419
|
+
const exitSources = new Set(
|
|
21420
|
+
exitChildEdges.filter((e) => e.to === successExit.id).map((e) => e.from)
|
|
21421
|
+
);
|
|
21382
21422
|
const adj = /* @__PURE__ */ new Map();
|
|
21383
21423
|
for (const e of internal) {
|
|
21384
21424
|
if (e.isExceptional || e.isTimeout) continue;
|
|
@@ -21417,7 +21457,11 @@ function wrapIntoGroup(workflow, nodeIds, groupId, label, groupType) {
|
|
|
21417
21457
|
childGraph = {
|
|
21418
21458
|
name: label,
|
|
21419
21459
|
description: "",
|
|
21420
|
-
nodes: [
|
|
21460
|
+
nodes: [
|
|
21461
|
+
{ id: startId, type: "start", label: "Start" },
|
|
21462
|
+
...groupedNodes,
|
|
21463
|
+
...extraChildNodes
|
|
21464
|
+
],
|
|
21421
21465
|
edges: [
|
|
21422
21466
|
{ from: startId, to: entry, isMainPath: true },
|
|
21423
21467
|
...internal.map(markMain),
|
|
@@ -21426,7 +21470,13 @@ function wrapIntoGroup(workflow, nodeIds, groupId, label, groupType) {
|
|
|
21426
21470
|
mainPath: [startId, ...mainBody, ...mainTail]
|
|
21427
21471
|
};
|
|
21428
21472
|
}
|
|
21429
|
-
const groupNode = {
|
|
21473
|
+
const groupNode = {
|
|
21474
|
+
id: groupId,
|
|
21475
|
+
type: "group",
|
|
21476
|
+
groupType,
|
|
21477
|
+
label,
|
|
21478
|
+
childGraph
|
|
21479
|
+
};
|
|
21430
21480
|
const newNodes = [];
|
|
21431
21481
|
let placed = false;
|
|
21432
21482
|
for (const n of workflow.nodes) {
|
|
@@ -21472,7 +21522,10 @@ function applyWorkflowPatch(workflow, patch) {
|
|
|
21472
21522
|
return applyScopedPatch(workflow, patch.scope, patch);
|
|
21473
21523
|
}
|
|
21474
21524
|
if (patch.op === "batch") {
|
|
21475
|
-
return patch.patches.reduce(
|
|
21525
|
+
return patch.patches.reduce(
|
|
21526
|
+
(current, operation) => applyWorkflowPatch(current, operation),
|
|
21527
|
+
workflow
|
|
21528
|
+
);
|
|
21476
21529
|
}
|
|
21477
21530
|
if (patch.op === "replace") {
|
|
21478
21531
|
return cloneWorkflow(patch.workflow);
|
|
@@ -21506,7 +21559,9 @@ function applyWorkflowPatch(workflow, patch) {
|
|
|
21506
21559
|
next.mainPath = next.mainPath.filter((nodeId) => nodeId !== patch.nodeId);
|
|
21507
21560
|
const shouldRemoveEdges = patch.removeAttachedEdges ?? true;
|
|
21508
21561
|
if (shouldRemoveEdges) {
|
|
21509
|
-
next.edges = next.edges.filter(
|
|
21562
|
+
next.edges = next.edges.filter(
|
|
21563
|
+
(edge) => edge.from !== patch.nodeId && edge.to !== patch.nodeId
|
|
21564
|
+
);
|
|
21510
21565
|
}
|
|
21511
21566
|
return next;
|
|
21512
21567
|
}
|
|
@@ -21554,7 +21609,13 @@ function applyWorkflowPatch(workflow, patch) {
|
|
|
21554
21609
|
return next;
|
|
21555
21610
|
}
|
|
21556
21611
|
case "group": {
|
|
21557
|
-
return wrapIntoGroup(
|
|
21612
|
+
return wrapIntoGroup(
|
|
21613
|
+
next,
|
|
21614
|
+
patch.nodeIds,
|
|
21615
|
+
patch.groupId,
|
|
21616
|
+
patch.label,
|
|
21617
|
+
patch.groupType ?? "function"
|
|
21618
|
+
);
|
|
21558
21619
|
}
|
|
21559
21620
|
case "setMainPath": {
|
|
21560
21621
|
next.mainPath = sanitizeMainPath(next, patch.mainPath);
|
|
@@ -21852,6 +21913,78 @@ var init_change_counts = __esm({
|
|
|
21852
21913
|
|
|
21853
21914
|
// libs/workflow-model/src/process-artifact.ts
|
|
21854
21915
|
import { z as z4 } from "zod";
|
|
21916
|
+
function outcomeTriggers(outcome) {
|
|
21917
|
+
const raw = Array.isArray(outcome.when) ? outcome.when : [outcome.when];
|
|
21918
|
+
return raw.map((trigger) => {
|
|
21919
|
+
if ("predicate" in trigger) return { kind: "predicate", name: trigger.predicate };
|
|
21920
|
+
if ("timeoutOf" in trigger) return { kind: "timeout", name: trigger.timeoutOf };
|
|
21921
|
+
return { kind: "command", name: trigger.command };
|
|
21922
|
+
});
|
|
21923
|
+
}
|
|
21924
|
+
function resolveSubstepActor(artifact, stage, substep) {
|
|
21925
|
+
const actorId = substep.actor ?? stage.actor;
|
|
21926
|
+
if (!actorId) return void 0;
|
|
21927
|
+
const actor = artifact.process.actors[actorId];
|
|
21928
|
+
if (!actor) return void 0;
|
|
21929
|
+
return {
|
|
21930
|
+
id: actorId,
|
|
21931
|
+
label: actor.label,
|
|
21932
|
+
...actor.category ? { category: actor.category } : {},
|
|
21933
|
+
...substep.selector ?? actor.selector ? { selector: substep.selector ?? actor.selector } : {},
|
|
21934
|
+
...actor.cardinality ? { cardinality: actor.cardinality } : {}
|
|
21935
|
+
};
|
|
21936
|
+
}
|
|
21937
|
+
function resolveActorRef(artifact, actorId) {
|
|
21938
|
+
const actor = artifact.process.actors[actorId];
|
|
21939
|
+
if (!actor) return void 0;
|
|
21940
|
+
return {
|
|
21941
|
+
id: actorId,
|
|
21942
|
+
label: actor.label,
|
|
21943
|
+
...actor.category ? { category: actor.category } : {},
|
|
21944
|
+
...actor.selector ? { selector: actor.selector } : {},
|
|
21945
|
+
...actor.cardinality ? { cardinality: actor.cardinality } : {}
|
|
21946
|
+
};
|
|
21947
|
+
}
|
|
21948
|
+
function buildProcessManifest(artifact, outcomeNodeIds) {
|
|
21949
|
+
const { process: process2 } = artifact;
|
|
21950
|
+
const actors = {};
|
|
21951
|
+
for (const actorId of Object.keys(process2.actors)) {
|
|
21952
|
+
actors[actorId] = resolveActorRef(artifact, actorId);
|
|
21953
|
+
}
|
|
21954
|
+
let selectors;
|
|
21955
|
+
if (process2.selectors) {
|
|
21956
|
+
selectors = {};
|
|
21957
|
+
for (const [name, selector] of Object.entries(process2.selectors)) {
|
|
21958
|
+
selectors[name] = {
|
|
21959
|
+
name,
|
|
21960
|
+
label: selector.label,
|
|
21961
|
+
...selector.description ? { description: selector.description } : {}
|
|
21962
|
+
};
|
|
21963
|
+
}
|
|
21964
|
+
}
|
|
21965
|
+
const outcomes = process2.outcomes.map((outcome) => {
|
|
21966
|
+
const nodeId = outcomeNodeIds?.get(outcome.id);
|
|
21967
|
+
return {
|
|
21968
|
+
id: outcome.id,
|
|
21969
|
+
label: outcome.label,
|
|
21970
|
+
kind: outcome.kind,
|
|
21971
|
+
triggers: outcomeTriggers(outcome),
|
|
21972
|
+
...outcome.description ? { description: outcome.description } : {},
|
|
21973
|
+
...nodeId ? { nodeId } : {}
|
|
21974
|
+
};
|
|
21975
|
+
});
|
|
21976
|
+
const pointOfNoReturnStage = process2.stages.find((stage) => stage.pointOfNoReturn);
|
|
21977
|
+
return {
|
|
21978
|
+
source: "process-artifact",
|
|
21979
|
+
artifactVersion: process2.version,
|
|
21980
|
+
revision: process2.revision,
|
|
21981
|
+
workflowType: process2.workflowType,
|
|
21982
|
+
actors,
|
|
21983
|
+
...selectors ? { selectors } : {},
|
|
21984
|
+
outcomes,
|
|
21985
|
+
...pointOfNoReturnStage ? { pointOfNoReturnStageId: pointOfNoReturnStage.id } : {}
|
|
21986
|
+
};
|
|
21987
|
+
}
|
|
21855
21988
|
function formatPath(path44) {
|
|
21856
21989
|
return path44.length > 0 ? z4.core.toDotPath(path44) : "(root)";
|
|
21857
21990
|
}
|
|
@@ -21871,19 +22004,74 @@ function issueToDiagnostic(issue) {
|
|
|
21871
22004
|
path: path44
|
|
21872
22005
|
};
|
|
21873
22006
|
}
|
|
22007
|
+
function upgradeV1(artifact) {
|
|
22008
|
+
const diagnostics = [
|
|
22009
|
+
{
|
|
22010
|
+
severity: "warning",
|
|
22011
|
+
code: "DEPRECATED_ARTIFACT_VERSION",
|
|
22012
|
+
message: `process.version: artifact is version 1; upgraded in memory to version ${CURRENT_PROCESS_VERSION}. Migrate the file (add process.revision, declare actor categories/selectors) \u2014 version 1 is a deprecated input, not a second authoring format.`,
|
|
22013
|
+
path: "process.version"
|
|
22014
|
+
},
|
|
22015
|
+
{
|
|
22016
|
+
severity: "warning",
|
|
22017
|
+
code: "MISSING_PROCESS_REVISION",
|
|
22018
|
+
message: `process.revision: version 1 has no revision; recorded as "${UNVERSIONED_REVISION}". Anything pinned to this artifact cannot name which version of the process it ran.`,
|
|
22019
|
+
path: "process.revision"
|
|
22020
|
+
}
|
|
22021
|
+
];
|
|
22022
|
+
const process2 = artifact.process;
|
|
22023
|
+
const actors = {};
|
|
22024
|
+
for (const [actorId, actor] of Object.entries(process2.actors)) {
|
|
22025
|
+
const legacyCategory = LEGACY_V1_ACTOR_CATEGORY[actorId];
|
|
22026
|
+
actors[actorId] = {
|
|
22027
|
+
...actor,
|
|
22028
|
+
...actor.category === void 0 && legacyCategory ? { category: legacyCategory } : {}
|
|
22029
|
+
};
|
|
22030
|
+
}
|
|
22031
|
+
return {
|
|
22032
|
+
artifact: {
|
|
22033
|
+
...artifact,
|
|
22034
|
+
process: {
|
|
22035
|
+
...process2,
|
|
22036
|
+
version: CURRENT_PROCESS_VERSION,
|
|
22037
|
+
revision: UNVERSIONED_REVISION,
|
|
22038
|
+
actors
|
|
22039
|
+
}
|
|
22040
|
+
},
|
|
22041
|
+
diagnostics
|
|
22042
|
+
};
|
|
22043
|
+
}
|
|
21874
22044
|
function parseProcessArtifact(json) {
|
|
21875
22045
|
const result = processArtifactSchema.safeParse(json);
|
|
21876
|
-
if (result.success) {
|
|
21877
|
-
return {
|
|
22046
|
+
if (!result.success) {
|
|
22047
|
+
return { diagnostics: result.error.issues.map(issueToDiagnostic) };
|
|
21878
22048
|
}
|
|
21879
|
-
|
|
22049
|
+
if (result.data.process.version < CURRENT_PROCESS_VERSION) {
|
|
22050
|
+
return upgradeV1(result.data);
|
|
22051
|
+
}
|
|
22052
|
+
return { artifact: result.data, diagnostics: [] };
|
|
21880
22053
|
}
|
|
21881
|
-
var actorSchema, substepBindSchema, substepSchema, outcomeWhenSchema, outcomeSchema, stageCompleteSchema, stageSchema, processBlockSchema, processArtifactSchema;
|
|
22054
|
+
var CURRENT_PROCESS_VERSION, SUPPORTED_PROCESS_VERSIONS, UNVERSIONED_REVISION, LEGACY_V1_ACTOR_CATEGORY, actorSchema, selectorSchema, substepBindSchema, substepSchema, outcomeTriggerSchema, outcomeWhenSchema, outcomeSchema, stageCompleteSchema, stageSchema, processBlockSchema, processArtifactSchema;
|
|
21882
22055
|
var init_process_artifact = __esm({
|
|
21883
22056
|
"libs/workflow-model/src/process-artifact.ts"() {
|
|
21884
22057
|
"use strict";
|
|
22058
|
+
CURRENT_PROCESS_VERSION = 2;
|
|
22059
|
+
SUPPORTED_PROCESS_VERSIONS = [1, 2];
|
|
22060
|
+
UNVERSIONED_REVISION = "unversioned";
|
|
22061
|
+
LEGACY_V1_ACTOR_CATEGORY = {
|
|
22062
|
+
customer: "human",
|
|
22063
|
+
banker: "approval",
|
|
22064
|
+
system: "data"
|
|
22065
|
+
};
|
|
21885
22066
|
actorSchema = z4.object({
|
|
21886
|
-
label: z4.string()
|
|
22067
|
+
label: z4.string(),
|
|
22068
|
+
category: z4.string().min(1).optional(),
|
|
22069
|
+
selector: z4.string().min(1).optional(),
|
|
22070
|
+
cardinality: z4.enum(["one", "many"]).optional()
|
|
22071
|
+
}).strict();
|
|
22072
|
+
selectorSchema = z4.object({
|
|
22073
|
+
label: z4.string(),
|
|
22074
|
+
description: z4.string().optional()
|
|
21887
22075
|
}).strict();
|
|
21888
22076
|
substepBindSchema = z4.object({
|
|
21889
22077
|
commands: z4.array(z4.string()).optional(),
|
|
@@ -21901,11 +22089,30 @@ var init_process_artifact = __esm({
|
|
|
21901
22089
|
id: z4.string(),
|
|
21902
22090
|
label: z4.string(),
|
|
21903
22091
|
actor: z4.string().optional(),
|
|
22092
|
+
/**
|
|
22093
|
+
* Overrides the actor's own `selector` for this substep only — the case
|
|
22094
|
+
* where one cast entry is resolved differently at one step (a handoff
|
|
22095
|
+
* target, an escalation pool). Must be declared in `process.selectors`.
|
|
22096
|
+
*/
|
|
22097
|
+
selector: z4.string().min(1).optional(),
|
|
21904
22098
|
bind: substepBindSchema
|
|
21905
22099
|
}).strict();
|
|
22100
|
+
outcomeTriggerSchema = z4.union([
|
|
22101
|
+
z4.object({ predicate: z4.string().min(1) }).strict(),
|
|
22102
|
+
z4.object({ timeoutOf: z4.string().min(1) }).strict(),
|
|
22103
|
+
z4.object({ command: z4.string().min(1) }).strict()
|
|
22104
|
+
]);
|
|
21906
22105
|
outcomeWhenSchema = z4.union([
|
|
21907
|
-
|
|
21908
|
-
z4.
|
|
22106
|
+
outcomeTriggerSchema,
|
|
22107
|
+
z4.array(outcomeTriggerSchema).superRefine((triggers, ctx) => {
|
|
22108
|
+
if (triggers.length === 0) {
|
|
22109
|
+
ctx.addIssue({
|
|
22110
|
+
code: "custom",
|
|
22111
|
+
message: "when must declare at least one trigger",
|
|
22112
|
+
params: { code: "EMPTY_OUTCOME_TRIGGER" }
|
|
22113
|
+
});
|
|
22114
|
+
}
|
|
22115
|
+
})
|
|
21909
22116
|
]);
|
|
21910
22117
|
outcomeSchema = z4.object({
|
|
21911
22118
|
id: z4.string(),
|
|
@@ -21928,20 +22135,64 @@ var init_process_artifact = __esm({
|
|
|
21928
22135
|
}).strict();
|
|
21929
22136
|
processBlockSchema = z4.object({
|
|
21930
22137
|
version: z4.number(),
|
|
22138
|
+
/**
|
|
22139
|
+
* Pinned identity of this authored content. Opaque to the platform —
|
|
22140
|
+
* a date, a semver, a content hash, a monotonic counter all work. What
|
|
22141
|
+
* matters is that changing the process changes it, so an execution can
|
|
22142
|
+
* be pinned to the revision it started under. Required from V2; a V1
|
|
22143
|
+
* artifact is upgraded with {@link UNVERSIONED_REVISION} and a warning.
|
|
22144
|
+
*/
|
|
22145
|
+
revision: z4.string().min(1).optional(),
|
|
21931
22146
|
workflowType: z4.string(),
|
|
21932
22147
|
actors: z4.record(z4.string(), actorSchema),
|
|
22148
|
+
/** Named selector registry — every `selector` reference resolves here. */
|
|
22149
|
+
selectors: z4.record(z4.string(), selectorSchema).optional(),
|
|
21933
22150
|
stages: z4.array(stageSchema),
|
|
21934
22151
|
outcomes: z4.array(outcomeSchema),
|
|
21935
22152
|
internalCommands: z4.array(z4.string()).optional()
|
|
21936
22153
|
}).strict().superRefine((process2, ctx) => {
|
|
21937
|
-
if (process2.version
|
|
22154
|
+
if (!SUPPORTED_PROCESS_VERSIONS.includes(process2.version)) {
|
|
21938
22155
|
ctx.addIssue({
|
|
21939
22156
|
code: "custom",
|
|
21940
22157
|
path: ["version"],
|
|
21941
|
-
message: `Unsupported process.version ${JSON.stringify(process2.version)}; this parser
|
|
22158
|
+
message: `Unsupported process.version ${JSON.stringify(process2.version)}; this parser understands ${SUPPORTED_PROCESS_VERSIONS.join(" and ")}. Upgrade the parser or downgrade the artifact.`,
|
|
21942
22159
|
params: { code: "UNSUPPORTED_VERSION" }
|
|
21943
22160
|
});
|
|
21944
22161
|
}
|
|
22162
|
+
if (process2.version >= CURRENT_PROCESS_VERSION && process2.revision === void 0) {
|
|
22163
|
+
ctx.addIssue({
|
|
22164
|
+
code: "custom",
|
|
22165
|
+
path: ["revision"],
|
|
22166
|
+
message: `process.revision is required from version ${CURRENT_PROCESS_VERSION}. Give this authored content a pinned identity (a date, a semver, or a content hash) so an execution can name the revision it is running.`,
|
|
22167
|
+
params: { code: "MISSING_PROCESS_REVISION" }
|
|
22168
|
+
});
|
|
22169
|
+
}
|
|
22170
|
+
const declaredSelectors = new Set(Object.keys(process2.selectors ?? {}));
|
|
22171
|
+
const checkActor = (actorId, path44) => {
|
|
22172
|
+
if (actorId === void 0) return;
|
|
22173
|
+
if (!Object.prototype.hasOwnProperty.call(process2.actors, actorId)) {
|
|
22174
|
+
ctx.addIssue({
|
|
22175
|
+
code: "custom",
|
|
22176
|
+
path: path44,
|
|
22177
|
+
message: `Actor "${actorId}" is referenced at ${z4.core.toDotPath(path44)} but not declared in process.actors. Declare the actor (label, and optionally category/selector) or fix the reference.`,
|
|
22178
|
+
params: { code: "UNDECLARED_ACTOR" }
|
|
22179
|
+
});
|
|
22180
|
+
}
|
|
22181
|
+
};
|
|
22182
|
+
const checkSelector = (selector, path44) => {
|
|
22183
|
+
if (selector === void 0) return;
|
|
22184
|
+
if (!declaredSelectors.has(selector)) {
|
|
22185
|
+
ctx.addIssue({
|
|
22186
|
+
code: "custom",
|
|
22187
|
+
path: path44,
|
|
22188
|
+
message: `Selector "${selector}" is referenced at ${z4.core.toDotPath(path44)} but not declared in process.selectors. Declare the selector or fix the reference.`,
|
|
22189
|
+
params: { code: "UNDECLARED_SELECTOR" }
|
|
22190
|
+
});
|
|
22191
|
+
}
|
|
22192
|
+
};
|
|
22193
|
+
for (const [actorId, actor] of Object.entries(process2.actors)) {
|
|
22194
|
+
checkSelector(actor.selector, ["actors", actorId, "selector"]);
|
|
22195
|
+
}
|
|
21945
22196
|
const SAME_KIND_CODE = {
|
|
21946
22197
|
stage: "DUPLICATE_STAGE_ID",
|
|
21947
22198
|
substep: "DUPLICATE_SUBSTEP_ID",
|
|
@@ -21966,8 +22217,17 @@ var init_process_artifact = __esm({
|
|
|
21966
22217
|
};
|
|
21967
22218
|
process2.stages.forEach((stage, stageIndex) => {
|
|
21968
22219
|
checkId(stage.id, "stage", ["stages", stageIndex, "id"]);
|
|
22220
|
+
checkActor(stage.actor, ["stages", stageIndex, "actor"]);
|
|
21969
22221
|
stage.substeps?.forEach((substep, substepIndex) => {
|
|
21970
22222
|
checkId(substep.id, "substep", ["stages", stageIndex, "substeps", substepIndex, "id"]);
|
|
22223
|
+
checkActor(substep.actor, ["stages", stageIndex, "substeps", substepIndex, "actor"]);
|
|
22224
|
+
checkSelector(substep.selector, [
|
|
22225
|
+
"stages",
|
|
22226
|
+
stageIndex,
|
|
22227
|
+
"substeps",
|
|
22228
|
+
substepIndex,
|
|
22229
|
+
"selector"
|
|
22230
|
+
]);
|
|
21971
22231
|
});
|
|
21972
22232
|
});
|
|
21973
22233
|
process2.outcomes.forEach((outcome, outcomeIndex) => {
|
|
@@ -21990,7 +22250,7 @@ function stagePath(stageIndex) {
|
|
|
21990
22250
|
function substepPath(stageIndex, substepIndex) {
|
|
21991
22251
|
return `${stagePath(stageIndex)}.substeps[${substepIndex}]`;
|
|
21992
22252
|
}
|
|
21993
|
-
function lintProcess(artifact, inventory, predicateNames) {
|
|
22253
|
+
function lintProcess(artifact, inventory, predicateNames, options = {}) {
|
|
21994
22254
|
const diagnostics = [];
|
|
21995
22255
|
const process2 = artifact.process;
|
|
21996
22256
|
const commandNames = new Set(inventory.commands.map((c) => c.name));
|
|
@@ -22009,6 +22269,19 @@ function lintProcess(artifact, inventory, predicateNames) {
|
|
|
22009
22269
|
});
|
|
22010
22270
|
}
|
|
22011
22271
|
};
|
|
22272
|
+
if (options.selectorNames) {
|
|
22273
|
+
const selectorSet = new Set(options.selectorNames);
|
|
22274
|
+
for (const [name] of Object.entries(process2.selectors ?? {})) {
|
|
22275
|
+
if (!selectorSet.has(name)) {
|
|
22276
|
+
diagnostics.push({
|
|
22277
|
+
severity: "error",
|
|
22278
|
+
code: "UNKNOWN_SELECTOR",
|
|
22279
|
+
message: `Selector "${name}" declared at process.selectors.${name} is not in the selector registry; the application has no rule resolving it to subjects.`,
|
|
22280
|
+
path: `process.selectors.${name}`
|
|
22281
|
+
});
|
|
22282
|
+
}
|
|
22283
|
+
}
|
|
22284
|
+
}
|
|
22012
22285
|
process2.stages.forEach((stage, stageIndex) => {
|
|
22013
22286
|
const predicatePath = `${stagePath(stageIndex)}.complete.predicate`;
|
|
22014
22287
|
const predicate = stage.complete?.predicate;
|
|
@@ -22050,9 +22323,25 @@ function lintProcess(artifact, inventory, predicateNames) {
|
|
|
22050
22323
|
});
|
|
22051
22324
|
});
|
|
22052
22325
|
process2.outcomes.forEach((outcome, outcomeIndex) => {
|
|
22053
|
-
|
|
22054
|
-
|
|
22055
|
-
|
|
22326
|
+
const whenPath = `process.outcomes[${outcomeIndex}].when`;
|
|
22327
|
+
outcomeTriggers(outcome).forEach((trigger, triggerIndex) => {
|
|
22328
|
+
const path44 = Array.isArray(outcome.when) ? `${whenPath}[${triggerIndex}]` : whenPath;
|
|
22329
|
+
if (trigger.kind === "predicate") {
|
|
22330
|
+
checkPredicate(trigger.name, `${path44}.predicate`);
|
|
22331
|
+
} else if (trigger.kind === "command") {
|
|
22332
|
+
if (!boundCommandPaths.has(trigger.name)) {
|
|
22333
|
+
boundCommandPaths.set(trigger.name, `${path44}.command`);
|
|
22334
|
+
}
|
|
22335
|
+
if (!commandNames.has(trigger.name)) {
|
|
22336
|
+
diagnostics.push({
|
|
22337
|
+
severity: "error",
|
|
22338
|
+
code: "BOUND_COMMAND_NOT_IN_INVENTORY",
|
|
22339
|
+
message: `Command "${trigger.name}" triggering outcome "${outcome.id}" (${path44}.command) does not exist in the inventory.`,
|
|
22340
|
+
path: `${path44}.command`
|
|
22341
|
+
});
|
|
22342
|
+
}
|
|
22343
|
+
}
|
|
22344
|
+
});
|
|
22056
22345
|
});
|
|
22057
22346
|
const hasSuccessOutcome = process2.outcomes.some((o) => o.kind === "success");
|
|
22058
22347
|
const hasFailureOutcome = process2.outcomes.some((o) => o.kind === "failure");
|
|
@@ -22097,7 +22386,7 @@ function lintProcess(artifact, inventory, predicateNames) {
|
|
|
22097
22386
|
diagnostics.push({
|
|
22098
22387
|
severity: "error",
|
|
22099
22388
|
code: "UNBOUND_INVENTORY_COMMAND",
|
|
22100
|
-
message: `Inventory command "${command.name}" is neither bound by any substep nor listed in process.internalCommands.`,
|
|
22389
|
+
message: `Inventory command "${command.name}" is neither bound by any substep, nor named as an outcome trigger, nor listed in process.internalCommands.`,
|
|
22101
22390
|
path: "process.internalCommands"
|
|
22102
22391
|
});
|
|
22103
22392
|
}
|
|
@@ -22115,26 +22404,37 @@ function lintProcess(artifact, inventory, predicateNames) {
|
|
|
22115
22404
|
var init_process_lint = __esm({
|
|
22116
22405
|
"libs/workflow-model/src/process-lint.ts"() {
|
|
22117
22406
|
"use strict";
|
|
22407
|
+
init_process_artifact();
|
|
22118
22408
|
}
|
|
22119
22409
|
});
|
|
22120
22410
|
|
|
22121
22411
|
// libs/workflow-model/src/index.ts
|
|
22122
22412
|
var src_exports2 = {};
|
|
22123
22413
|
__export(src_exports2, {
|
|
22414
|
+
CURRENT_PROCESS_VERSION: () => CURRENT_PROCESS_VERSION,
|
|
22415
|
+
SUPPORTED_PROCESS_VERSIONS: () => SUPPORTED_PROCESS_VERSIONS,
|
|
22416
|
+
UNVERSIONED_REVISION: () => UNVERSIONED_REVISION,
|
|
22124
22417
|
WorkflowPatchError: () => WorkflowPatchError,
|
|
22125
22418
|
WorkflowPatchStream: () => WorkflowPatchStream,
|
|
22126
22419
|
applyPreviewPatch: () => applyPreviewPatch,
|
|
22127
22420
|
applyWorkflowPatch: () => applyWorkflowPatch,
|
|
22128
22421
|
applyWorkflowPatches: () => applyWorkflowPatches,
|
|
22422
|
+
buildProcessManifest: () => buildProcessManifest,
|
|
22129
22423
|
computeHappyPath: () => computeHappyPath,
|
|
22130
22424
|
countChanges: () => countChanges,
|
|
22131
22425
|
describeChanges: () => describeChanges,
|
|
22132
22426
|
emptyWorkflowIR: () => emptyWorkflowIR,
|
|
22427
|
+
findProcessNodesByCommand: () => findProcessNodesByCommand,
|
|
22428
|
+
findProcessNodesByElementId: () => findProcessNodesByElementId,
|
|
22133
22429
|
lintProcess: () => lintProcess,
|
|
22430
|
+
outcomeTriggers: () => outcomeTriggers,
|
|
22134
22431
|
parseProcessArtifact: () => parseProcessArtifact,
|
|
22135
22432
|
processArtifactSchema: () => processArtifactSchema,
|
|
22433
|
+
resolveActorRef: () => resolveActorRef,
|
|
22434
|
+
resolveSubstepActor: () => resolveSubstepActor,
|
|
22136
22435
|
validateWorkflowIR: () => validateWorkflowIR,
|
|
22137
|
-
validateWorkflowPatches: () => validateWorkflowPatches
|
|
22436
|
+
validateWorkflowPatches: () => validateWorkflowPatches,
|
|
22437
|
+
walkProcessNodes: () => walkProcessNodes
|
|
22138
22438
|
});
|
|
22139
22439
|
var init_src3 = __esm({
|
|
22140
22440
|
"libs/workflow-model/src/index.ts"() {
|
|
@@ -22358,6 +22658,9 @@ async function uploadToS3(bucket, appName, workflows) {
|
|
|
22358
22658
|
})
|
|
22359
22659
|
);
|
|
22360
22660
|
}
|
|
22661
|
+
function parseNameList(value) {
|
|
22662
|
+
return value ? value.split(",").map((name) => name.trim()).filter((name) => name.length > 0) : void 0;
|
|
22663
|
+
}
|
|
22361
22664
|
function registerWorkflowCommands(program2) {
|
|
22362
22665
|
const workflow = program2.command("workflow").description("Workflow tooling \u2014 IR extraction, visualization");
|
|
22363
22666
|
workflow.command("extract-ir <path>").description(
|
|
@@ -22464,13 +22767,16 @@ function registerWorkflowCommands(program2) {
|
|
|
22464
22767
|
}
|
|
22465
22768
|
});
|
|
22466
22769
|
workflow.command("lint-process <path>").description(
|
|
22467
|
-
"Lint a process artifact's bindings against the as-built code inventory\n\nReuses the inventory extraction's aux/activity discovery, resolves the process\nartifact (--process, or the same sibling process/*.process.json discovery\nextract-ir uses), then runs parseProcessArtifact + lintProcess against it.\n\nWithout --predicates, the CLI cannot verify
|
|
22770
|
+
"Lint a process artifact's bindings against the as-built code inventory\n\nReuses the inventory extraction's aux/activity discovery, resolves the process\nartifact (--process, or the same sibling process/*.process.json discovery\nextract-ir uses), then runs parseProcessArtifact + lintProcess against it.\n\nWithout --predicates / --selectors, the CLI cannot verify those names against the\nworker's registries (it has no way to execute them) \u2014 the corresponding findings\nare skipped and a note is printed; every other rule (bindings, coverage, ids,\nactors, outcomes, workflowType) still runs. Pass both for full conformance, or rely\non the worker's own process-conformance test which has the registries in-process."
|
|
22468
22771
|
).option(
|
|
22469
22772
|
"--process <path>",
|
|
22470
22773
|
"Path to a process artifact JSON file. Absent this flag, a sibling process/*.process.json is auto-discovered per workflow file."
|
|
22471
22774
|
).option(
|
|
22472
22775
|
"--predicates <names>",
|
|
22473
22776
|
"Comma-separated named-predicate registry (enables UNKNOWN_PREDICATE checks)"
|
|
22777
|
+
).option(
|
|
22778
|
+
"--selectors <names>",
|
|
22779
|
+
"Comma-separated named-selector registry (enables UNKNOWN_SELECTOR checks)"
|
|
22474
22780
|
).action(async (targetPath, opts) => {
|
|
22475
22781
|
try {
|
|
22476
22782
|
const resolvedPath = path43.resolve(targetPath);
|
|
@@ -22508,12 +22814,16 @@ function registerWorkflowCommands(program2) {
|
|
|
22508
22814
|
process.exitCode = 1;
|
|
22509
22815
|
return;
|
|
22510
22816
|
}
|
|
22511
|
-
const predicateNames = opts.predicates
|
|
22817
|
+
const predicateNames = parseNameList(opts.predicates);
|
|
22818
|
+
const selectorNames = parseNameList(opts.selectors);
|
|
22512
22819
|
if (!predicateNames) {
|
|
22513
22820
|
logWarn(
|
|
22514
22821
|
"predicate checks skipped \u2014 pass --predicates or run the worker conformance test"
|
|
22515
22822
|
);
|
|
22516
22823
|
}
|
|
22824
|
+
if (!selectorNames) {
|
|
22825
|
+
logWarn("selector checks skipped \u2014 pass --selectors or run the worker conformance test");
|
|
22826
|
+
}
|
|
22517
22827
|
logInfo(`Linting process artifact(s) against ${resolvedPath}`);
|
|
22518
22828
|
const results = runLintExtraction(resolvedPath, extractorPath, resolvedProcessPath);
|
|
22519
22829
|
if (!results || results.length === 0) {
|
|
@@ -22535,7 +22845,12 @@ ${inventory.workflowType} (${sourceFile})`);
|
|
|
22535
22845
|
const { artifact, diagnostics: parseDiagnostics } = parseProcessArtifact2(processArtifact);
|
|
22536
22846
|
let diagnostics = parseDiagnostics;
|
|
22537
22847
|
if (artifact) {
|
|
22538
|
-
const lintDiagnostics = lintProcess2(
|
|
22848
|
+
const lintDiagnostics = lintProcess2(
|
|
22849
|
+
artifact,
|
|
22850
|
+
inventory,
|
|
22851
|
+
predicateNames ?? [],
|
|
22852
|
+
selectorNames ? { selectorNames } : {}
|
|
22853
|
+
);
|
|
22539
22854
|
const reportable = predicateNames ? lintDiagnostics : lintDiagnostics.filter((d) => d.code !== "UNKNOWN_PREDICATE");
|
|
22540
22855
|
diagnostics = diagnostics.concat(reportable);
|
|
22541
22856
|
}
|