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/index.js CHANGED
@@ -58419,18 +58419,27 @@ var TaskSchema = z6.object({
58419
58419
  completion_criteria: z6.array(z6.string()).optional(),
58420
58420
  rules: z6.array(RuleSchema).optional(),
58421
58421
  anti_patterns: z6.array(z6.string()).optional(),
58422
- escalation_criteria: z6.array(EscalationCriterionSchema).optional()
58422
+ escalation_criteria: z6.array(EscalationCriterionSchema).optional(),
58423
+ validations: z6.array(z6.string()).default([])
58423
58424
  }).passthrough();
58424
58425
 
58425
58426
  // src/schema/tool.ts
58426
58427
  import { z as z7 } from "zod";
58428
+ var CommandSchema = z7.object({
58429
+ command: z7.string(),
58430
+ category: z7.string(),
58431
+ reads: z7.array(z7.string()).default([]),
58432
+ writes: z7.array(z7.string()).default([]),
58433
+ purpose: z7.string().optional()
58434
+ });
58427
58435
  var ToolSchema = z7.object({
58428
58436
  kind: z7.string(),
58429
58437
  description: z7.string().optional(),
58430
58438
  input_artifacts: z7.array(z7.string()).default([]),
58431
58439
  output_artifacts: z7.array(z7.string()).default([]),
58432
58440
  invokable_by: z7.array(z7.string()),
58433
- side_effects: z7.array(z7.string()).default([])
58441
+ side_effects: z7.array(z7.string()).default([]),
58442
+ commands: z7.array(CommandSchema).default([])
58434
58443
  }).passthrough();
58435
58444
 
58436
58445
  // src/schema/validation.ts
@@ -58446,25 +58455,56 @@ var ValidationSchema = z8.object({
58446
58455
 
58447
58456
  // src/schema/workflow.ts
58448
58457
  import { z as z9 } from "zod";
58458
+ var RetrySchema = z9.object({
58459
+ condition: z9.string(),
58460
+ fix_task: z9.string(),
58461
+ revalidate_task: z9.string().optional()
58462
+ });
58463
+ var ExternalParticipantSchema = z9.object({
58464
+ id: z9.string(),
58465
+ kind: z9.enum(["actor", "participant"]),
58466
+ label: z9.string(),
58467
+ description: z9.string().optional()
58468
+ });
58469
+ var WorkflowDelegateStepSchema = z9.object({
58470
+ type: z9.literal("delegate"),
58471
+ description: z9.string().optional(),
58472
+ task: z9.string(),
58473
+ from_agent: z9.string(),
58474
+ group: z9.string().optional(),
58475
+ retry: RetrySchema.optional()
58476
+ }).passthrough();
58477
+ var WorkflowGateStepSchema = z9.object({
58478
+ type: z9.literal("gate"),
58479
+ description: z9.string().optional(),
58480
+ gate_kind: z9.string(),
58481
+ group: z9.string().optional()
58482
+ }).passthrough();
58449
58483
  var WorkflowHandoffStepSchema = z9.object({
58450
58484
  type: z9.literal("handoff"),
58451
58485
  description: z9.string().optional(),
58452
58486
  handoff_kind: z9.string(),
58453
58487
  task: z9.string().optional(),
58454
- from_agent: z9.string().optional()
58488
+ from_agent: z9.string().optional(),
58489
+ group: z9.string().optional(),
58490
+ retry: RetrySchema.optional()
58455
58491
  }).passthrough();
58456
58492
  var WorkflowValidationStepSchema = z9.object({
58457
58493
  type: z9.literal("validation"),
58458
58494
  description: z9.string().optional(),
58459
- validation: z9.string()
58495
+ validation: z9.string(),
58496
+ group: z9.string().optional()
58460
58497
  }).passthrough();
58461
58498
  var WorkflowDecisionStepSchema = z9.object({
58462
58499
  type: z9.literal("decision"),
58463
58500
  description: z9.string().optional(),
58464
58501
  on: z9.string(),
58465
- branches: z9.record(z9.string(), z9.array(z9.string()))
58502
+ branches: z9.record(z9.string(), z9.array(z9.string())),
58503
+ group: z9.string().optional()
58466
58504
  }).passthrough();
58467
58505
  var WorkflowStepSchema = z9.discriminatedUnion("type", [
58506
+ WorkflowDelegateStepSchema,
58507
+ WorkflowGateStepSchema,
58468
58508
  WorkflowHandoffStepSchema,
58469
58509
  WorkflowValidationStepSchema,
58470
58510
  WorkflowDecisionStepSchema
@@ -58473,7 +58513,8 @@ var WorkflowSchema = z9.object({
58473
58513
  description: z9.string().optional(),
58474
58514
  entry_conditions: z9.array(z9.string()).default([]),
58475
58515
  trigger: z9.string().optional(),
58476
- steps: z9.array(WorkflowStepSchema)
58516
+ steps: z9.array(WorkflowStepSchema),
58517
+ external_participants: z9.array(ExternalParticipantSchema).default([])
58477
58518
  }).passthrough();
58478
58519
 
58479
58520
  // src/schema/dsl.ts
@@ -59240,12 +59281,20 @@ function checkReferences(dsl) {
59240
59281
  for (const ref of task.input_artifacts) {
59241
59282
  checkExists(ref, artifactIds, "artifacts", `tasks.${id}.input_artifacts`);
59242
59283
  }
59284
+ for (const ref of task.validations) {
59285
+ checkExists(ref, validationIds, "validations", `tasks.${id}.validations`);
59286
+ }
59243
59287
  }
59244
59288
  for (const [wfId, wf] of Object.entries(dsl.workflow)) {
59245
59289
  checkExists(wfId, workflowIds, "system.default_workflow_order", `workflow.${wfId}`);
59246
59290
  for (let j2 = 0; j2 < wf.steps.length; j2++) {
59247
59291
  const step = wf.steps[j2];
59248
- if (step.type === "handoff") {
59292
+ if (step.type === "delegate") {
59293
+ checkExists(step.task, taskIds, "tasks", `workflow.${wfId}.steps[${j2}].task`);
59294
+ checkExists(step.from_agent, agentIds, "agents", `workflow.${wfId}.steps[${j2}].from_agent`);
59295
+ } else if (step.type === "gate") {
59296
+ checkExists(step.gate_kind, handoffKinds, "handoff_types", `workflow.${wfId}.steps[${j2}].gate_kind`);
59297
+ } else if (step.type === "handoff") {
59249
59298
  if (step.task) {
59250
59299
  checkExists(step.task, taskIds, "tasks", `workflow.${wfId}.steps[${j2}].task`);
59251
59300
  }
@@ -59370,21 +59419,26 @@ var validationCoverageRule = {
59370
59419
  });
59371
59420
  }
59372
59421
  }
59373
- const validationsReferencedInWorkflow = /* @__PURE__ */ new Set();
59422
+ const referencedValidations = /* @__PURE__ */ new Set();
59374
59423
  for (const wf of Object.values(dsl.workflow)) {
59375
59424
  for (const step of wf.steps) {
59376
59425
  if (step.type === "validation") {
59377
- validationsReferencedInWorkflow.add(step.validation);
59426
+ referencedValidations.add(step.validation);
59378
59427
  }
59379
59428
  }
59380
59429
  }
59430
+ for (const task of Object.values(dsl.tasks)) {
59431
+ for (const valId of task.validations) {
59432
+ referencedValidations.add(valId);
59433
+ }
59434
+ }
59381
59435
  for (const [valId, val] of Object.entries(dsl.validations)) {
59382
- if (val.blocking && !validationsReferencedInWorkflow.has(valId)) {
59436
+ if (val.blocking && !referencedValidations.has(valId)) {
59383
59437
  diagnostics.push({
59384
59438
  ruleId: "validation-coverage",
59385
59439
  severity: "warning",
59386
59440
  path: `validations.${valId}`,
59387
- message: `Blocking validation "${valId}" is not referenced in any workflow step`
59441
+ message: `Blocking validation "${valId}" is not referenced in any workflow step or task`
59388
59442
  });
59389
59443
  }
59390
59444
  }
@@ -59594,12 +59648,100 @@ var mergeIntegrityRule = {
59594
59648
  }
59595
59649
  };
59596
59650
 
59651
+ // src/linter/rules/artifact-ownership.ts
59652
+ var artifactOwnershipRule = {
59653
+ id: "artifact-ownership",
59654
+ description: "Ensure execution_step produces/reads operations are consistent with artifact producers/editors/consumers",
59655
+ run(dsl) {
59656
+ const diagnostics = [];
59657
+ for (const [taskId, task] of Object.entries(dsl.tasks)) {
59658
+ if (!task.execution_steps) continue;
59659
+ const agentId = task.target_agent;
59660
+ for (const step of task.execution_steps) {
59661
+ if (step.produces_artifact) {
59662
+ const artifact = dsl.artifacts[step.produces_artifact];
59663
+ if (artifact) {
59664
+ const canWrite = artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
59665
+ if (!canWrite) {
59666
+ diagnostics.push({
59667
+ ruleId: "artifact-ownership",
59668
+ severity: "warning",
59669
+ path: `tasks.${taskId}.execution_steps`,
59670
+ message: `Agent "${agentId}" produces artifact "${step.produces_artifact}" but is not listed in its producers or editors`
59671
+ });
59672
+ }
59673
+ }
59674
+ }
59675
+ if (step.reads_artifact) {
59676
+ const artifact = dsl.artifacts[step.reads_artifact];
59677
+ if (artifact) {
59678
+ const canRead = artifact.consumers.includes(agentId) || artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
59679
+ if (!canRead) {
59680
+ diagnostics.push({
59681
+ ruleId: "artifact-ownership",
59682
+ severity: "warning",
59683
+ path: `tasks.${taskId}.execution_steps`,
59684
+ message: `Agent "${agentId}" reads artifact "${step.reads_artifact}" but is not listed in its producers, editors, or consumers`
59685
+ });
59686
+ }
59687
+ }
59688
+ }
59689
+ }
59690
+ }
59691
+ return diagnostics;
59692
+ }
59693
+ };
59694
+
59695
+ // src/linter/rules/tool-commands.ts
59696
+ var toolCommandsRule = {
59697
+ id: "tool-commands",
59698
+ description: "Validate tool commands: reads/writes reference existing artifacts; writes align with output_artifacts",
59699
+ run(dsl) {
59700
+ const diagnostics = [];
59701
+ for (const [toolId, tool] of Object.entries(dsl.tools)) {
59702
+ for (const cmd of tool.commands) {
59703
+ for (const ref of cmd.reads) {
59704
+ if (!dsl.artifacts[ref]) {
59705
+ diagnostics.push({
59706
+ ruleId: "tool-commands",
59707
+ severity: "error",
59708
+ path: `tools.${toolId}.commands`,
59709
+ message: `Command "${cmd.command}" reads artifact "${ref}" which does not exist`
59710
+ });
59711
+ }
59712
+ }
59713
+ for (const ref of cmd.writes) {
59714
+ if (!dsl.artifacts[ref]) {
59715
+ diagnostics.push({
59716
+ ruleId: "tool-commands",
59717
+ severity: "error",
59718
+ path: `tools.${toolId}.commands`,
59719
+ message: `Command "${cmd.command}" writes artifact "${ref}" which does not exist`
59720
+ });
59721
+ }
59722
+ if (dsl.artifacts[ref] && !tool.output_artifacts.includes(ref)) {
59723
+ diagnostics.push({
59724
+ ruleId: "tool-commands",
59725
+ severity: "warning",
59726
+ path: `tools.${toolId}.commands`,
59727
+ message: `Command "${cmd.command}" writes artifact "${ref}" but tool's output_artifacts does not include it`
59728
+ });
59729
+ }
59730
+ }
59731
+ }
59732
+ }
59733
+ return diagnostics;
59734
+ }
59735
+ };
59736
+
59597
59737
  // src/linter/linter.ts
59598
59738
  var builtinRules = [
59599
59739
  validationCoverageRule,
59600
59740
  toolExecutionRule,
59601
59741
  taskAgentBindingRule,
59602
- mergeIntegrityRule
59742
+ mergeIntegrityRule,
59743
+ artifactOwnershipRule,
59744
+ toolCommandsRule
59603
59745
  ];
59604
59746
  function lint(dsl, rules = builtinRules) {
59605
59747
  const diagnostics = [];
@@ -59772,6 +59914,28 @@ var workflow_handoff_kind_exists_default = (0, import_spectral_core6.createRules
59772
59914
  for (let i3 = 0; i3 < steps.length; i3++) {
59773
59915
  const step = steps[i3];
59774
59916
  const stepPath = [...context.path, "steps", i3];
59917
+ if (step.type === "delegate") {
59918
+ if (step.task && !taskKeys.has(step.task)) {
59919
+ results.push({
59920
+ message: `task "${step.task}" does not exist in tasks`,
59921
+ path: [...stepPath, "task"]
59922
+ });
59923
+ }
59924
+ if (step.from_agent && !agentKeys.has(step.from_agent)) {
59925
+ results.push({
59926
+ message: `from_agent "${step.from_agent}" does not exist in agents`,
59927
+ path: [...stepPath, "from_agent"]
59928
+ });
59929
+ }
59930
+ }
59931
+ if (step.type === "gate") {
59932
+ if (step.gate_kind && !handoffKeys.has(step.gate_kind)) {
59933
+ results.push({
59934
+ message: `gate_kind "${step.gate_kind}" does not exist in handoff_types`,
59935
+ path: [...stepPath, "gate_kind"]
59936
+ });
59937
+ }
59938
+ }
59775
59939
  if (step.type === "handoff") {
59776
59940
  if (step.handoff_kind && !handoffKeys.has(step.handoff_kind)) {
59777
59941
  results.push({
@@ -59985,6 +60149,17 @@ var ruleset = {
59985
60149
  functionOptions: { referenceTo: "artifacts" }
59986
60150
  }
59987
60151
  },
60152
+ "task-validations-ref": {
60153
+ description: "Task validations must reference existing validations",
60154
+ message: "{{error}}",
60155
+ severity: "error",
60156
+ given: "$.tasks.*",
60157
+ then: {
60158
+ field: "validations",
60159
+ function: ref_exists_default,
60160
+ functionOptions: { referenceTo: "validations" }
60161
+ }
60162
+ },
59988
60163
  "validation-target-artifact-ref": {
59989
60164
  description: "Validation target_artifact must reference an existing artifact",
59990
60165
  message: "{{error}}",
@@ -60028,7 +60203,7 @@ var ruleset = {
60028
60203
  },
60029
60204
  // ========== 15.2.5 Handoff integrity ==========
60030
60205
  "workflow-step-refs": {
60031
- description: "Workflow step references (handoff_kind, task, from_agent, validation) must exist",
60206
+ description: "Workflow step references (task, from_agent, gate_kind, handoff_kind, validation) must exist",
60032
60207
  message: "{{error}}",
60033
60208
  severity: "error",
60034
60209
  given: "$.workflow.*",
@@ -60295,7 +60470,23 @@ function buildHandoffTypeContext(dsl, handoffTypeId) {
60295
60470
  function buildWorkflowContext(dsl, workflowId) {
60296
60471
  const wfDef = dsl.workflow[workflowId];
60297
60472
  const workflow = { ...wfDef, id: workflowId };
60298
- const relatedTasks = Object.entries(dsl.tasks).filter(([, t3]) => t3.workflow === workflowId).map(([id, t3]) => ({ ...t3, id }));
60473
+ const stepReferencedTaskIds = /* @__PURE__ */ new Set();
60474
+ for (const step of wfDef.steps) {
60475
+ if (step.type === "delegate") {
60476
+ stepReferencedTaskIds.add(step.task);
60477
+ if (step.retry) {
60478
+ stepReferencedTaskIds.add(step.retry.fix_task);
60479
+ if (step.retry.revalidate_task) stepReferencedTaskIds.add(step.retry.revalidate_task);
60480
+ }
60481
+ } else if (step.type === "handoff" && step.task) {
60482
+ stepReferencedTaskIds.add(step.task);
60483
+ if (step.retry) {
60484
+ stepReferencedTaskIds.add(step.retry.fix_task);
60485
+ if (step.retry.revalidate_task) stepReferencedTaskIds.add(step.retry.revalidate_task);
60486
+ }
60487
+ }
60488
+ }
60489
+ const relatedTasks = Object.entries(dsl.tasks).filter(([id, t3]) => t3.workflow === workflowId || stepReferencedTaskIds.has(id)).map(([id, t3]) => ({ ...t3, id }));
60299
60490
  const agentIds = /* @__PURE__ */ new Set();
60300
60491
  for (const task of relatedTasks) {
60301
60492
  agentIds.add(task.target_agent);
@@ -60304,7 +60495,9 @@ function buildWorkflowContext(dsl, workflowId) {
60304
60495
  }
60305
60496
  }
60306
60497
  for (const step of wfDef.steps) {
60307
- if (step.type === "handoff" && step.from_agent) {
60498
+ if (step.type === "delegate") {
60499
+ agentIds.add(step.from_agent);
60500
+ } else if (step.type === "handoff" && step.from_agent) {
60308
60501
  agentIds.add(step.from_agent);
60309
60502
  }
60310
60503
  if (step.type === "validation") {
@@ -60361,6 +60554,11 @@ function buildWorkflowContext(dsl, workflowId) {
60361
60554
  validationIds.add(step.validation);
60362
60555
  }
60363
60556
  }
60557
+ for (const task of relatedTasks) {
60558
+ for (const valId of task.validations ?? []) {
60559
+ validationIds.add(valId);
60560
+ }
60561
+ }
60364
60562
  const relatedValidations = {};
60365
60563
  for (const id of validationIds) {
60366
60564
  if (dsl.validations[id]) relatedValidations[id] = dsl.validations[id];
@@ -60526,40 +60724,64 @@ function agentAlias(id, agent) {
60526
60724
  }
60527
60725
  function collectReferencedIds(workflow, dsl, relatedTasks) {
60528
60726
  const agents = /* @__PURE__ */ new Set();
60727
+ const auditAgents = /* @__PURE__ */ new Set();
60529
60728
  const tools = /* @__PURE__ */ new Set();
60530
60729
  const artifacts = /* @__PURE__ */ new Set();
60531
60730
  const taskMap = /* @__PURE__ */ new Map();
60532
60731
  for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
60732
+ function collectTaskIds(task) {
60733
+ addAgent(task.target_agent);
60734
+ for (const es of task.execution_steps ?? []) {
60735
+ collectExecutionStepIds(es, tools, artifacts);
60736
+ }
60737
+ }
60738
+ function collectRetryIds(retry) {
60739
+ const fixTask = taskMap.get(retry.fix_task);
60740
+ if (fixTask) collectTaskIds(fixTask);
60741
+ if (retry.revalidate_task) {
60742
+ const revalTask = taskMap.get(retry.revalidate_task);
60743
+ if (revalTask) addAgent(revalTask.target_agent);
60744
+ }
60745
+ }
60533
60746
  for (const step of workflow.steps) {
60534
- if (step.type === "handoff") {
60535
- if (step.from_agent) agents.add(step.from_agent);
60747
+ if (step.type === "delegate") {
60748
+ addAgent(step.from_agent);
60749
+ const task = taskMap.get(step.task);
60750
+ if (task) collectTaskIds(task);
60751
+ if (step.retry) collectRetryIds(step.retry);
60752
+ } else if (step.type === "gate") {
60753
+ } else if (step.type === "handoff") {
60754
+ if (step.from_agent) addAgent(step.from_agent);
60536
60755
  if (step.task) {
60537
60756
  const task = taskMap.get(step.task);
60538
- if (task) {
60539
- agents.add(task.target_agent);
60540
- for (const es of task.execution_steps ?? []) {
60541
- collectExecutionStepIds(es, tools, artifacts);
60542
- }
60543
- }
60757
+ if (task) collectTaskIds(task);
60544
60758
  }
60759
+ if (step.retry) collectRetryIds(step.retry);
60545
60760
  } else if (step.type === "validation") {
60546
60761
  const val = dsl.validations[step.validation];
60547
60762
  if (val) {
60548
- if (val.executor_type === "agent") agents.add(val.executor);
60763
+ if (val.executor_type === "agent") addAgent(val.executor);
60549
60764
  else tools.add(val.executor);
60550
60765
  artifacts.add(val.target_artifact);
60551
60766
  }
60552
- } else if (step.type === "decision") {
60553
60767
  }
60554
60768
  }
60555
- return { agents, tools, artifacts };
60769
+ function addAgent(agentId) {
60770
+ const agent = dsl.agents[agentId];
60771
+ if (agent?.mode === "read-only") {
60772
+ auditAgents.add(agentId);
60773
+ } else {
60774
+ agents.add(agentId);
60775
+ }
60776
+ }
60777
+ return { agents, auditAgents, tools, artifacts };
60556
60778
  }
60557
60779
  function collectExecutionStepIds(es, tools, artifacts) {
60558
60780
  if (es.uses_tool) tools.add(es.uses_tool);
60559
60781
  if (es.produces_artifact) artifacts.add(es.produces_artifact);
60560
60782
  if (es.reads_artifact) artifacts.add(es.reads_artifact);
60561
60783
  }
60562
- function buildParticipants(ids, dsl) {
60784
+ function buildParticipants(ids, externals, dsl) {
60563
60785
  const participants = [];
60564
60786
  const usedAliases = /* @__PURE__ */ new Set();
60565
60787
  function uniqueAlias(preferred) {
@@ -60572,12 +60794,22 @@ function buildParticipants(ids, dsl) {
60572
60794
  usedAliases.add(alias);
60573
60795
  return alias;
60574
60796
  }
60797
+ for (const ep of externals) {
60798
+ const alias = uniqueAlias(sanitizeAlias(ep.id));
60799
+ participants.push({ id: ep.id, alias, label: ep.label, group: "external" });
60800
+ }
60575
60801
  for (const id of ids.agents) {
60576
60802
  const agent = dsl.agents[id];
60577
60803
  if (!agent) continue;
60578
60804
  const alias = uniqueAlias(agentAlias(id, agent));
60579
60805
  participants.push({ id, alias, label: agent.role_name, group: "agents" });
60580
60806
  }
60807
+ for (const id of ids.auditAgents) {
60808
+ const agent = dsl.agents[id];
60809
+ if (!agent) continue;
60810
+ const alias = uniqueAlias(agentAlias(id, agent));
60811
+ participants.push({ id, alias, label: agent.role_name, group: "audit" });
60812
+ }
60581
60813
  for (const id of ids.tools) {
60582
60814
  const tool = dsl.tools[id];
60583
60815
  if (!tool) continue;
@@ -60596,15 +60828,33 @@ function participantAlias(participants, id) {
60596
60828
  const p2 = participants.find((pp) => pp.id === id);
60597
60829
  return p2 ? p2.alias : sanitizeAlias(id);
60598
60830
  }
60599
- function emitParticipants(participants, lines, indent) {
60831
+ function emitParticipants(participants, externals, lines, indent) {
60600
60832
  const groups = {
60833
+ external: [],
60601
60834
  agents: [],
60835
+ audit: [],
60602
60836
  toolchain: [],
60603
60837
  artifacts: []
60604
60838
  };
60605
60839
  for (const p2 of participants) groups[p2.group].push(p2);
60840
+ const externalMap = /* @__PURE__ */ new Map();
60841
+ for (const ep of externals) externalMap.set(ep.id, ep);
60842
+ if (groups.external.length > 0) {
60843
+ lines.push(`${indent}box rgb(255,245,230) External`);
60844
+ for (const p2 of groups.external) {
60845
+ const ep = externalMap.get(p2.id);
60846
+ const keyword = ep?.kind === "actor" ? "actor" : "participant";
60847
+ if (p2.alias === p2.label) {
60848
+ lines.push(`${indent}${keyword} ${p2.alias}`);
60849
+ } else {
60850
+ lines.push(`${indent}${keyword} ${p2.alias} as ${p2.label}`);
60851
+ }
60852
+ }
60853
+ lines.push(`${indent}end`);
60854
+ }
60606
60855
  const groupConfig = [
60607
60856
  { key: "agents", label: "Agents", color: "rgb(200,220,255)" },
60857
+ { key: "audit", label: "Audit", color: "rgb(255,220,220)" },
60608
60858
  { key: "toolchain", label: "Toolchain", color: "rgb(220,255,220)" },
60609
60859
  { key: "artifacts", label: "Artifacts", color: "rgb(255,230,210)" }
60610
60860
  ];
@@ -60680,7 +60930,7 @@ function emitValidationStep(step, participants, dsl, lastFromAgent, lines, inden
60680
60930
  function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
60681
60931
  const branches = Object.entries(step.branches);
60682
60932
  if (branches.length === 0) return;
60683
- const agentAlias2 = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
60933
+ const agentAl = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
60684
60934
  for (let i3 = 0; i3 < branches.length; i3++) {
60685
60935
  const [key, values] = branches[i3];
60686
60936
  if (i3 === 0) {
@@ -60688,21 +60938,95 @@ function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
60688
60938
  } else {
60689
60939
  lines.push(`${indent}else ${key}`);
60690
60940
  }
60691
- if (agentAlias2) {
60692
- lines.push(`${indent} Note over ${agentAlias2}: ${values.join(", ")}`);
60693
- } else {
60694
- lines.push(`${indent} Note right of ${participantAlias(participants, [.../* @__PURE__ */ new Set()].join(""))}: ${values.join(", ")}`);
60941
+ if (agentAl) {
60942
+ lines.push(`${indent} Note over ${agentAl}: ${values.join(", ")}`);
60695
60943
  }
60696
60944
  }
60697
60945
  lines.push(`${indent}end`);
60698
60946
  }
60947
+ function emitDelegateStep(step, participants, dsl, relatedTasks, lines, indent) {
60948
+ const taskMap = /* @__PURE__ */ new Map();
60949
+ for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
60950
+ const task = taskMap.get(step.task);
60951
+ if (!task) return;
60952
+ const fromAlias = participantAlias(participants, step.from_agent);
60953
+ const targetAlias = participantAlias(participants, task.target_agent);
60954
+ lines.push(`${indent}${fromAlias}->>${targetAlias}: delegate ${step.task}`);
60955
+ for (const es of task.execution_steps ?? []) {
60956
+ emitExecutionStep(es, targetAlias, participants, lines, indent);
60957
+ }
60958
+ lines.push(`${indent}${targetAlias}-->>${fromAlias}: ${task.result_handoff}`);
60959
+ }
60960
+ function emitGateStep(step, participants, lastFromAgent, lines, indent) {
60961
+ if (lastFromAgent) {
60962
+ const agentAl = participantAlias(participants, lastFromAgent);
60963
+ lines.push(`${indent}${agentAl}->>${agentAl}: ${step.gate_kind}`);
60964
+ }
60965
+ }
60966
+ function emitRetryBlock(fromAgent, retry, participants, relatedTasks, lines, indent) {
60967
+ const taskMap = /* @__PURE__ */ new Map();
60968
+ for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
60969
+ lines.push(`${indent}opt ${retry.condition}`);
60970
+ const innerIndent = indent + " ";
60971
+ const fixTask = taskMap.get(retry.fix_task);
60972
+ if (fixTask) {
60973
+ const fromAlias = fromAgent ? participantAlias(participants, fromAgent) : null;
60974
+ const targetAlias = participantAlias(participants, fixTask.target_agent);
60975
+ if (fromAlias) {
60976
+ lines.push(`${innerIndent}${fromAlias}->>${targetAlias}: fix ${retry.fix_task}`);
60977
+ }
60978
+ for (const es of fixTask.execution_steps ?? []) {
60979
+ emitExecutionStep(es, targetAlias, participants, lines, innerIndent);
60980
+ }
60981
+ if (fromAlias) {
60982
+ lines.push(`${innerIndent}${targetAlias}-->>${fromAlias}: ${fixTask.result_handoff}`);
60983
+ }
60984
+ }
60985
+ if (retry.revalidate_task) {
60986
+ const revalTask = taskMap.get(retry.revalidate_task);
60987
+ if (revalTask) {
60988
+ const fromAlias = fromAgent ? participantAlias(participants, fromAgent) : null;
60989
+ const revalAlias = participantAlias(participants, revalTask.target_agent);
60990
+ if (fromAlias) {
60991
+ lines.push(`${innerIndent}${fromAlias}->>${revalAlias}: revalidate ${retry.revalidate_task}`);
60992
+ lines.push(`${innerIndent}${revalAlias}-->>${fromAlias}: ${revalTask.result_handoff}`);
60993
+ }
60994
+ }
60995
+ }
60996
+ lines.push(`${indent}end`);
60997
+ }
60998
+ function groupSteps(steps) {
60999
+ const result = [];
61000
+ let currentGroup = null;
61001
+ for (let i3 = 0; i3 < steps.length; i3++) {
61002
+ const step = steps[i3];
61003
+ const group = "group" in step ? step.group : void 0;
61004
+ if (group) {
61005
+ if (currentGroup && currentGroup.group === group) {
61006
+ currentGroup.steps.push({ step, index: i3 });
61007
+ } else {
61008
+ if (currentGroup) result.push(currentGroup);
61009
+ currentGroup = { group, steps: [{ step, index: i3 }] };
61010
+ }
61011
+ } else {
61012
+ if (currentGroup) {
61013
+ result.push(currentGroup);
61014
+ currentGroup = null;
61015
+ }
61016
+ result.push({ group: null, steps: [{ step, index: i3 }] });
61017
+ }
61018
+ }
61019
+ if (currentGroup) result.push(currentGroup);
61020
+ return result;
61021
+ }
60699
61022
  function generateSequenceDiagram(workflow, relatedTasks, dsl) {
60700
61023
  const ids = collectReferencedIds(workflow, dsl, relatedTasks);
60701
- const participants = buildParticipants(ids, dsl);
61024
+ const externals = workflow.external_participants ?? [];
61025
+ const participants = buildParticipants(ids, externals, dsl);
60702
61026
  const lines = [];
60703
61027
  const indent = " ";
60704
61028
  lines.push("sequenceDiagram");
60705
- emitParticipants(participants, lines, indent);
61029
+ emitParticipants(participants, externals, lines, indent);
60706
61030
  lines.push("");
60707
61031
  lines.push(`${indent}rect ${hashToColor(workflow.id, 0.15, 0.95)}`);
60708
61032
  const firstP = participants[0];
@@ -60711,22 +61035,188 @@ function generateSequenceDiagram(workflow, relatedTasks, dsl) {
60711
61035
  const noteLabel = workflow.description ? `${workflow.id} \u2014 ${workflow.description}` : workflow.id;
60712
61036
  lines.push(`${indent}Note over ${firstP.alias},${lastP.alias}: ${noteLabel}`);
60713
61037
  }
61038
+ if (workflow.trigger && externals.some((ep) => ep.kind === "actor")) {
61039
+ const actor = externals.find((ep) => ep.kind === "actor");
61040
+ const actorAlias = participantAlias(participants, actor.id);
61041
+ const firstAgent = participants.find((p2) => p2.group === "agents" || p2.group === "audit");
61042
+ if (firstAgent) {
61043
+ lines.push(`${indent}${actorAlias}->>${firstAgent.alias}: ${workflow.trigger}`);
61044
+ }
61045
+ }
60714
61046
  let lastFromAgent;
60715
- for (const step of workflow.steps) {
60716
- lines.push("");
60717
- if (step.type === "handoff") {
60718
- if (step.from_agent) lastFromAgent = step.from_agent;
60719
- emitHandoffStep(step, participants, dsl, relatedTasks, lines, indent);
60720
- } else if (step.type === "validation") {
60721
- emitValidationStep(step, participants, dsl, lastFromAgent, lines, indent);
60722
- } else if (step.type === "decision") {
60723
- emitDecisionStep(step, participants, lastFromAgent, lines, indent);
61047
+ const grouped = groupSteps(workflow.steps);
61048
+ for (const g2 of grouped) {
61049
+ if (g2.group && g2.steps.length > 1) {
61050
+ lines.push("");
61051
+ lines.push(`${indent}par ${g2.group}`);
61052
+ const parIndent = indent + " ";
61053
+ for (let i3 = 0; i3 < g2.steps.length; i3++) {
61054
+ const { step } = g2.steps[i3];
61055
+ if (i3 > 0) lines.push(`${indent}and`);
61056
+ emitStep(step, participants, dsl, relatedTasks, lines, parIndent, lastFromAgent, (a3) => {
61057
+ lastFromAgent = a3;
61058
+ });
61059
+ }
61060
+ lines.push(`${indent}end`);
61061
+ } else {
61062
+ for (const { step } of g2.steps) {
61063
+ lines.push("");
61064
+ emitStep(step, participants, dsl, relatedTasks, lines, indent, lastFromAgent, (a3) => {
61065
+ lastFromAgent = a3;
61066
+ });
61067
+ }
60724
61068
  }
60725
61069
  }
60726
61070
  lines.push("");
60727
61071
  lines.push(`${indent}end`);
60728
61072
  return lines.join("\n");
60729
61073
  }
61074
+ function emitStep(step, participants, dsl, relatedTasks, lines, indent, lastFromAgent, setLastFromAgent) {
61075
+ if (step.type === "delegate") {
61076
+ setLastFromAgent(step.from_agent);
61077
+ emitDelegateStep(step, participants, dsl, relatedTasks, lines, indent);
61078
+ if (step.retry) {
61079
+ emitRetryBlock(step.from_agent, step.retry, participants, relatedTasks, lines, indent);
61080
+ }
61081
+ } else if (step.type === "gate") {
61082
+ emitGateStep(step, participants, lastFromAgent, lines, indent);
61083
+ } else if (step.type === "handoff") {
61084
+ if (step.from_agent) setLastFromAgent(step.from_agent);
61085
+ emitHandoffStep(step, participants, dsl, relatedTasks, lines, indent);
61086
+ if (step.retry) {
61087
+ emitRetryBlock(step.from_agent, step.retry, participants, relatedTasks, lines, indent);
61088
+ }
61089
+ } else if (step.type === "validation") {
61090
+ emitValidationStep(step, participants, dsl, lastFromAgent, lines, indent);
61091
+ } else if (step.type === "decision") {
61092
+ emitDecisionStep(step, participants, lastFromAgent, lines, indent);
61093
+ }
61094
+ }
61095
+
61096
+ // src/renderer/overview-flowchart.ts
61097
+ function collectPhaseOps(dsl, wfId) {
61098
+ const ctx = buildWorkflowContext(dsl, wfId);
61099
+ const wf = dsl.workflow[wfId];
61100
+ const agentOps = /* @__PURE__ */ new Map();
61101
+ const artifactOps = /* @__PURE__ */ new Map();
61102
+ const toolOps = /* @__PURE__ */ new Map();
61103
+ function addOp(map, id, op) {
61104
+ if (!map.has(id)) map.set(id, /* @__PURE__ */ new Set());
61105
+ map.get(id).add(op);
61106
+ }
61107
+ const taskMap = new Map(ctx.relatedTasks.map((t3) => [t3.id, t3]));
61108
+ function collectTaskOps(task) {
61109
+ addOp(agentOps, task.target_agent, "execute");
61110
+ for (const es of task.execution_steps ?? []) {
61111
+ if (es.reads_artifact) addOp(artifactOps, es.reads_artifact, "R");
61112
+ if (es.produces_artifact) addOp(artifactOps, es.produces_artifact, "W");
61113
+ if (es.uses_tool) {
61114
+ const tool = dsl.tools[es.uses_tool];
61115
+ if (tool) {
61116
+ const cats = tool.commands.map((c2) => c2.category).filter((v2, i3, a3) => a3.indexOf(v2) === i3);
61117
+ for (const cat of cats) addOp(toolOps, es.uses_tool, cat);
61118
+ if (cats.length === 0) addOp(toolOps, es.uses_tool, "\u2713");
61119
+ } else {
61120
+ addOp(toolOps, es.uses_tool, "\u2713");
61121
+ }
61122
+ }
61123
+ }
61124
+ }
61125
+ for (const step of wf.steps) {
61126
+ if (step.type === "delegate") {
61127
+ addOp(agentOps, step.from_agent, "delegate");
61128
+ const task = taskMap.get(step.task);
61129
+ if (task) collectTaskOps(task);
61130
+ } else if (step.type === "gate") {
61131
+ } else if (step.type === "handoff") {
61132
+ if (step.from_agent) addOp(agentOps, step.from_agent, "delegate");
61133
+ if (step.task) {
61134
+ const task = taskMap.get(step.task);
61135
+ if (task) collectTaskOps(task);
61136
+ }
61137
+ } else if (step.type === "validation") {
61138
+ const val = dsl.validations[step.validation];
61139
+ if (val) {
61140
+ if (val.executor_type === "agent") {
61141
+ addOp(agentOps, val.executor, "validate");
61142
+ } else {
61143
+ addOp(toolOps, val.executor, "verification");
61144
+ }
61145
+ addOp(artifactOps, val.target_artifact, "V");
61146
+ }
61147
+ }
61148
+ }
61149
+ return { agentOps, artifactOps, toolOps };
61150
+ }
61151
+ function formatOps(ops) {
61152
+ if (!ops || ops.size === 0) return "\u2014";
61153
+ return [...ops].join(", ");
61154
+ }
61155
+ function buildTable(header, rows) {
61156
+ const lines = [];
61157
+ lines.push("| " + header.join(" | ") + " |");
61158
+ lines.push("|" + header.map(() => "---").join("|") + "|");
61159
+ for (const row of rows) {
61160
+ lines.push("| " + row.join(" | ") + " |");
61161
+ }
61162
+ return lines.join("\n");
61163
+ }
61164
+ function generateOverviewFlowchart(dsl) {
61165
+ const workflowOrder = dsl.system.default_workflow_order ?? Object.keys(dsl.workflow);
61166
+ const phases = workflowOrder.filter((id) => dsl.workflow[id]);
61167
+ const phaseData = /* @__PURE__ */ new Map();
61168
+ for (const wfId of phases) {
61169
+ phaseData.set(wfId, collectPhaseOps(dsl, wfId));
61170
+ }
61171
+ const allAgentIds = /* @__PURE__ */ new Set();
61172
+ const allArtifactIds = /* @__PURE__ */ new Set();
61173
+ const allToolIds = /* @__PURE__ */ new Set();
61174
+ for (const ops of phaseData.values()) {
61175
+ for (const id of ops.agentOps.keys()) allAgentIds.add(id);
61176
+ for (const id of ops.artifactOps.keys()) allArtifactIds.add(id);
61177
+ for (const id of ops.toolOps.keys()) allToolIds.add(id);
61178
+ }
61179
+ const sections = [];
61180
+ if (allAgentIds.size > 0) {
61181
+ const header = ["Agent", ...phases];
61182
+ const rows = [];
61183
+ for (const agentId of allAgentIds) {
61184
+ const agent = dsl.agents[agentId];
61185
+ const label = agent ? agent.role_name : agentId;
61186
+ const row = [label];
61187
+ for (const wfId of phases) {
61188
+ row.push(formatOps(phaseData.get(wfId).agentOps.get(agentId)));
61189
+ }
61190
+ rows.push(row);
61191
+ }
61192
+ sections.push("#### Agent \xD7 Phase\n\n" + buildTable(header, rows));
61193
+ }
61194
+ if (allArtifactIds.size > 0) {
61195
+ const header = ["Artifact", ...phases];
61196
+ const rows = [];
61197
+ for (const artId of allArtifactIds) {
61198
+ const row = [artId];
61199
+ for (const wfId of phases) {
61200
+ row.push(formatOps(phaseData.get(wfId).artifactOps.get(artId)));
61201
+ }
61202
+ rows.push(row);
61203
+ }
61204
+ sections.push("#### Artifact \xD7 Phase\n\n" + buildTable(header, rows));
61205
+ }
61206
+ if (allToolIds.size > 0) {
61207
+ const header = ["Tool", ...phases];
61208
+ const rows = [];
61209
+ for (const toolId of allToolIds) {
61210
+ const row = [toolId];
61211
+ for (const wfId of phases) {
61212
+ row.push(formatOps(phaseData.get(wfId).toolOps.get(toolId)));
61213
+ }
61214
+ rows.push(row);
61215
+ }
61216
+ sections.push("#### Tool \xD7 Phase\n\n" + buildTable(header, rows));
61217
+ }
61218
+ return sections.join("\n\n");
61219
+ }
60730
61220
 
60731
61221
  // src/renderer/renderer.ts
60732
61222
  Handlebars.registerHelper("eq", (a3, b3) => a3 === b3);
@@ -60891,14 +61381,39 @@ Handlebars.registerHelper("size", (obj) => {
60891
61381
  });
60892
61382
  Handlebars.registerHelper(
60893
61383
  "sequenceDiagram",
60894
- function() {
61384
+ function(...args) {
61385
+ const opts = args[args.length - 1];
61386
+ const positionalArgs = args.slice(0, -1);
61387
+ if (typeof positionalArgs[0] === "string" && positionalArgs[1]) {
61388
+ const workflowId = positionalArgs[0];
61389
+ const dsl2 = positionalArgs[1];
61390
+ if (!dsl2.workflow[workflowId]) return "";
61391
+ const ctx = buildWorkflowContext(dsl2, workflowId);
61392
+ return generateSequenceDiagram(
61393
+ ctx.workflow,
61394
+ ctx.relatedTasks,
61395
+ dsl2
61396
+ );
61397
+ }
60895
61398
  const workflow = this["workflow"];
60896
61399
  const relatedTasks = this["relatedTasks"];
60897
- const dsl = this["dsl"];
61400
+ const dsl = opts?.hash?.["dsl"] ?? this["dsl"];
60898
61401
  if (!workflow || !dsl) return "";
60899
61402
  return generateSequenceDiagram(workflow, relatedTasks ?? [], dsl);
60900
61403
  }
60901
61404
  );
61405
+ Handlebars.registerHelper(
61406
+ "overviewFlowchart",
61407
+ function(...args) {
61408
+ const positionalArgs = args.slice(0, -1);
61409
+ if (positionalArgs[0] && typeof positionalArgs[0] === "object") {
61410
+ return generateOverviewFlowchart(positionalArgs[0]);
61411
+ }
61412
+ const dsl = this["dsl"];
61413
+ if (!dsl) return "";
61414
+ return generateOverviewFlowchart(dsl);
61415
+ }
61416
+ );
60902
61417
  function getDslSection(dsl, context) {
60903
61418
  const sectionMap = {
60904
61419
  agent: dsl.agents,
@@ -61140,6 +61655,7 @@ export {
61140
61655
  ArtifactSchema,
61141
61656
  BaseResolveError,
61142
61657
  CONTEXT_TYPES,
61658
+ CommandSchema,
61143
61659
  ConfigLoadError,
61144
61660
  ContextTypeSchema,
61145
61661
  DslLoadError,