agent-contracts 0.7.0 → 0.8.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/cli.js CHANGED
@@ -59155,6 +59155,7 @@ var ExecutionStepSchema = z7.object({
59155
59155
  abort_on_failure: z7.boolean().optional(),
59156
59156
  uses_tool: z7.string().optional(),
59157
59157
  produces_artifact: z7.string().optional(),
59158
+ reads_artifact: z7.string().optional(),
59158
59159
  depends_on: z7.array(z7.string()).optional(),
59159
59160
  skip_condition: z7.string().optional(),
59160
59161
  wait_for_approval: z7.boolean().optional()
@@ -59179,13 +59180,21 @@ var TaskSchema = z7.object({
59179
59180
 
59180
59181
  // src/schema/tool.ts
59181
59182
  import { z as z8 } from "zod";
59183
+ var CommandSchema = z8.object({
59184
+ command: z8.string(),
59185
+ category: z8.string(),
59186
+ reads: z8.array(z8.string()).default([]),
59187
+ writes: z8.array(z8.string()).default([]),
59188
+ purpose: z8.string().optional()
59189
+ });
59182
59190
  var ToolSchema = z8.object({
59183
59191
  kind: z8.string(),
59184
59192
  description: z8.string().optional(),
59185
59193
  input_artifacts: z8.array(z8.string()).default([]),
59186
59194
  output_artifacts: z8.array(z8.string()).default([]),
59187
59195
  invokable_by: z8.array(z8.string()),
59188
- side_effects: z8.array(z8.string()).default([])
59196
+ side_effects: z8.array(z8.string()).default([]),
59197
+ commands: z8.array(CommandSchema).default([])
59189
59198
  }).passthrough();
59190
59199
 
59191
59200
  // src/schema/validation.ts
@@ -59201,23 +59210,38 @@ var ValidationSchema = z9.object({
59201
59210
 
59202
59211
  // src/schema/workflow.ts
59203
59212
  import { z as z10 } from "zod";
59213
+ var RetrySchema = z10.object({
59214
+ condition: z10.string(),
59215
+ fix_task: z10.string(),
59216
+ revalidate_task: z10.string().optional()
59217
+ });
59218
+ var ExternalParticipantSchema = z10.object({
59219
+ id: z10.string(),
59220
+ kind: z10.enum(["actor", "participant"]),
59221
+ label: z10.string(),
59222
+ description: z10.string().optional()
59223
+ });
59204
59224
  var WorkflowHandoffStepSchema = z10.object({
59205
59225
  type: z10.literal("handoff"),
59206
59226
  description: z10.string().optional(),
59207
59227
  handoff_kind: z10.string(),
59208
59228
  task: z10.string().optional(),
59209
- from_agent: z10.string().optional()
59229
+ from_agent: z10.string().optional(),
59230
+ group: z10.string().optional(),
59231
+ retry: RetrySchema.optional()
59210
59232
  }).passthrough();
59211
59233
  var WorkflowValidationStepSchema = z10.object({
59212
59234
  type: z10.literal("validation"),
59213
59235
  description: z10.string().optional(),
59214
- validation: z10.string()
59236
+ validation: z10.string(),
59237
+ group: z10.string().optional()
59215
59238
  }).passthrough();
59216
59239
  var WorkflowDecisionStepSchema = z10.object({
59217
59240
  type: z10.literal("decision"),
59218
59241
  description: z10.string().optional(),
59219
59242
  on: z10.string(),
59220
- branches: z10.record(z10.string(), z10.array(z10.string()))
59243
+ branches: z10.record(z10.string(), z10.array(z10.string())),
59244
+ group: z10.string().optional()
59221
59245
  }).passthrough();
59222
59246
  var WorkflowStepSchema = z10.discriminatedUnion("type", [
59223
59247
  WorkflowHandoffStepSchema,
@@ -59225,9 +59249,11 @@ var WorkflowStepSchema = z10.discriminatedUnion("type", [
59225
59249
  WorkflowDecisionStepSchema
59226
59250
  ]);
59227
59251
  var WorkflowSchema = z10.object({
59252
+ description: z10.string().optional(),
59228
59253
  entry_conditions: z10.array(z10.string()).default([]),
59229
59254
  trigger: z10.string().optional(),
59230
- steps: z10.array(WorkflowStepSchema)
59255
+ steps: z10.array(WorkflowStepSchema),
59256
+ external_participants: z10.array(ExternalParticipantSchema).default([])
59231
59257
  }).passthrough();
59232
59258
 
59233
59259
  // src/schema/dsl.ts
@@ -59805,6 +59831,16 @@ var taskAgentBindingRule = {
59805
59831
  });
59806
59832
  }
59807
59833
  }
59834
+ if (step.reads_artifact) {
59835
+ if (!targetAgent.can_read_artifacts.includes(step.reads_artifact)) {
59836
+ diagnostics.push({
59837
+ ruleId: "task-agent-binding",
59838
+ severity: "error",
59839
+ path: `tasks.${taskId}.execution_steps`,
59840
+ message: `Task "${taskId}" step reads_artifact "${step.reads_artifact}" not in target agent "${task.target_agent}" can_read_artifacts`
59841
+ });
59842
+ }
59843
+ }
59808
59844
  }
59809
59845
  }
59810
59846
  return diagnostics;
@@ -59834,12 +59870,100 @@ var mergeIntegrityRule = {
59834
59870
  }
59835
59871
  };
59836
59872
 
59873
+ // src/linter/rules/artifact-ownership.ts
59874
+ var artifactOwnershipRule = {
59875
+ id: "artifact-ownership",
59876
+ description: "Ensure execution_step produces/reads operations are consistent with artifact producers/editors/consumers",
59877
+ run(dsl) {
59878
+ const diagnostics = [];
59879
+ for (const [taskId, task] of Object.entries(dsl.tasks)) {
59880
+ if (!task.execution_steps) continue;
59881
+ const agentId = task.target_agent;
59882
+ for (const step of task.execution_steps) {
59883
+ if (step.produces_artifact) {
59884
+ const artifact = dsl.artifacts[step.produces_artifact];
59885
+ if (artifact) {
59886
+ const canWrite = artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
59887
+ if (!canWrite) {
59888
+ diagnostics.push({
59889
+ ruleId: "artifact-ownership",
59890
+ severity: "warning",
59891
+ path: `tasks.${taskId}.execution_steps`,
59892
+ message: `Agent "${agentId}" produces artifact "${step.produces_artifact}" but is not listed in its producers or editors`
59893
+ });
59894
+ }
59895
+ }
59896
+ }
59897
+ if (step.reads_artifact) {
59898
+ const artifact = dsl.artifacts[step.reads_artifact];
59899
+ if (artifact) {
59900
+ const canRead = artifact.consumers.includes(agentId) || artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
59901
+ if (!canRead) {
59902
+ diagnostics.push({
59903
+ ruleId: "artifact-ownership",
59904
+ severity: "warning",
59905
+ path: `tasks.${taskId}.execution_steps`,
59906
+ message: `Agent "${agentId}" reads artifact "${step.reads_artifact}" but is not listed in its producers, editors, or consumers`
59907
+ });
59908
+ }
59909
+ }
59910
+ }
59911
+ }
59912
+ }
59913
+ return diagnostics;
59914
+ }
59915
+ };
59916
+
59917
+ // src/linter/rules/tool-commands.ts
59918
+ var toolCommandsRule = {
59919
+ id: "tool-commands",
59920
+ description: "Validate tool commands: reads/writes reference existing artifacts; writes align with output_artifacts",
59921
+ run(dsl) {
59922
+ const diagnostics = [];
59923
+ for (const [toolId, tool] of Object.entries(dsl.tools)) {
59924
+ for (const cmd of tool.commands) {
59925
+ for (const ref of cmd.reads) {
59926
+ if (!dsl.artifacts[ref]) {
59927
+ diagnostics.push({
59928
+ ruleId: "tool-commands",
59929
+ severity: "error",
59930
+ path: `tools.${toolId}.commands`,
59931
+ message: `Command "${cmd.command}" reads artifact "${ref}" which does not exist`
59932
+ });
59933
+ }
59934
+ }
59935
+ for (const ref of cmd.writes) {
59936
+ if (!dsl.artifacts[ref]) {
59937
+ diagnostics.push({
59938
+ ruleId: "tool-commands",
59939
+ severity: "error",
59940
+ path: `tools.${toolId}.commands`,
59941
+ message: `Command "${cmd.command}" writes artifact "${ref}" which does not exist`
59942
+ });
59943
+ }
59944
+ if (dsl.artifacts[ref] && !tool.output_artifacts.includes(ref)) {
59945
+ diagnostics.push({
59946
+ ruleId: "tool-commands",
59947
+ severity: "warning",
59948
+ path: `tools.${toolId}.commands`,
59949
+ message: `Command "${cmd.command}" writes artifact "${ref}" but tool's output_artifacts does not include it`
59950
+ });
59951
+ }
59952
+ }
59953
+ }
59954
+ }
59955
+ return diagnostics;
59956
+ }
59957
+ };
59958
+
59837
59959
  // src/linter/linter.ts
59838
59960
  var builtinRules = [
59839
59961
  validationCoverageRule,
59840
59962
  toolExecutionRule,
59841
59963
  taskAgentBindingRule,
59842
- mergeIntegrityRule
59964
+ mergeIntegrityRule,
59965
+ artifactOwnershipRule,
59966
+ toolCommandsRule
59843
59967
  ];
59844
59968
  function lint(dsl, rules = builtinRules) {
59845
59969
  const diagnostics = [];
@@ -60602,6 +60726,11 @@ function buildWorkflowContext(dsl, workflowId) {
60602
60726
  }
60603
60727
  }
60604
60728
  }
60729
+ for (const task of relatedTasks) {
60730
+ for (const step of task.execution_steps ?? []) {
60731
+ if (step.uses_tool) toolIds.add(step.uses_tool);
60732
+ }
60733
+ }
60605
60734
  const relatedTools = {};
60606
60735
  for (const id of toolIds) {
60607
60736
  if (dsl.tools[id]) relatedTools[id] = dsl.tools[id];
@@ -60609,6 +60738,10 @@ function buildWorkflowContext(dsl, workflowId) {
60609
60738
  const artifactIds = /* @__PURE__ */ new Set();
60610
60739
  for (const task of relatedTasks) {
60611
60740
  for (const artId of task.input_artifacts) artifactIds.add(artId);
60741
+ for (const step of task.execution_steps ?? []) {
60742
+ if (step.produces_artifact) artifactIds.add(step.produces_artifact);
60743
+ if (step.reads_artifact) artifactIds.add(step.reads_artifact);
60744
+ }
60612
60745
  }
60613
60746
  for (const id of agentIds) {
60614
60747
  const agent = dsl.agents[id];
@@ -60752,6 +60885,508 @@ function buildPerAgentContext(dsl, agent) {
60752
60885
  };
60753
60886
  }
60754
60887
 
60888
+ // src/renderer/sequence-diagram.ts
60889
+ function hashToColor(s2, saturation, lightness) {
60890
+ let hash = 0;
60891
+ for (const ch of s2) hash = (hash << 5) - hash + ch.charCodeAt(0) | 0;
60892
+ const h2 = (hash % 360 + 360) % 360;
60893
+ const c2 = (1 - Math.abs(2 * lightness - 1)) * saturation;
60894
+ const x3 = c2 * (1 - Math.abs(h2 / 60 % 2 - 1));
60895
+ const m2 = lightness - c2 / 2;
60896
+ let r3 = 0, g2 = 0, b3 = 0;
60897
+ if (h2 < 60) {
60898
+ r3 = c2;
60899
+ g2 = x3;
60900
+ } else if (h2 < 120) {
60901
+ r3 = x3;
60902
+ g2 = c2;
60903
+ } else if (h2 < 180) {
60904
+ g2 = c2;
60905
+ b3 = x3;
60906
+ } else if (h2 < 240) {
60907
+ g2 = x3;
60908
+ b3 = c2;
60909
+ } else if (h2 < 300) {
60910
+ r3 = x3;
60911
+ b3 = c2;
60912
+ } else {
60913
+ r3 = c2;
60914
+ b3 = x3;
60915
+ }
60916
+ return `rgb(${Math.round((r3 + m2) * 255)},${Math.round((g2 + m2) * 255)},${Math.round((b3 + m2) * 255)})`;
60917
+ }
60918
+ function sanitizeAlias(id) {
60919
+ return id.replace(/[^a-zA-Z0-9_]/g, "_");
60920
+ }
60921
+ function agentAlias(id, agent) {
60922
+ const words = agent.role_name.split(/\s+/);
60923
+ if (words.length === 1) return sanitizeAlias(words[0].slice(0, 4));
60924
+ return sanitizeAlias(words.map((w2) => w2[0]).join(""));
60925
+ }
60926
+ function collectReferencedIds(workflow, dsl, relatedTasks) {
60927
+ const agents = /* @__PURE__ */ new Set();
60928
+ const auditAgents = /* @__PURE__ */ new Set();
60929
+ const tools = /* @__PURE__ */ new Set();
60930
+ const artifacts = /* @__PURE__ */ new Set();
60931
+ const taskMap = /* @__PURE__ */ new Map();
60932
+ for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
60933
+ for (const step of workflow.steps) {
60934
+ if (step.type === "handoff") {
60935
+ if (step.from_agent) addAgent(step.from_agent);
60936
+ if (step.task) {
60937
+ const task = taskMap.get(step.task);
60938
+ if (task) {
60939
+ addAgent(task.target_agent);
60940
+ for (const es of task.execution_steps ?? []) {
60941
+ collectExecutionStepIds(es, tools, artifacts);
60942
+ }
60943
+ }
60944
+ }
60945
+ if (step.retry) {
60946
+ const fixTask = taskMap.get(step.retry.fix_task);
60947
+ if (fixTask) {
60948
+ addAgent(fixTask.target_agent);
60949
+ for (const es of fixTask.execution_steps ?? []) {
60950
+ collectExecutionStepIds(es, tools, artifacts);
60951
+ }
60952
+ }
60953
+ if (step.retry.revalidate_task) {
60954
+ const revalTask = taskMap.get(step.retry.revalidate_task);
60955
+ if (revalTask) {
60956
+ addAgent(revalTask.target_agent);
60957
+ }
60958
+ }
60959
+ }
60960
+ } else if (step.type === "validation") {
60961
+ const val = dsl.validations[step.validation];
60962
+ if (val) {
60963
+ if (val.executor_type === "agent") addAgent(val.executor);
60964
+ else tools.add(val.executor);
60965
+ artifacts.add(val.target_artifact);
60966
+ }
60967
+ }
60968
+ }
60969
+ function addAgent(agentId) {
60970
+ const agent = dsl.agents[agentId];
60971
+ if (agent?.mode === "read-only") {
60972
+ auditAgents.add(agentId);
60973
+ } else {
60974
+ agents.add(agentId);
60975
+ }
60976
+ }
60977
+ return { agents, auditAgents, tools, artifacts };
60978
+ }
60979
+ function collectExecutionStepIds(es, tools, artifacts) {
60980
+ if (es.uses_tool) tools.add(es.uses_tool);
60981
+ if (es.produces_artifact) artifacts.add(es.produces_artifact);
60982
+ if (es.reads_artifact) artifacts.add(es.reads_artifact);
60983
+ }
60984
+ function buildParticipants(ids, externals, dsl) {
60985
+ const participants = [];
60986
+ const usedAliases = /* @__PURE__ */ new Set();
60987
+ function uniqueAlias(preferred) {
60988
+ let alias = preferred;
60989
+ let i3 = 2;
60990
+ while (usedAliases.has(alias)) {
60991
+ alias = `${preferred}${i3}`;
60992
+ i3++;
60993
+ }
60994
+ usedAliases.add(alias);
60995
+ return alias;
60996
+ }
60997
+ for (const ep of externals) {
60998
+ const alias = uniqueAlias(sanitizeAlias(ep.id));
60999
+ participants.push({ id: ep.id, alias, label: ep.label, group: "external" });
61000
+ }
61001
+ for (const id of ids.agents) {
61002
+ const agent = dsl.agents[id];
61003
+ if (!agent) continue;
61004
+ const alias = uniqueAlias(agentAlias(id, agent));
61005
+ participants.push({ id, alias, label: agent.role_name, group: "agents" });
61006
+ }
61007
+ for (const id of ids.auditAgents) {
61008
+ const agent = dsl.agents[id];
61009
+ if (!agent) continue;
61010
+ const alias = uniqueAlias(agentAlias(id, agent));
61011
+ participants.push({ id, alias, label: agent.role_name, group: "audit" });
61012
+ }
61013
+ for (const id of ids.tools) {
61014
+ const tool = dsl.tools[id];
61015
+ if (!tool) continue;
61016
+ const alias = uniqueAlias(sanitizeAlias(id));
61017
+ participants.push({ id, alias, label: id, group: "toolchain" });
61018
+ }
61019
+ for (const id of ids.artifacts) {
61020
+ const art = dsl.artifacts[id];
61021
+ if (!art) continue;
61022
+ const alias = uniqueAlias(sanitizeAlias(id));
61023
+ participants.push({ id, alias, label: id, group: "artifacts" });
61024
+ }
61025
+ return participants;
61026
+ }
61027
+ function participantAlias(participants, id) {
61028
+ const p2 = participants.find((pp) => pp.id === id);
61029
+ return p2 ? p2.alias : sanitizeAlias(id);
61030
+ }
61031
+ function emitParticipants(participants, externals, lines, indent) {
61032
+ const groups = {
61033
+ external: [],
61034
+ agents: [],
61035
+ audit: [],
61036
+ toolchain: [],
61037
+ artifacts: []
61038
+ };
61039
+ for (const p2 of participants) groups[p2.group].push(p2);
61040
+ const externalMap = /* @__PURE__ */ new Map();
61041
+ for (const ep of externals) externalMap.set(ep.id, ep);
61042
+ if (groups.external.length > 0) {
61043
+ lines.push(`${indent}box rgb(255,245,230) External`);
61044
+ for (const p2 of groups.external) {
61045
+ const ep = externalMap.get(p2.id);
61046
+ const keyword = ep?.kind === "actor" ? "actor" : "participant";
61047
+ if (p2.alias === p2.label) {
61048
+ lines.push(`${indent}${keyword} ${p2.alias}`);
61049
+ } else {
61050
+ lines.push(`${indent}${keyword} ${p2.alias} as ${p2.label}`);
61051
+ }
61052
+ }
61053
+ lines.push(`${indent}end`);
61054
+ }
61055
+ const groupConfig = [
61056
+ { key: "agents", label: "Agents", color: "rgb(200,220,255)" },
61057
+ { key: "audit", label: "Audit", color: "rgb(255,220,220)" },
61058
+ { key: "toolchain", label: "Toolchain", color: "rgb(220,255,220)" },
61059
+ { key: "artifacts", label: "Artifacts", color: "rgb(255,230,210)" }
61060
+ ];
61061
+ for (const { key, label, color } of groupConfig) {
61062
+ const members = groups[key];
61063
+ if (members.length === 0) continue;
61064
+ lines.push(`${indent}box ${color} ${label}`);
61065
+ for (const p2 of members) {
61066
+ if (p2.alias === p2.label) {
61067
+ lines.push(`${indent}participant ${p2.alias}`);
61068
+ } else {
61069
+ lines.push(`${indent}participant ${p2.alias} as ${p2.label}`);
61070
+ }
61071
+ }
61072
+ lines.push(`${indent}end`);
61073
+ }
61074
+ }
61075
+ function emitHandoffStep(step, participants, dsl, relatedTasks, lines, indent) {
61076
+ const taskMap = /* @__PURE__ */ new Map();
61077
+ for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
61078
+ if (!step.task) {
61079
+ if (step.from_agent) {
61080
+ const fromAlias2 = participantAlias(participants, step.from_agent);
61081
+ lines.push(`${indent}${fromAlias2}->>${fromAlias2}: ${step.handoff_kind}`);
61082
+ }
61083
+ return;
61084
+ }
61085
+ const task = taskMap.get(step.task);
61086
+ if (!task) return;
61087
+ const fromAlias = step.from_agent ? participantAlias(participants, step.from_agent) : null;
61088
+ const targetAlias = participantAlias(participants, task.target_agent);
61089
+ if (fromAlias) {
61090
+ lines.push(`${indent}${fromAlias}->>${targetAlias}: delegate ${step.task}`);
61091
+ }
61092
+ for (const es of task.execution_steps ?? []) {
61093
+ emitExecutionStep(es, targetAlias, participants, lines, indent);
61094
+ }
61095
+ if (fromAlias) {
61096
+ lines.push(`${indent}${targetAlias}-->>${fromAlias}: ${task.result_handoff}`);
61097
+ }
61098
+ }
61099
+ function emitExecutionStep(es, agentAlias2, participants, lines, indent) {
61100
+ if (es.reads_artifact) {
61101
+ const artAlias = participantAlias(participants, es.reads_artifact);
61102
+ lines.push(`${indent}${agentAlias2}->>${artAlias}: [R] ${es.action}`);
61103
+ }
61104
+ if (es.produces_artifact) {
61105
+ const artAlias = participantAlias(participants, es.produces_artifact);
61106
+ lines.push(`${indent}${agentAlias2}->>${artAlias}: [W] ${es.action}`);
61107
+ }
61108
+ if (es.uses_tool) {
61109
+ const toolAlias = participantAlias(participants, es.uses_tool);
61110
+ lines.push(`${indent}${agentAlias2}->>${toolAlias}: ${es.action}`);
61111
+ }
61112
+ if (!es.reads_artifact && !es.produces_artifact && !es.uses_tool) {
61113
+ lines.push(`${indent}${agentAlias2}->>${agentAlias2}: ${es.action}`);
61114
+ }
61115
+ }
61116
+ function emitValidationStep(step, participants, dsl, lastFromAgent, lines, indent) {
61117
+ const val = dsl.validations[step.validation];
61118
+ if (!val) return;
61119
+ const executorAlias = participantAlias(participants, val.executor);
61120
+ const artifactAlias = participantAlias(participants, val.target_artifact);
61121
+ const fromAlias = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
61122
+ if (fromAlias && fromAlias !== executorAlias) {
61123
+ lines.push(`${indent}${fromAlias}->>${executorAlias}: ${step.validation}`);
61124
+ }
61125
+ lines.push(`${indent}${executorAlias}->>${artifactAlias}: [R] ${val.target_artifact}`);
61126
+ if (fromAlias && fromAlias !== executorAlias) {
61127
+ lines.push(`${indent}${executorAlias}-->>${fromAlias}: results`);
61128
+ }
61129
+ }
61130
+ function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
61131
+ const branches = Object.entries(step.branches);
61132
+ if (branches.length === 0) return;
61133
+ const agentAl = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
61134
+ for (let i3 = 0; i3 < branches.length; i3++) {
61135
+ const [key, values] = branches[i3];
61136
+ if (i3 === 0) {
61137
+ lines.push(`${indent}alt ${key}`);
61138
+ } else {
61139
+ lines.push(`${indent}else ${key}`);
61140
+ }
61141
+ if (agentAl) {
61142
+ lines.push(`${indent} Note over ${agentAl}: ${values.join(", ")}`);
61143
+ }
61144
+ }
61145
+ lines.push(`${indent}end`);
61146
+ }
61147
+ function emitRetryBlock(step, participants, dsl, relatedTasks, lines, indent) {
61148
+ const retry = step.retry;
61149
+ if (!retry) return;
61150
+ const taskMap = /* @__PURE__ */ new Map();
61151
+ for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
61152
+ lines.push(`${indent}opt ${retry.condition}`);
61153
+ const innerIndent = indent + " ";
61154
+ const fixTask = taskMap.get(retry.fix_task);
61155
+ if (fixTask) {
61156
+ const fromAlias = step.from_agent ? participantAlias(participants, step.from_agent) : null;
61157
+ const targetAlias = participantAlias(participants, fixTask.target_agent);
61158
+ if (fromAlias) {
61159
+ lines.push(`${innerIndent}${fromAlias}->>${targetAlias}: fix ${retry.fix_task}`);
61160
+ }
61161
+ for (const es of fixTask.execution_steps ?? []) {
61162
+ emitExecutionStep(es, targetAlias, participants, lines, innerIndent);
61163
+ }
61164
+ if (fromAlias) {
61165
+ lines.push(`${innerIndent}${targetAlias}-->>${fromAlias}: ${fixTask.result_handoff}`);
61166
+ }
61167
+ }
61168
+ if (retry.revalidate_task) {
61169
+ const revalTask = taskMap.get(retry.revalidate_task);
61170
+ if (revalTask) {
61171
+ const fromAlias = step.from_agent ? participantAlias(participants, step.from_agent) : null;
61172
+ const revalAlias = participantAlias(participants, revalTask.target_agent);
61173
+ if (fromAlias) {
61174
+ lines.push(`${innerIndent}${fromAlias}->>${revalAlias}: revalidate ${retry.revalidate_task}`);
61175
+ lines.push(`${innerIndent}${revalAlias}-->>${fromAlias}: ${revalTask.result_handoff}`);
61176
+ }
61177
+ }
61178
+ }
61179
+ lines.push(`${indent}end`);
61180
+ }
61181
+ function groupSteps(steps) {
61182
+ const result = [];
61183
+ let currentGroup = null;
61184
+ for (let i3 = 0; i3 < steps.length; i3++) {
61185
+ const step = steps[i3];
61186
+ const group = "group" in step ? step.group : void 0;
61187
+ if (group) {
61188
+ if (currentGroup && currentGroup.group === group) {
61189
+ currentGroup.steps.push({ step, index: i3 });
61190
+ } else {
61191
+ if (currentGroup) result.push(currentGroup);
61192
+ currentGroup = { group, steps: [{ step, index: i3 }] };
61193
+ }
61194
+ } else {
61195
+ if (currentGroup) {
61196
+ result.push(currentGroup);
61197
+ currentGroup = null;
61198
+ }
61199
+ result.push({ group: null, steps: [{ step, index: i3 }] });
61200
+ }
61201
+ }
61202
+ if (currentGroup) result.push(currentGroup);
61203
+ return result;
61204
+ }
61205
+ function generateSequenceDiagram(workflow, relatedTasks, dsl) {
61206
+ const ids = collectReferencedIds(workflow, dsl, relatedTasks);
61207
+ const externals = workflow.external_participants ?? [];
61208
+ const participants = buildParticipants(ids, externals, dsl);
61209
+ const lines = [];
61210
+ const indent = " ";
61211
+ lines.push("sequenceDiagram");
61212
+ emitParticipants(participants, externals, lines, indent);
61213
+ lines.push("");
61214
+ lines.push(`${indent}rect ${hashToColor(workflow.id, 0.15, 0.95)}`);
61215
+ const firstP = participants[0];
61216
+ const lastP = participants[participants.length - 1];
61217
+ if (firstP && lastP) {
61218
+ const noteLabel = workflow.description ? `${workflow.id} \u2014 ${workflow.description}` : workflow.id;
61219
+ lines.push(`${indent}Note over ${firstP.alias},${lastP.alias}: ${noteLabel}`);
61220
+ }
61221
+ if (workflow.trigger && externals.some((ep) => ep.kind === "actor")) {
61222
+ const actor = externals.find((ep) => ep.kind === "actor");
61223
+ const actorAlias = participantAlias(participants, actor.id);
61224
+ const firstAgent = participants.find((p2) => p2.group === "agents" || p2.group === "audit");
61225
+ if (firstAgent) {
61226
+ lines.push(`${indent}${actorAlias}->>${firstAgent.alias}: ${workflow.trigger}`);
61227
+ }
61228
+ }
61229
+ let lastFromAgent;
61230
+ const grouped = groupSteps(workflow.steps);
61231
+ for (const g2 of grouped) {
61232
+ if (g2.group && g2.steps.length > 1) {
61233
+ lines.push("");
61234
+ lines.push(`${indent}par ${g2.group}`);
61235
+ const parIndent = indent + " ";
61236
+ for (let i3 = 0; i3 < g2.steps.length; i3++) {
61237
+ const { step } = g2.steps[i3];
61238
+ if (i3 > 0) lines.push(`${indent}and`);
61239
+ emitStep(step, participants, dsl, relatedTasks, lines, parIndent, lastFromAgent, (a3) => {
61240
+ lastFromAgent = a3;
61241
+ });
61242
+ }
61243
+ lines.push(`${indent}end`);
61244
+ } else {
61245
+ for (const { step } of g2.steps) {
61246
+ lines.push("");
61247
+ emitStep(step, participants, dsl, relatedTasks, lines, indent, lastFromAgent, (a3) => {
61248
+ lastFromAgent = a3;
61249
+ });
61250
+ }
61251
+ }
61252
+ }
61253
+ lines.push("");
61254
+ lines.push(`${indent}end`);
61255
+ return lines.join("\n");
61256
+ }
61257
+ function emitStep(step, participants, dsl, relatedTasks, lines, indent, lastFromAgent, setLastFromAgent) {
61258
+ if (step.type === "handoff") {
61259
+ if (step.from_agent) setLastFromAgent(step.from_agent);
61260
+ emitHandoffStep(step, participants, dsl, relatedTasks, lines, indent);
61261
+ if (step.retry) {
61262
+ emitRetryBlock(step, participants, dsl, relatedTasks, lines, indent);
61263
+ }
61264
+ } else if (step.type === "validation") {
61265
+ emitValidationStep(step, participants, dsl, lastFromAgent, lines, indent);
61266
+ } else if (step.type === "decision") {
61267
+ emitDecisionStep(step, participants, lastFromAgent, lines, indent);
61268
+ }
61269
+ }
61270
+
61271
+ // src/renderer/overview-flowchart.ts
61272
+ function collectPhaseOps(dsl, wfId) {
61273
+ const ctx = buildWorkflowContext(dsl, wfId);
61274
+ const wf = dsl.workflow[wfId];
61275
+ const agentOps = /* @__PURE__ */ new Map();
61276
+ const artifactOps = /* @__PURE__ */ new Map();
61277
+ const toolOps = /* @__PURE__ */ new Map();
61278
+ function addOp(map, id, op) {
61279
+ if (!map.has(id)) map.set(id, /* @__PURE__ */ new Set());
61280
+ map.get(id).add(op);
61281
+ }
61282
+ const taskMap = new Map(ctx.relatedTasks.map((t3) => [t3.id, t3]));
61283
+ for (const step of wf.steps) {
61284
+ if (step.type === "handoff") {
61285
+ if (step.from_agent) addOp(agentOps, step.from_agent, "delegate");
61286
+ if (step.task) {
61287
+ const task = taskMap.get(step.task);
61288
+ if (task) {
61289
+ addOp(agentOps, task.target_agent, "execute");
61290
+ for (const es of task.execution_steps ?? []) {
61291
+ if (es.reads_artifact) addOp(artifactOps, es.reads_artifact, "R");
61292
+ if (es.produces_artifact) addOp(artifactOps, es.produces_artifact, "W");
61293
+ if (es.uses_tool) {
61294
+ const tool = dsl.tools[es.uses_tool];
61295
+ if (tool) {
61296
+ const cats = tool.commands.map((c2) => c2.category).filter((v2, i3, a3) => a3.indexOf(v2) === i3);
61297
+ for (const cat of cats) addOp(toolOps, es.uses_tool, cat);
61298
+ if (cats.length === 0) addOp(toolOps, es.uses_tool, "\u2713");
61299
+ } else {
61300
+ addOp(toolOps, es.uses_tool, "\u2713");
61301
+ }
61302
+ }
61303
+ }
61304
+ }
61305
+ }
61306
+ } else if (step.type === "validation") {
61307
+ const val = dsl.validations[step.validation];
61308
+ if (val) {
61309
+ if (val.executor_type === "agent") {
61310
+ addOp(agentOps, val.executor, "validate");
61311
+ } else {
61312
+ addOp(toolOps, val.executor, "verification");
61313
+ }
61314
+ addOp(artifactOps, val.target_artifact, "V");
61315
+ }
61316
+ }
61317
+ }
61318
+ return { agentOps, artifactOps, toolOps };
61319
+ }
61320
+ function formatOps(ops) {
61321
+ if (!ops || ops.size === 0) return "\u2014";
61322
+ return [...ops].join(", ");
61323
+ }
61324
+ function buildTable(header, rows) {
61325
+ const lines = [];
61326
+ lines.push("| " + header.join(" | ") + " |");
61327
+ lines.push("|" + header.map(() => "---").join("|") + "|");
61328
+ for (const row of rows) {
61329
+ lines.push("| " + row.join(" | ") + " |");
61330
+ }
61331
+ return lines.join("\n");
61332
+ }
61333
+ function generateOverviewFlowchart(dsl) {
61334
+ const workflowOrder = dsl.system.default_workflow_order ?? Object.keys(dsl.workflow);
61335
+ const phases = workflowOrder.filter((id) => dsl.workflow[id]);
61336
+ const phaseData = /* @__PURE__ */ new Map();
61337
+ for (const wfId of phases) {
61338
+ phaseData.set(wfId, collectPhaseOps(dsl, wfId));
61339
+ }
61340
+ const allAgentIds = /* @__PURE__ */ new Set();
61341
+ const allArtifactIds = /* @__PURE__ */ new Set();
61342
+ const allToolIds = /* @__PURE__ */ new Set();
61343
+ for (const ops of phaseData.values()) {
61344
+ for (const id of ops.agentOps.keys()) allAgentIds.add(id);
61345
+ for (const id of ops.artifactOps.keys()) allArtifactIds.add(id);
61346
+ for (const id of ops.toolOps.keys()) allToolIds.add(id);
61347
+ }
61348
+ const sections = [];
61349
+ if (allAgentIds.size > 0) {
61350
+ const header = ["Agent", ...phases];
61351
+ const rows = [];
61352
+ for (const agentId of allAgentIds) {
61353
+ const agent = dsl.agents[agentId];
61354
+ const label = agent ? agent.role_name : agentId;
61355
+ const row = [label];
61356
+ for (const wfId of phases) {
61357
+ row.push(formatOps(phaseData.get(wfId).agentOps.get(agentId)));
61358
+ }
61359
+ rows.push(row);
61360
+ }
61361
+ sections.push("#### Agent \xD7 Phase\n\n" + buildTable(header, rows));
61362
+ }
61363
+ if (allArtifactIds.size > 0) {
61364
+ const header = ["Artifact", ...phases];
61365
+ const rows = [];
61366
+ for (const artId of allArtifactIds) {
61367
+ const row = [artId];
61368
+ for (const wfId of phases) {
61369
+ row.push(formatOps(phaseData.get(wfId).artifactOps.get(artId)));
61370
+ }
61371
+ rows.push(row);
61372
+ }
61373
+ sections.push("#### Artifact \xD7 Phase\n\n" + buildTable(header, rows));
61374
+ }
61375
+ if (allToolIds.size > 0) {
61376
+ const header = ["Tool", ...phases];
61377
+ const rows = [];
61378
+ for (const toolId of allToolIds) {
61379
+ const row = [toolId];
61380
+ for (const wfId of phases) {
61381
+ row.push(formatOps(phaseData.get(wfId).toolOps.get(toolId)));
61382
+ }
61383
+ rows.push(row);
61384
+ }
61385
+ sections.push("#### Tool \xD7 Phase\n\n" + buildTable(header, rows));
61386
+ }
61387
+ return sections.join("\n\n");
61388
+ }
61389
+
60755
61390
  // src/renderer/renderer.ts
60756
61391
  Handlebars.registerHelper("eq", (a3, b3) => a3 === b3);
60757
61392
  Handlebars.registerHelper("notEmpty", (obj) => {
@@ -60913,6 +61548,41 @@ Handlebars.registerHelper("size", (obj) => {
60913
61548
  if (obj && typeof obj === "object") return Object.keys(obj).length;
60914
61549
  return 0;
60915
61550
  });
61551
+ Handlebars.registerHelper(
61552
+ "sequenceDiagram",
61553
+ function(...args) {
61554
+ const opts = args[args.length - 1];
61555
+ const positionalArgs = args.slice(0, -1);
61556
+ if (typeof positionalArgs[0] === "string" && positionalArgs[1]) {
61557
+ const workflowId = positionalArgs[0];
61558
+ const dsl2 = positionalArgs[1];
61559
+ if (!dsl2.workflow[workflowId]) return "";
61560
+ const ctx = buildWorkflowContext(dsl2, workflowId);
61561
+ return generateSequenceDiagram(
61562
+ ctx.workflow,
61563
+ ctx.relatedTasks,
61564
+ dsl2
61565
+ );
61566
+ }
61567
+ const workflow = this["workflow"];
61568
+ const relatedTasks = this["relatedTasks"];
61569
+ const dsl = opts?.hash?.["dsl"] ?? this["dsl"];
61570
+ if (!workflow || !dsl) return "";
61571
+ return generateSequenceDiagram(workflow, relatedTasks ?? [], dsl);
61572
+ }
61573
+ );
61574
+ Handlebars.registerHelper(
61575
+ "overviewFlowchart",
61576
+ function(...args) {
61577
+ const positionalArgs = args.slice(0, -1);
61578
+ if (positionalArgs[0] && typeof positionalArgs[0] === "object") {
61579
+ return generateOverviewFlowchart(positionalArgs[0]);
61580
+ }
61581
+ const dsl = this["dsl"];
61582
+ if (!dsl) return "";
61583
+ return generateOverviewFlowchart(dsl);
61584
+ }
61585
+ );
60916
61586
  function getDslSection(dsl, context) {
60917
61587
  const sectionMap = {
60918
61588
  agent: dsl.agents,