agent-contracts 0.7.1 → 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/README.md CHANGED
@@ -204,15 +204,30 @@ An **Artifact** defines the objects that move through the workflow:
204
204
  * required validations
205
205
  * visibility
206
206
 
207
+ ### Tool
208
+
209
+ A **Tool** defines an invokable CLI/MCP tool:
210
+
211
+ * kind (cli, mcp, etc.)
212
+ * input/output artifacts
213
+ * invokable_by (which agents can use it)
214
+ * `commands` — structured list of sub-commands with `category`, `reads`, `writes`, and `purpose`
215
+
207
216
  ### Workflow
208
217
 
209
218
  A **Workflow** defines a phase-level execution sequence:
210
219
 
211
- * description
212
- * entry conditions
213
- * trigger
220
+ * `description` — human-readable summary
221
+ * `entry_conditions`
222
+ * `trigger`
223
+ * `external_participants` — actors/participants outside the agent system (e.g., User, external advisory)
214
224
  * ordered steps (handoff, validation, decision)
215
225
 
226
+ Workflow steps support additional properties:
227
+
228
+ * `group` — consecutive steps with the same group are rendered as `par` (parallel) blocks in sequence diagrams
229
+ * `retry` (handoff steps only) — defines a conditional retry loop with `condition`, `fix_task`, and optional `revalidate_task`
230
+
216
231
  ### Handoff
217
232
 
218
233
  A **Handoff** is a runtime delegation instance.
@@ -761,7 +776,8 @@ Templates can use these built-in helpers:
761
776
  | `or` | `{{#if (or a b)}}` | Boolean OR (variadic) |
762
777
  | `and` | `{{#if (and a b)}}` | Boolean AND (variadic) |
763
778
  | `gt` / `gte` / `lt` | `{{#if (gt a b)}}` | Numeric comparisons |
764
- | `sequenceDiagram` | `{{{sequenceDiagram}}}` | Generate Mermaid sequence diagram from workflow context (requires `workflow` context) |
779
+ | `sequenceDiagram` | `{{{sequenceDiagram}}}` or `{{{sequenceDiagram @key ../dsl}}}` | Generate Mermaid sequence diagram. Supports `external_participants`, `group` (par blocks), `retry` (opt blocks), and read-only agent separation into Audit box |
780
+ | `overviewFlowchart` | `{{{overviewFlowchart dsl}}}` | Generate Mermaid graph showing phases → agents/tools/artifacts relationships (system context) |
765
781
 
766
782
  ---
767
783
 
@@ -800,6 +816,8 @@ Checks:
800
816
  * merge integrity
801
817
  * read-only write violations
802
818
  * prerequisite readability
819
+ * artifact ownership — `produces_artifact`/`reads_artifact` in execution steps vs. artifact producers/editors/consumers
820
+ * tool commands — `commands[].reads`/`commands[].writes` reference valid artifacts and align with `output_artifacts`
803
821
  * naming/style issues through Spectral rules
804
822
 
805
823
  ---
package/dist/cli.js CHANGED
@@ -59180,13 +59180,21 @@ var TaskSchema = z7.object({
59180
59180
 
59181
59181
  // src/schema/tool.ts
59182
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
+ });
59183
59190
  var ToolSchema = z8.object({
59184
59191
  kind: z8.string(),
59185
59192
  description: z8.string().optional(),
59186
59193
  input_artifacts: z8.array(z8.string()).default([]),
59187
59194
  output_artifacts: z8.array(z8.string()).default([]),
59188
59195
  invokable_by: z8.array(z8.string()),
59189
- side_effects: z8.array(z8.string()).default([])
59196
+ side_effects: z8.array(z8.string()).default([]),
59197
+ commands: z8.array(CommandSchema).default([])
59190
59198
  }).passthrough();
59191
59199
 
59192
59200
  // src/schema/validation.ts
@@ -59202,23 +59210,38 @@ var ValidationSchema = z9.object({
59202
59210
 
59203
59211
  // src/schema/workflow.ts
59204
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
+ });
59205
59224
  var WorkflowHandoffStepSchema = z10.object({
59206
59225
  type: z10.literal("handoff"),
59207
59226
  description: z10.string().optional(),
59208
59227
  handoff_kind: z10.string(),
59209
59228
  task: z10.string().optional(),
59210
- from_agent: z10.string().optional()
59229
+ from_agent: z10.string().optional(),
59230
+ group: z10.string().optional(),
59231
+ retry: RetrySchema.optional()
59211
59232
  }).passthrough();
59212
59233
  var WorkflowValidationStepSchema = z10.object({
59213
59234
  type: z10.literal("validation"),
59214
59235
  description: z10.string().optional(),
59215
- validation: z10.string()
59236
+ validation: z10.string(),
59237
+ group: z10.string().optional()
59216
59238
  }).passthrough();
59217
59239
  var WorkflowDecisionStepSchema = z10.object({
59218
59240
  type: z10.literal("decision"),
59219
59241
  description: z10.string().optional(),
59220
59242
  on: z10.string(),
59221
- branches: z10.record(z10.string(), z10.array(z10.string()))
59243
+ branches: z10.record(z10.string(), z10.array(z10.string())),
59244
+ group: z10.string().optional()
59222
59245
  }).passthrough();
59223
59246
  var WorkflowStepSchema = z10.discriminatedUnion("type", [
59224
59247
  WorkflowHandoffStepSchema,
@@ -59229,7 +59252,8 @@ var WorkflowSchema = z10.object({
59229
59252
  description: z10.string().optional(),
59230
59253
  entry_conditions: z10.array(z10.string()).default([]),
59231
59254
  trigger: z10.string().optional(),
59232
- steps: z10.array(WorkflowStepSchema)
59255
+ steps: z10.array(WorkflowStepSchema),
59256
+ external_participants: z10.array(ExternalParticipantSchema).default([])
59233
59257
  }).passthrough();
59234
59258
 
59235
59259
  // src/schema/dsl.ts
@@ -59846,12 +59870,100 @@ var mergeIntegrityRule = {
59846
59870
  }
59847
59871
  };
59848
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
+
59849
59959
  // src/linter/linter.ts
59850
59960
  var builtinRules = [
59851
59961
  validationCoverageRule,
59852
59962
  toolExecutionRule,
59853
59963
  taskAgentBindingRule,
59854
- mergeIntegrityRule
59964
+ mergeIntegrityRule,
59965
+ artifactOwnershipRule,
59966
+ toolCommandsRule
59855
59967
  ];
59856
59968
  function lint(dsl, rules = builtinRules) {
59857
59969
  const diagnostics = [];
@@ -60813,40 +60925,63 @@ function agentAlias(id, agent) {
60813
60925
  }
60814
60926
  function collectReferencedIds(workflow, dsl, relatedTasks) {
60815
60927
  const agents = /* @__PURE__ */ new Set();
60928
+ const auditAgents = /* @__PURE__ */ new Set();
60816
60929
  const tools = /* @__PURE__ */ new Set();
60817
60930
  const artifacts = /* @__PURE__ */ new Set();
60818
60931
  const taskMap = /* @__PURE__ */ new Map();
60819
60932
  for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
60820
60933
  for (const step of workflow.steps) {
60821
60934
  if (step.type === "handoff") {
60822
- if (step.from_agent) agents.add(step.from_agent);
60935
+ if (step.from_agent) addAgent(step.from_agent);
60823
60936
  if (step.task) {
60824
60937
  const task = taskMap.get(step.task);
60825
60938
  if (task) {
60826
- agents.add(task.target_agent);
60939
+ addAgent(task.target_agent);
60827
60940
  for (const es of task.execution_steps ?? []) {
60828
60941
  collectExecutionStepIds(es, tools, artifacts);
60829
60942
  }
60830
60943
  }
60831
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
+ }
60832
60960
  } else if (step.type === "validation") {
60833
60961
  const val = dsl.validations[step.validation];
60834
60962
  if (val) {
60835
- if (val.executor_type === "agent") agents.add(val.executor);
60963
+ if (val.executor_type === "agent") addAgent(val.executor);
60836
60964
  else tools.add(val.executor);
60837
60965
  artifacts.add(val.target_artifact);
60838
60966
  }
60839
- } else if (step.type === "decision") {
60840
60967
  }
60841
60968
  }
60842
- return { agents, tools, artifacts };
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 };
60843
60978
  }
60844
60979
  function collectExecutionStepIds(es, tools, artifacts) {
60845
60980
  if (es.uses_tool) tools.add(es.uses_tool);
60846
60981
  if (es.produces_artifact) artifacts.add(es.produces_artifact);
60847
60982
  if (es.reads_artifact) artifacts.add(es.reads_artifact);
60848
60983
  }
60849
- function buildParticipants(ids, dsl) {
60984
+ function buildParticipants(ids, externals, dsl) {
60850
60985
  const participants = [];
60851
60986
  const usedAliases = /* @__PURE__ */ new Set();
60852
60987
  function uniqueAlias(preferred) {
@@ -60859,12 +60994,22 @@ function buildParticipants(ids, dsl) {
60859
60994
  usedAliases.add(alias);
60860
60995
  return alias;
60861
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
+ }
60862
61001
  for (const id of ids.agents) {
60863
61002
  const agent = dsl.agents[id];
60864
61003
  if (!agent) continue;
60865
61004
  const alias = uniqueAlias(agentAlias(id, agent));
60866
61005
  participants.push({ id, alias, label: agent.role_name, group: "agents" });
60867
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
+ }
60868
61013
  for (const id of ids.tools) {
60869
61014
  const tool = dsl.tools[id];
60870
61015
  if (!tool) continue;
@@ -60883,15 +61028,33 @@ function participantAlias(participants, id) {
60883
61028
  const p2 = participants.find((pp) => pp.id === id);
60884
61029
  return p2 ? p2.alias : sanitizeAlias(id);
60885
61030
  }
60886
- function emitParticipants(participants, lines, indent) {
61031
+ function emitParticipants(participants, externals, lines, indent) {
60887
61032
  const groups = {
61033
+ external: [],
60888
61034
  agents: [],
61035
+ audit: [],
60889
61036
  toolchain: [],
60890
61037
  artifacts: []
60891
61038
  };
60892
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
+ }
60893
61055
  const groupConfig = [
60894
61056
  { key: "agents", label: "Agents", color: "rgb(200,220,255)" },
61057
+ { key: "audit", label: "Audit", color: "rgb(255,220,220)" },
60895
61058
  { key: "toolchain", label: "Toolchain", color: "rgb(220,255,220)" },
60896
61059
  { key: "artifacts", label: "Artifacts", color: "rgb(255,230,210)" }
60897
61060
  ];
@@ -60967,7 +61130,7 @@ function emitValidationStep(step, participants, dsl, lastFromAgent, lines, inden
60967
61130
  function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
60968
61131
  const branches = Object.entries(step.branches);
60969
61132
  if (branches.length === 0) return;
60970
- const agentAlias2 = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
61133
+ const agentAl = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
60971
61134
  for (let i3 = 0; i3 < branches.length; i3++) {
60972
61135
  const [key, values] = branches[i3];
60973
61136
  if (i3 === 0) {
@@ -60975,21 +61138,78 @@ function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
60975
61138
  } else {
60976
61139
  lines.push(`${indent}else ${key}`);
60977
61140
  }
60978
- if (agentAlias2) {
60979
- lines.push(`${indent} Note over ${agentAlias2}: ${values.join(", ")}`);
60980
- } else {
60981
- lines.push(`${indent} Note right of ${participantAlias(participants, [.../* @__PURE__ */ new Set()].join(""))}: ${values.join(", ")}`);
61141
+ if (agentAl) {
61142
+ lines.push(`${indent} Note over ${agentAl}: ${values.join(", ")}`);
60982
61143
  }
60983
61144
  }
60984
61145
  lines.push(`${indent}end`);
60985
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
+ }
60986
61205
  function generateSequenceDiagram(workflow, relatedTasks, dsl) {
60987
61206
  const ids = collectReferencedIds(workflow, dsl, relatedTasks);
60988
- const participants = buildParticipants(ids, dsl);
61207
+ const externals = workflow.external_participants ?? [];
61208
+ const participants = buildParticipants(ids, externals, dsl);
60989
61209
  const lines = [];
60990
61210
  const indent = " ";
60991
61211
  lines.push("sequenceDiagram");
60992
- emitParticipants(participants, lines, indent);
61212
+ emitParticipants(participants, externals, lines, indent);
60993
61213
  lines.push("");
60994
61214
  lines.push(`${indent}rect ${hashToColor(workflow.id, 0.15, 0.95)}`);
60995
61215
  const firstP = participants[0];
@@ -60998,22 +61218,174 @@ function generateSequenceDiagram(workflow, relatedTasks, dsl) {
60998
61218
  const noteLabel = workflow.description ? `${workflow.id} \u2014 ${workflow.description}` : workflow.id;
60999
61219
  lines.push(`${indent}Note over ${firstP.alias},${lastP.alias}: ${noteLabel}`);
61000
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
+ }
61001
61229
  let lastFromAgent;
61002
- for (const step of workflow.steps) {
61003
- lines.push("");
61004
- if (step.type === "handoff") {
61005
- if (step.from_agent) lastFromAgent = step.from_agent;
61006
- emitHandoffStep(step, participants, dsl, relatedTasks, lines, indent);
61007
- } else if (step.type === "validation") {
61008
- emitValidationStep(step, participants, dsl, lastFromAgent, lines, indent);
61009
- } else if (step.type === "decision") {
61010
- emitDecisionStep(step, participants, lastFromAgent, lines, indent);
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
+ }
61011
61251
  }
61012
61252
  }
61013
61253
  lines.push("");
61014
61254
  lines.push(`${indent}end`);
61015
61255
  return lines.join("\n");
61016
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
+ }
61017
61389
 
61018
61390
  // src/renderer/renderer.ts
61019
61391
  Handlebars.registerHelper("eq", (a3, b3) => a3 === b3);
@@ -61178,14 +61550,39 @@ Handlebars.registerHelper("size", (obj) => {
61178
61550
  });
61179
61551
  Handlebars.registerHelper(
61180
61552
  "sequenceDiagram",
61181
- function() {
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
+ }
61182
61567
  const workflow = this["workflow"];
61183
61568
  const relatedTasks = this["relatedTasks"];
61184
- const dsl = this["dsl"];
61569
+ const dsl = opts?.hash?.["dsl"] ?? this["dsl"];
61185
61570
  if (!workflow || !dsl) return "";
61186
61571
  return generateSequenceDiagram(workflow, relatedTasks ?? [], dsl);
61187
61572
  }
61188
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
+ );
61189
61586
  function getDslSection(dsl, context) {
61190
61587
  const sectionMap = {
61191
61588
  agent: dsl.agents,