agent-contracts 0.7.1 → 0.9.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
@@ -59175,18 +59175,27 @@ var TaskSchema = z7.object({
59175
59175
  completion_criteria: z7.array(z7.string()).optional(),
59176
59176
  rules: z7.array(RuleSchema).optional(),
59177
59177
  anti_patterns: z7.array(z7.string()).optional(),
59178
- escalation_criteria: z7.array(EscalationCriterionSchema).optional()
59178
+ escalation_criteria: z7.array(EscalationCriterionSchema).optional(),
59179
+ validations: z7.array(z7.string()).default([])
59179
59180
  }).passthrough();
59180
59181
 
59181
59182
  // src/schema/tool.ts
59182
59183
  import { z as z8 } from "zod";
59184
+ var CommandSchema = z8.object({
59185
+ command: z8.string(),
59186
+ category: z8.string(),
59187
+ reads: z8.array(z8.string()).default([]),
59188
+ writes: z8.array(z8.string()).default([]),
59189
+ purpose: z8.string().optional()
59190
+ });
59183
59191
  var ToolSchema = z8.object({
59184
59192
  kind: z8.string(),
59185
59193
  description: z8.string().optional(),
59186
59194
  input_artifacts: z8.array(z8.string()).default([]),
59187
59195
  output_artifacts: z8.array(z8.string()).default([]),
59188
59196
  invokable_by: z8.array(z8.string()),
59189
- side_effects: z8.array(z8.string()).default([])
59197
+ side_effects: z8.array(z8.string()).default([]),
59198
+ commands: z8.array(CommandSchema).default([])
59190
59199
  }).passthrough();
59191
59200
 
59192
59201
  // src/schema/validation.ts
@@ -59202,25 +59211,56 @@ var ValidationSchema = z9.object({
59202
59211
 
59203
59212
  // src/schema/workflow.ts
59204
59213
  import { z as z10 } from "zod";
59214
+ var RetrySchema = z10.object({
59215
+ condition: z10.string(),
59216
+ fix_task: z10.string(),
59217
+ revalidate_task: z10.string().optional()
59218
+ });
59219
+ var ExternalParticipantSchema = z10.object({
59220
+ id: z10.string(),
59221
+ kind: z10.enum(["actor", "participant"]),
59222
+ label: z10.string(),
59223
+ description: z10.string().optional()
59224
+ });
59225
+ var WorkflowDelegateStepSchema = z10.object({
59226
+ type: z10.literal("delegate"),
59227
+ description: z10.string().optional(),
59228
+ task: z10.string(),
59229
+ from_agent: z10.string(),
59230
+ group: z10.string().optional(),
59231
+ retry: RetrySchema.optional()
59232
+ }).passthrough();
59233
+ var WorkflowGateStepSchema = z10.object({
59234
+ type: z10.literal("gate"),
59235
+ description: z10.string().optional(),
59236
+ gate_kind: z10.string(),
59237
+ group: z10.string().optional()
59238
+ }).passthrough();
59205
59239
  var WorkflowHandoffStepSchema = z10.object({
59206
59240
  type: z10.literal("handoff"),
59207
59241
  description: z10.string().optional(),
59208
59242
  handoff_kind: z10.string(),
59209
59243
  task: z10.string().optional(),
59210
- from_agent: z10.string().optional()
59244
+ from_agent: z10.string().optional(),
59245
+ group: z10.string().optional(),
59246
+ retry: RetrySchema.optional()
59211
59247
  }).passthrough();
59212
59248
  var WorkflowValidationStepSchema = z10.object({
59213
59249
  type: z10.literal("validation"),
59214
59250
  description: z10.string().optional(),
59215
- validation: z10.string()
59251
+ validation: z10.string(),
59252
+ group: z10.string().optional()
59216
59253
  }).passthrough();
59217
59254
  var WorkflowDecisionStepSchema = z10.object({
59218
59255
  type: z10.literal("decision"),
59219
59256
  description: z10.string().optional(),
59220
59257
  on: z10.string(),
59221
- branches: z10.record(z10.string(), z10.array(z10.string()))
59258
+ branches: z10.record(z10.string(), z10.array(z10.string())),
59259
+ group: z10.string().optional()
59222
59260
  }).passthrough();
59223
59261
  var WorkflowStepSchema = z10.discriminatedUnion("type", [
59262
+ WorkflowDelegateStepSchema,
59263
+ WorkflowGateStepSchema,
59224
59264
  WorkflowHandoffStepSchema,
59225
59265
  WorkflowValidationStepSchema,
59226
59266
  WorkflowDecisionStepSchema
@@ -59229,7 +59269,8 @@ var WorkflowSchema = z10.object({
59229
59269
  description: z10.string().optional(),
59230
59270
  entry_conditions: z10.array(z10.string()).default([]),
59231
59271
  trigger: z10.string().optional(),
59232
- steps: z10.array(WorkflowStepSchema)
59272
+ steps: z10.array(WorkflowStepSchema),
59273
+ external_participants: z10.array(ExternalParticipantSchema).default([])
59233
59274
  }).passthrough();
59234
59275
 
59235
59276
  // src/schema/dsl.ts
@@ -59445,12 +59486,20 @@ function checkReferences(dsl) {
59445
59486
  for (const ref of task.input_artifacts) {
59446
59487
  checkExists(ref, artifactIds, "artifacts", `tasks.${id}.input_artifacts`);
59447
59488
  }
59489
+ for (const ref of task.validations) {
59490
+ checkExists(ref, validationIds, "validations", `tasks.${id}.validations`);
59491
+ }
59448
59492
  }
59449
59493
  for (const [wfId, wf] of Object.entries(dsl.workflow)) {
59450
59494
  checkExists(wfId, workflowIds, "system.default_workflow_order", `workflow.${wfId}`);
59451
59495
  for (let j2 = 0; j2 < wf.steps.length; j2++) {
59452
59496
  const step = wf.steps[j2];
59453
- if (step.type === "handoff") {
59497
+ if (step.type === "delegate") {
59498
+ checkExists(step.task, taskIds, "tasks", `workflow.${wfId}.steps[${j2}].task`);
59499
+ checkExists(step.from_agent, agentIds, "agents", `workflow.${wfId}.steps[${j2}].from_agent`);
59500
+ } else if (step.type === "gate") {
59501
+ checkExists(step.gate_kind, handoffKinds, "handoff_types", `workflow.${wfId}.steps[${j2}].gate_kind`);
59502
+ } else if (step.type === "handoff") {
59454
59503
  if (step.task) {
59455
59504
  checkExists(step.task, taskIds, "tasks", `workflow.${wfId}.steps[${j2}].task`);
59456
59505
  }
@@ -59622,21 +59671,26 @@ var validationCoverageRule = {
59622
59671
  });
59623
59672
  }
59624
59673
  }
59625
- const validationsReferencedInWorkflow = /* @__PURE__ */ new Set();
59674
+ const referencedValidations = /* @__PURE__ */ new Set();
59626
59675
  for (const wf of Object.values(dsl.workflow)) {
59627
59676
  for (const step of wf.steps) {
59628
59677
  if (step.type === "validation") {
59629
- validationsReferencedInWorkflow.add(step.validation);
59678
+ referencedValidations.add(step.validation);
59630
59679
  }
59631
59680
  }
59632
59681
  }
59682
+ for (const task of Object.values(dsl.tasks)) {
59683
+ for (const valId of task.validations) {
59684
+ referencedValidations.add(valId);
59685
+ }
59686
+ }
59633
59687
  for (const [valId, val] of Object.entries(dsl.validations)) {
59634
- if (val.blocking && !validationsReferencedInWorkflow.has(valId)) {
59688
+ if (val.blocking && !referencedValidations.has(valId)) {
59635
59689
  diagnostics.push({
59636
59690
  ruleId: "validation-coverage",
59637
59691
  severity: "warning",
59638
59692
  path: `validations.${valId}`,
59639
- message: `Blocking validation "${valId}" is not referenced in any workflow step`
59693
+ message: `Blocking validation "${valId}" is not referenced in any workflow step or task`
59640
59694
  });
59641
59695
  }
59642
59696
  }
@@ -59846,12 +59900,100 @@ var mergeIntegrityRule = {
59846
59900
  }
59847
59901
  };
59848
59902
 
59903
+ // src/linter/rules/artifact-ownership.ts
59904
+ var artifactOwnershipRule = {
59905
+ id: "artifact-ownership",
59906
+ description: "Ensure execution_step produces/reads operations are consistent with artifact producers/editors/consumers",
59907
+ run(dsl) {
59908
+ const diagnostics = [];
59909
+ for (const [taskId, task] of Object.entries(dsl.tasks)) {
59910
+ if (!task.execution_steps) continue;
59911
+ const agentId = task.target_agent;
59912
+ for (const step of task.execution_steps) {
59913
+ if (step.produces_artifact) {
59914
+ const artifact = dsl.artifacts[step.produces_artifact];
59915
+ if (artifact) {
59916
+ const canWrite = artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
59917
+ if (!canWrite) {
59918
+ diagnostics.push({
59919
+ ruleId: "artifact-ownership",
59920
+ severity: "warning",
59921
+ path: `tasks.${taskId}.execution_steps`,
59922
+ message: `Agent "${agentId}" produces artifact "${step.produces_artifact}" but is not listed in its producers or editors`
59923
+ });
59924
+ }
59925
+ }
59926
+ }
59927
+ if (step.reads_artifact) {
59928
+ const artifact = dsl.artifacts[step.reads_artifact];
59929
+ if (artifact) {
59930
+ const canRead = artifact.consumers.includes(agentId) || artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
59931
+ if (!canRead) {
59932
+ diagnostics.push({
59933
+ ruleId: "artifact-ownership",
59934
+ severity: "warning",
59935
+ path: `tasks.${taskId}.execution_steps`,
59936
+ message: `Agent "${agentId}" reads artifact "${step.reads_artifact}" but is not listed in its producers, editors, or consumers`
59937
+ });
59938
+ }
59939
+ }
59940
+ }
59941
+ }
59942
+ }
59943
+ return diagnostics;
59944
+ }
59945
+ };
59946
+
59947
+ // src/linter/rules/tool-commands.ts
59948
+ var toolCommandsRule = {
59949
+ id: "tool-commands",
59950
+ description: "Validate tool commands: reads/writes reference existing artifacts; writes align with output_artifacts",
59951
+ run(dsl) {
59952
+ const diagnostics = [];
59953
+ for (const [toolId, tool] of Object.entries(dsl.tools)) {
59954
+ for (const cmd of tool.commands) {
59955
+ for (const ref of cmd.reads) {
59956
+ if (!dsl.artifacts[ref]) {
59957
+ diagnostics.push({
59958
+ ruleId: "tool-commands",
59959
+ severity: "error",
59960
+ path: `tools.${toolId}.commands`,
59961
+ message: `Command "${cmd.command}" reads artifact "${ref}" which does not exist`
59962
+ });
59963
+ }
59964
+ }
59965
+ for (const ref of cmd.writes) {
59966
+ if (!dsl.artifacts[ref]) {
59967
+ diagnostics.push({
59968
+ ruleId: "tool-commands",
59969
+ severity: "error",
59970
+ path: `tools.${toolId}.commands`,
59971
+ message: `Command "${cmd.command}" writes artifact "${ref}" which does not exist`
59972
+ });
59973
+ }
59974
+ if (dsl.artifacts[ref] && !tool.output_artifacts.includes(ref)) {
59975
+ diagnostics.push({
59976
+ ruleId: "tool-commands",
59977
+ severity: "warning",
59978
+ path: `tools.${toolId}.commands`,
59979
+ message: `Command "${cmd.command}" writes artifact "${ref}" but tool's output_artifacts does not include it`
59980
+ });
59981
+ }
59982
+ }
59983
+ }
59984
+ }
59985
+ return diagnostics;
59986
+ }
59987
+ };
59988
+
59849
59989
  // src/linter/linter.ts
59850
59990
  var builtinRules = [
59851
59991
  validationCoverageRule,
59852
59992
  toolExecutionRule,
59853
59993
  taskAgentBindingRule,
59854
- mergeIntegrityRule
59994
+ mergeIntegrityRule,
59995
+ artifactOwnershipRule,
59996
+ toolCommandsRule
59855
59997
  ];
59856
59998
  function lint(dsl, rules = builtinRules) {
59857
59999
  const diagnostics = [];
@@ -60024,6 +60166,28 @@ var workflow_handoff_kind_exists_default = (0, import_spectral_core6.createRules
60024
60166
  for (let i3 = 0; i3 < steps.length; i3++) {
60025
60167
  const step = steps[i3];
60026
60168
  const stepPath = [...context.path, "steps", i3];
60169
+ if (step.type === "delegate") {
60170
+ if (step.task && !taskKeys.has(step.task)) {
60171
+ results.push({
60172
+ message: `task "${step.task}" does not exist in tasks`,
60173
+ path: [...stepPath, "task"]
60174
+ });
60175
+ }
60176
+ if (step.from_agent && !agentKeys.has(step.from_agent)) {
60177
+ results.push({
60178
+ message: `from_agent "${step.from_agent}" does not exist in agents`,
60179
+ path: [...stepPath, "from_agent"]
60180
+ });
60181
+ }
60182
+ }
60183
+ if (step.type === "gate") {
60184
+ if (step.gate_kind && !handoffKeys.has(step.gate_kind)) {
60185
+ results.push({
60186
+ message: `gate_kind "${step.gate_kind}" does not exist in handoff_types`,
60187
+ path: [...stepPath, "gate_kind"]
60188
+ });
60189
+ }
60190
+ }
60027
60191
  if (step.type === "handoff") {
60028
60192
  if (step.handoff_kind && !handoffKeys.has(step.handoff_kind)) {
60029
60193
  results.push({
@@ -60237,6 +60401,17 @@ var ruleset = {
60237
60401
  functionOptions: { referenceTo: "artifacts" }
60238
60402
  }
60239
60403
  },
60404
+ "task-validations-ref": {
60405
+ description: "Task validations must reference existing validations",
60406
+ message: "{{error}}",
60407
+ severity: "error",
60408
+ given: "$.tasks.*",
60409
+ then: {
60410
+ field: "validations",
60411
+ function: ref_exists_default,
60412
+ functionOptions: { referenceTo: "validations" }
60413
+ }
60414
+ },
60240
60415
  "validation-target-artifact-ref": {
60241
60416
  description: "Validation target_artifact must reference an existing artifact",
60242
60417
  message: "{{error}}",
@@ -60280,7 +60455,7 @@ var ruleset = {
60280
60455
  },
60281
60456
  // ========== 15.2.5 Handoff integrity ==========
60282
60457
  "workflow-step-refs": {
60283
- description: "Workflow step references (handoff_kind, task, from_agent, validation) must exist",
60458
+ description: "Workflow step references (task, from_agent, gate_kind, handoff_kind, validation) must exist",
60284
60459
  message: "{{error}}",
60285
60460
  severity: "error",
60286
60461
  given: "$.workflow.*",
@@ -60582,7 +60757,23 @@ function buildHandoffTypeContext(dsl, handoffTypeId) {
60582
60757
  function buildWorkflowContext(dsl, workflowId) {
60583
60758
  const wfDef = dsl.workflow[workflowId];
60584
60759
  const workflow = { ...wfDef, id: workflowId };
60585
- const relatedTasks = Object.entries(dsl.tasks).filter(([, t3]) => t3.workflow === workflowId).map(([id, t3]) => ({ ...t3, id }));
60760
+ const stepReferencedTaskIds = /* @__PURE__ */ new Set();
60761
+ for (const step of wfDef.steps) {
60762
+ if (step.type === "delegate") {
60763
+ stepReferencedTaskIds.add(step.task);
60764
+ if (step.retry) {
60765
+ stepReferencedTaskIds.add(step.retry.fix_task);
60766
+ if (step.retry.revalidate_task) stepReferencedTaskIds.add(step.retry.revalidate_task);
60767
+ }
60768
+ } else if (step.type === "handoff" && step.task) {
60769
+ stepReferencedTaskIds.add(step.task);
60770
+ if (step.retry) {
60771
+ stepReferencedTaskIds.add(step.retry.fix_task);
60772
+ if (step.retry.revalidate_task) stepReferencedTaskIds.add(step.retry.revalidate_task);
60773
+ }
60774
+ }
60775
+ }
60776
+ const relatedTasks = Object.entries(dsl.tasks).filter(([id, t3]) => t3.workflow === workflowId || stepReferencedTaskIds.has(id)).map(([id, t3]) => ({ ...t3, id }));
60586
60777
  const agentIds = /* @__PURE__ */ new Set();
60587
60778
  for (const task of relatedTasks) {
60588
60779
  agentIds.add(task.target_agent);
@@ -60591,7 +60782,9 @@ function buildWorkflowContext(dsl, workflowId) {
60591
60782
  }
60592
60783
  }
60593
60784
  for (const step of wfDef.steps) {
60594
- if (step.type === "handoff" && step.from_agent) {
60785
+ if (step.type === "delegate") {
60786
+ agentIds.add(step.from_agent);
60787
+ } else if (step.type === "handoff" && step.from_agent) {
60595
60788
  agentIds.add(step.from_agent);
60596
60789
  }
60597
60790
  if (step.type === "validation") {
@@ -60648,6 +60841,11 @@ function buildWorkflowContext(dsl, workflowId) {
60648
60841
  validationIds.add(step.validation);
60649
60842
  }
60650
60843
  }
60844
+ for (const task of relatedTasks) {
60845
+ for (const valId of task.validations ?? []) {
60846
+ validationIds.add(valId);
60847
+ }
60848
+ }
60651
60849
  const relatedValidations = {};
60652
60850
  for (const id of validationIds) {
60653
60851
  if (dsl.validations[id]) relatedValidations[id] = dsl.validations[id];
@@ -60813,40 +61011,64 @@ function agentAlias(id, agent) {
60813
61011
  }
60814
61012
  function collectReferencedIds(workflow, dsl, relatedTasks) {
60815
61013
  const agents = /* @__PURE__ */ new Set();
61014
+ const auditAgents = /* @__PURE__ */ new Set();
60816
61015
  const tools = /* @__PURE__ */ new Set();
60817
61016
  const artifacts = /* @__PURE__ */ new Set();
60818
61017
  const taskMap = /* @__PURE__ */ new Map();
60819
61018
  for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
61019
+ function collectTaskIds(task) {
61020
+ addAgent(task.target_agent);
61021
+ for (const es of task.execution_steps ?? []) {
61022
+ collectExecutionStepIds(es, tools, artifacts);
61023
+ }
61024
+ }
61025
+ function collectRetryIds(retry) {
61026
+ const fixTask = taskMap.get(retry.fix_task);
61027
+ if (fixTask) collectTaskIds(fixTask);
61028
+ if (retry.revalidate_task) {
61029
+ const revalTask = taskMap.get(retry.revalidate_task);
61030
+ if (revalTask) addAgent(revalTask.target_agent);
61031
+ }
61032
+ }
60820
61033
  for (const step of workflow.steps) {
60821
- if (step.type === "handoff") {
60822
- if (step.from_agent) agents.add(step.from_agent);
61034
+ if (step.type === "delegate") {
61035
+ addAgent(step.from_agent);
61036
+ const task = taskMap.get(step.task);
61037
+ if (task) collectTaskIds(task);
61038
+ if (step.retry) collectRetryIds(step.retry);
61039
+ } else if (step.type === "gate") {
61040
+ } else if (step.type === "handoff") {
61041
+ if (step.from_agent) addAgent(step.from_agent);
60823
61042
  if (step.task) {
60824
61043
  const task = taskMap.get(step.task);
60825
- if (task) {
60826
- agents.add(task.target_agent);
60827
- for (const es of task.execution_steps ?? []) {
60828
- collectExecutionStepIds(es, tools, artifacts);
60829
- }
60830
- }
61044
+ if (task) collectTaskIds(task);
60831
61045
  }
61046
+ if (step.retry) collectRetryIds(step.retry);
60832
61047
  } else if (step.type === "validation") {
60833
61048
  const val = dsl.validations[step.validation];
60834
61049
  if (val) {
60835
- if (val.executor_type === "agent") agents.add(val.executor);
61050
+ if (val.executor_type === "agent") addAgent(val.executor);
60836
61051
  else tools.add(val.executor);
60837
61052
  artifacts.add(val.target_artifact);
60838
61053
  }
60839
- } else if (step.type === "decision") {
60840
61054
  }
60841
61055
  }
60842
- return { agents, tools, artifacts };
61056
+ function addAgent(agentId) {
61057
+ const agent = dsl.agents[agentId];
61058
+ if (agent?.mode === "read-only") {
61059
+ auditAgents.add(agentId);
61060
+ } else {
61061
+ agents.add(agentId);
61062
+ }
61063
+ }
61064
+ return { agents, auditAgents, tools, artifacts };
60843
61065
  }
60844
61066
  function collectExecutionStepIds(es, tools, artifacts) {
60845
61067
  if (es.uses_tool) tools.add(es.uses_tool);
60846
61068
  if (es.produces_artifact) artifacts.add(es.produces_artifact);
60847
61069
  if (es.reads_artifact) artifacts.add(es.reads_artifact);
60848
61070
  }
60849
- function buildParticipants(ids, dsl) {
61071
+ function buildParticipants(ids, externals, dsl) {
60850
61072
  const participants = [];
60851
61073
  const usedAliases = /* @__PURE__ */ new Set();
60852
61074
  function uniqueAlias(preferred) {
@@ -60859,12 +61081,22 @@ function buildParticipants(ids, dsl) {
60859
61081
  usedAliases.add(alias);
60860
61082
  return alias;
60861
61083
  }
61084
+ for (const ep of externals) {
61085
+ const alias = uniqueAlias(sanitizeAlias(ep.id));
61086
+ participants.push({ id: ep.id, alias, label: ep.label, group: "external" });
61087
+ }
60862
61088
  for (const id of ids.agents) {
60863
61089
  const agent = dsl.agents[id];
60864
61090
  if (!agent) continue;
60865
61091
  const alias = uniqueAlias(agentAlias(id, agent));
60866
61092
  participants.push({ id, alias, label: agent.role_name, group: "agents" });
60867
61093
  }
61094
+ for (const id of ids.auditAgents) {
61095
+ const agent = dsl.agents[id];
61096
+ if (!agent) continue;
61097
+ const alias = uniqueAlias(agentAlias(id, agent));
61098
+ participants.push({ id, alias, label: agent.role_name, group: "audit" });
61099
+ }
60868
61100
  for (const id of ids.tools) {
60869
61101
  const tool = dsl.tools[id];
60870
61102
  if (!tool) continue;
@@ -60883,15 +61115,33 @@ function participantAlias(participants, id) {
60883
61115
  const p2 = participants.find((pp) => pp.id === id);
60884
61116
  return p2 ? p2.alias : sanitizeAlias(id);
60885
61117
  }
60886
- function emitParticipants(participants, lines, indent) {
61118
+ function emitParticipants(participants, externals, lines, indent) {
60887
61119
  const groups = {
61120
+ external: [],
60888
61121
  agents: [],
61122
+ audit: [],
60889
61123
  toolchain: [],
60890
61124
  artifacts: []
60891
61125
  };
60892
61126
  for (const p2 of participants) groups[p2.group].push(p2);
61127
+ const externalMap = /* @__PURE__ */ new Map();
61128
+ for (const ep of externals) externalMap.set(ep.id, ep);
61129
+ if (groups.external.length > 0) {
61130
+ lines.push(`${indent}box rgb(255,245,230) External`);
61131
+ for (const p2 of groups.external) {
61132
+ const ep = externalMap.get(p2.id);
61133
+ const keyword = ep?.kind === "actor" ? "actor" : "participant";
61134
+ if (p2.alias === p2.label) {
61135
+ lines.push(`${indent}${keyword} ${p2.alias}`);
61136
+ } else {
61137
+ lines.push(`${indent}${keyword} ${p2.alias} as ${p2.label}`);
61138
+ }
61139
+ }
61140
+ lines.push(`${indent}end`);
61141
+ }
60893
61142
  const groupConfig = [
60894
61143
  { key: "agents", label: "Agents", color: "rgb(200,220,255)" },
61144
+ { key: "audit", label: "Audit", color: "rgb(255,220,220)" },
60895
61145
  { key: "toolchain", label: "Toolchain", color: "rgb(220,255,220)" },
60896
61146
  { key: "artifacts", label: "Artifacts", color: "rgb(255,230,210)" }
60897
61147
  ];
@@ -60967,7 +61217,7 @@ function emitValidationStep(step, participants, dsl, lastFromAgent, lines, inden
60967
61217
  function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
60968
61218
  const branches = Object.entries(step.branches);
60969
61219
  if (branches.length === 0) return;
60970
- const agentAlias2 = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
61220
+ const agentAl = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
60971
61221
  for (let i3 = 0; i3 < branches.length; i3++) {
60972
61222
  const [key, values] = branches[i3];
60973
61223
  if (i3 === 0) {
@@ -60975,21 +61225,95 @@ function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
60975
61225
  } else {
60976
61226
  lines.push(`${indent}else ${key}`);
60977
61227
  }
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(", ")}`);
61228
+ if (agentAl) {
61229
+ lines.push(`${indent} Note over ${agentAl}: ${values.join(", ")}`);
60982
61230
  }
60983
61231
  }
60984
61232
  lines.push(`${indent}end`);
60985
61233
  }
61234
+ function emitDelegateStep(step, participants, dsl, relatedTasks, lines, indent) {
61235
+ const taskMap = /* @__PURE__ */ new Map();
61236
+ for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
61237
+ const task = taskMap.get(step.task);
61238
+ if (!task) return;
61239
+ const fromAlias = participantAlias(participants, step.from_agent);
61240
+ const targetAlias = participantAlias(participants, task.target_agent);
61241
+ lines.push(`${indent}${fromAlias}->>${targetAlias}: delegate ${step.task}`);
61242
+ for (const es of task.execution_steps ?? []) {
61243
+ emitExecutionStep(es, targetAlias, participants, lines, indent);
61244
+ }
61245
+ lines.push(`${indent}${targetAlias}-->>${fromAlias}: ${task.result_handoff}`);
61246
+ }
61247
+ function emitGateStep(step, participants, lastFromAgent, lines, indent) {
61248
+ if (lastFromAgent) {
61249
+ const agentAl = participantAlias(participants, lastFromAgent);
61250
+ lines.push(`${indent}${agentAl}->>${agentAl}: ${step.gate_kind}`);
61251
+ }
61252
+ }
61253
+ function emitRetryBlock(fromAgent, retry, participants, relatedTasks, lines, indent) {
61254
+ const taskMap = /* @__PURE__ */ new Map();
61255
+ for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
61256
+ lines.push(`${indent}opt ${retry.condition}`);
61257
+ const innerIndent = indent + " ";
61258
+ const fixTask = taskMap.get(retry.fix_task);
61259
+ if (fixTask) {
61260
+ const fromAlias = fromAgent ? participantAlias(participants, fromAgent) : null;
61261
+ const targetAlias = participantAlias(participants, fixTask.target_agent);
61262
+ if (fromAlias) {
61263
+ lines.push(`${innerIndent}${fromAlias}->>${targetAlias}: fix ${retry.fix_task}`);
61264
+ }
61265
+ for (const es of fixTask.execution_steps ?? []) {
61266
+ emitExecutionStep(es, targetAlias, participants, lines, innerIndent);
61267
+ }
61268
+ if (fromAlias) {
61269
+ lines.push(`${innerIndent}${targetAlias}-->>${fromAlias}: ${fixTask.result_handoff}`);
61270
+ }
61271
+ }
61272
+ if (retry.revalidate_task) {
61273
+ const revalTask = taskMap.get(retry.revalidate_task);
61274
+ if (revalTask) {
61275
+ const fromAlias = fromAgent ? participantAlias(participants, fromAgent) : null;
61276
+ const revalAlias = participantAlias(participants, revalTask.target_agent);
61277
+ if (fromAlias) {
61278
+ lines.push(`${innerIndent}${fromAlias}->>${revalAlias}: revalidate ${retry.revalidate_task}`);
61279
+ lines.push(`${innerIndent}${revalAlias}-->>${fromAlias}: ${revalTask.result_handoff}`);
61280
+ }
61281
+ }
61282
+ }
61283
+ lines.push(`${indent}end`);
61284
+ }
61285
+ function groupSteps(steps) {
61286
+ const result = [];
61287
+ let currentGroup = null;
61288
+ for (let i3 = 0; i3 < steps.length; i3++) {
61289
+ const step = steps[i3];
61290
+ const group = "group" in step ? step.group : void 0;
61291
+ if (group) {
61292
+ if (currentGroup && currentGroup.group === group) {
61293
+ currentGroup.steps.push({ step, index: i3 });
61294
+ } else {
61295
+ if (currentGroup) result.push(currentGroup);
61296
+ currentGroup = { group, steps: [{ step, index: i3 }] };
61297
+ }
61298
+ } else {
61299
+ if (currentGroup) {
61300
+ result.push(currentGroup);
61301
+ currentGroup = null;
61302
+ }
61303
+ result.push({ group: null, steps: [{ step, index: i3 }] });
61304
+ }
61305
+ }
61306
+ if (currentGroup) result.push(currentGroup);
61307
+ return result;
61308
+ }
60986
61309
  function generateSequenceDiagram(workflow, relatedTasks, dsl) {
60987
61310
  const ids = collectReferencedIds(workflow, dsl, relatedTasks);
60988
- const participants = buildParticipants(ids, dsl);
61311
+ const externals = workflow.external_participants ?? [];
61312
+ const participants = buildParticipants(ids, externals, dsl);
60989
61313
  const lines = [];
60990
61314
  const indent = " ";
60991
61315
  lines.push("sequenceDiagram");
60992
- emitParticipants(participants, lines, indent);
61316
+ emitParticipants(participants, externals, lines, indent);
60993
61317
  lines.push("");
60994
61318
  lines.push(`${indent}rect ${hashToColor(workflow.id, 0.15, 0.95)}`);
60995
61319
  const firstP = participants[0];
@@ -60998,22 +61322,188 @@ function generateSequenceDiagram(workflow, relatedTasks, dsl) {
60998
61322
  const noteLabel = workflow.description ? `${workflow.id} \u2014 ${workflow.description}` : workflow.id;
60999
61323
  lines.push(`${indent}Note over ${firstP.alias},${lastP.alias}: ${noteLabel}`);
61000
61324
  }
61325
+ if (workflow.trigger && externals.some((ep) => ep.kind === "actor")) {
61326
+ const actor = externals.find((ep) => ep.kind === "actor");
61327
+ const actorAlias = participantAlias(participants, actor.id);
61328
+ const firstAgent = participants.find((p2) => p2.group === "agents" || p2.group === "audit");
61329
+ if (firstAgent) {
61330
+ lines.push(`${indent}${actorAlias}->>${firstAgent.alias}: ${workflow.trigger}`);
61331
+ }
61332
+ }
61001
61333
  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);
61334
+ const grouped = groupSteps(workflow.steps);
61335
+ for (const g2 of grouped) {
61336
+ if (g2.group && g2.steps.length > 1) {
61337
+ lines.push("");
61338
+ lines.push(`${indent}par ${g2.group}`);
61339
+ const parIndent = indent + " ";
61340
+ for (let i3 = 0; i3 < g2.steps.length; i3++) {
61341
+ const { step } = g2.steps[i3];
61342
+ if (i3 > 0) lines.push(`${indent}and`);
61343
+ emitStep(step, participants, dsl, relatedTasks, lines, parIndent, lastFromAgent, (a3) => {
61344
+ lastFromAgent = a3;
61345
+ });
61346
+ }
61347
+ lines.push(`${indent}end`);
61348
+ } else {
61349
+ for (const { step } of g2.steps) {
61350
+ lines.push("");
61351
+ emitStep(step, participants, dsl, relatedTasks, lines, indent, lastFromAgent, (a3) => {
61352
+ lastFromAgent = a3;
61353
+ });
61354
+ }
61011
61355
  }
61012
61356
  }
61013
61357
  lines.push("");
61014
61358
  lines.push(`${indent}end`);
61015
61359
  return lines.join("\n");
61016
61360
  }
61361
+ function emitStep(step, participants, dsl, relatedTasks, lines, indent, lastFromAgent, setLastFromAgent) {
61362
+ if (step.type === "delegate") {
61363
+ setLastFromAgent(step.from_agent);
61364
+ emitDelegateStep(step, participants, dsl, relatedTasks, lines, indent);
61365
+ if (step.retry) {
61366
+ emitRetryBlock(step.from_agent, step.retry, participants, relatedTasks, lines, indent);
61367
+ }
61368
+ } else if (step.type === "gate") {
61369
+ emitGateStep(step, participants, lastFromAgent, lines, indent);
61370
+ } else if (step.type === "handoff") {
61371
+ if (step.from_agent) setLastFromAgent(step.from_agent);
61372
+ emitHandoffStep(step, participants, dsl, relatedTasks, lines, indent);
61373
+ if (step.retry) {
61374
+ emitRetryBlock(step.from_agent, step.retry, participants, relatedTasks, lines, indent);
61375
+ }
61376
+ } else if (step.type === "validation") {
61377
+ emitValidationStep(step, participants, dsl, lastFromAgent, lines, indent);
61378
+ } else if (step.type === "decision") {
61379
+ emitDecisionStep(step, participants, lastFromAgent, lines, indent);
61380
+ }
61381
+ }
61382
+
61383
+ // src/renderer/overview-flowchart.ts
61384
+ function collectPhaseOps(dsl, wfId) {
61385
+ const ctx = buildWorkflowContext(dsl, wfId);
61386
+ const wf = dsl.workflow[wfId];
61387
+ const agentOps = /* @__PURE__ */ new Map();
61388
+ const artifactOps = /* @__PURE__ */ new Map();
61389
+ const toolOps = /* @__PURE__ */ new Map();
61390
+ function addOp(map, id, op) {
61391
+ if (!map.has(id)) map.set(id, /* @__PURE__ */ new Set());
61392
+ map.get(id).add(op);
61393
+ }
61394
+ const taskMap = new Map(ctx.relatedTasks.map((t3) => [t3.id, t3]));
61395
+ function collectTaskOps(task) {
61396
+ addOp(agentOps, task.target_agent, "execute");
61397
+ for (const es of task.execution_steps ?? []) {
61398
+ if (es.reads_artifact) addOp(artifactOps, es.reads_artifact, "R");
61399
+ if (es.produces_artifact) addOp(artifactOps, es.produces_artifact, "W");
61400
+ if (es.uses_tool) {
61401
+ const tool = dsl.tools[es.uses_tool];
61402
+ if (tool) {
61403
+ const cats = tool.commands.map((c2) => c2.category).filter((v2, i3, a3) => a3.indexOf(v2) === i3);
61404
+ for (const cat of cats) addOp(toolOps, es.uses_tool, cat);
61405
+ if (cats.length === 0) addOp(toolOps, es.uses_tool, "\u2713");
61406
+ } else {
61407
+ addOp(toolOps, es.uses_tool, "\u2713");
61408
+ }
61409
+ }
61410
+ }
61411
+ }
61412
+ for (const step of wf.steps) {
61413
+ if (step.type === "delegate") {
61414
+ addOp(agentOps, step.from_agent, "delegate");
61415
+ const task = taskMap.get(step.task);
61416
+ if (task) collectTaskOps(task);
61417
+ } else if (step.type === "gate") {
61418
+ } else if (step.type === "handoff") {
61419
+ if (step.from_agent) addOp(agentOps, step.from_agent, "delegate");
61420
+ if (step.task) {
61421
+ const task = taskMap.get(step.task);
61422
+ if (task) collectTaskOps(task);
61423
+ }
61424
+ } else if (step.type === "validation") {
61425
+ const val = dsl.validations[step.validation];
61426
+ if (val) {
61427
+ if (val.executor_type === "agent") {
61428
+ addOp(agentOps, val.executor, "validate");
61429
+ } else {
61430
+ addOp(toolOps, val.executor, "verification");
61431
+ }
61432
+ addOp(artifactOps, val.target_artifact, "V");
61433
+ }
61434
+ }
61435
+ }
61436
+ return { agentOps, artifactOps, toolOps };
61437
+ }
61438
+ function formatOps(ops) {
61439
+ if (!ops || ops.size === 0) return "\u2014";
61440
+ return [...ops].join(", ");
61441
+ }
61442
+ function buildTable(header, rows) {
61443
+ const lines = [];
61444
+ lines.push("| " + header.join(" | ") + " |");
61445
+ lines.push("|" + header.map(() => "---").join("|") + "|");
61446
+ for (const row of rows) {
61447
+ lines.push("| " + row.join(" | ") + " |");
61448
+ }
61449
+ return lines.join("\n");
61450
+ }
61451
+ function generateOverviewFlowchart(dsl) {
61452
+ const workflowOrder = dsl.system.default_workflow_order ?? Object.keys(dsl.workflow);
61453
+ const phases = workflowOrder.filter((id) => dsl.workflow[id]);
61454
+ const phaseData = /* @__PURE__ */ new Map();
61455
+ for (const wfId of phases) {
61456
+ phaseData.set(wfId, collectPhaseOps(dsl, wfId));
61457
+ }
61458
+ const allAgentIds = /* @__PURE__ */ new Set();
61459
+ const allArtifactIds = /* @__PURE__ */ new Set();
61460
+ const allToolIds = /* @__PURE__ */ new Set();
61461
+ for (const ops of phaseData.values()) {
61462
+ for (const id of ops.agentOps.keys()) allAgentIds.add(id);
61463
+ for (const id of ops.artifactOps.keys()) allArtifactIds.add(id);
61464
+ for (const id of ops.toolOps.keys()) allToolIds.add(id);
61465
+ }
61466
+ const sections = [];
61467
+ if (allAgentIds.size > 0) {
61468
+ const header = ["Agent", ...phases];
61469
+ const rows = [];
61470
+ for (const agentId of allAgentIds) {
61471
+ const agent = dsl.agents[agentId];
61472
+ const label = agent ? agent.role_name : agentId;
61473
+ const row = [label];
61474
+ for (const wfId of phases) {
61475
+ row.push(formatOps(phaseData.get(wfId).agentOps.get(agentId)));
61476
+ }
61477
+ rows.push(row);
61478
+ }
61479
+ sections.push("#### Agent \xD7 Phase\n\n" + buildTable(header, rows));
61480
+ }
61481
+ if (allArtifactIds.size > 0) {
61482
+ const header = ["Artifact", ...phases];
61483
+ const rows = [];
61484
+ for (const artId of allArtifactIds) {
61485
+ const row = [artId];
61486
+ for (const wfId of phases) {
61487
+ row.push(formatOps(phaseData.get(wfId).artifactOps.get(artId)));
61488
+ }
61489
+ rows.push(row);
61490
+ }
61491
+ sections.push("#### Artifact \xD7 Phase\n\n" + buildTable(header, rows));
61492
+ }
61493
+ if (allToolIds.size > 0) {
61494
+ const header = ["Tool", ...phases];
61495
+ const rows = [];
61496
+ for (const toolId of allToolIds) {
61497
+ const row = [toolId];
61498
+ for (const wfId of phases) {
61499
+ row.push(formatOps(phaseData.get(wfId).toolOps.get(toolId)));
61500
+ }
61501
+ rows.push(row);
61502
+ }
61503
+ sections.push("#### Tool \xD7 Phase\n\n" + buildTable(header, rows));
61504
+ }
61505
+ return sections.join("\n\n");
61506
+ }
61017
61507
 
61018
61508
  // src/renderer/renderer.ts
61019
61509
  Handlebars.registerHelper("eq", (a3, b3) => a3 === b3);
@@ -61178,14 +61668,39 @@ Handlebars.registerHelper("size", (obj) => {
61178
61668
  });
61179
61669
  Handlebars.registerHelper(
61180
61670
  "sequenceDiagram",
61181
- function() {
61671
+ function(...args) {
61672
+ const opts = args[args.length - 1];
61673
+ const positionalArgs = args.slice(0, -1);
61674
+ if (typeof positionalArgs[0] === "string" && positionalArgs[1]) {
61675
+ const workflowId = positionalArgs[0];
61676
+ const dsl2 = positionalArgs[1];
61677
+ if (!dsl2.workflow[workflowId]) return "";
61678
+ const ctx = buildWorkflowContext(dsl2, workflowId);
61679
+ return generateSequenceDiagram(
61680
+ ctx.workflow,
61681
+ ctx.relatedTasks,
61682
+ dsl2
61683
+ );
61684
+ }
61182
61685
  const workflow = this["workflow"];
61183
61686
  const relatedTasks = this["relatedTasks"];
61184
- const dsl = this["dsl"];
61687
+ const dsl = opts?.hash?.["dsl"] ?? this["dsl"];
61185
61688
  if (!workflow || !dsl) return "";
61186
61689
  return generateSequenceDiagram(workflow, relatedTasks ?? [], dsl);
61187
61690
  }
61188
61691
  );
61692
+ Handlebars.registerHelper(
61693
+ "overviewFlowchart",
61694
+ function(...args) {
61695
+ const positionalArgs = args.slice(0, -1);
61696
+ if (positionalArgs[0] && typeof positionalArgs[0] === "object") {
61697
+ return generateOverviewFlowchart(positionalArgs[0]);
61698
+ }
61699
+ const dsl = this["dsl"];
61700
+ if (!dsl) return "";
61701
+ return generateOverviewFlowchart(dsl);
61702
+ }
61703
+ );
61189
61704
  function getDslSection(dsl, context) {
61190
61705
  const sectionMap = {
61191
61706
  agent: dsl.agents,