@wanbicoi/next-steps 0.1.0 → 0.1.2

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.
@@ -0,0 +1,120 @@
1
+ <!-- Template: copy this to AGENTS.md in a repo that uses next-steps on PATH. -->
2
+
3
+ # Work the graph with next-steps
4
+
5
+ This repo defines its work as one graph in `.next-steps/workflow.json`.
6
+ `next-steps` walks that graph one node at a time: it tells you which nodes are
7
+ legal now, and records the path you take.
8
+
9
+ Pass `--json` to every command.
10
+
11
+ ## Walk
12
+
13
+ 1. **Open a session.**
14
+
15
+ ```sh
16
+ next-steps create --json
17
+ ```
18
+
19
+ The response holds `key` (your task id) and the first `next` list.
20
+
21
+ **Done when:** you have `key` in hand and a non-empty `next` list.
22
+
23
+ 2. **Choose one next node.**
24
+
25
+ Each entry has `node`, `edge`, `title`, `description`, `reviewRequired`, and
26
+ sometimes `condition`. The `condition` is prose telling you when that branch
27
+ applies; you judge it against the task, nothing checks it for you. `edge` is
28
+ derived from `from->to` and is what the log will record.
29
+
30
+ ```json
31
+ {
32
+ "current": { "node": "verify", "title": "Verify" },
33
+ "next": [
34
+ { "edge": "verify->implement", "node": "implement", "title": "Implement",
35
+ "description": "Loop back and fix the failure.",
36
+ "condition": "the build or the tests failed",
37
+ "reviewRequired": true },
38
+ { "edge": "verify->review", "node": "review", "title": "Peer review",
39
+ "description": "Hand the change to review.",
40
+ "condition": "the build and the tests pass",
41
+ "reviewRequired": false }
42
+ ],
43
+ "done": false
44
+ }
45
+ ```
46
+
47
+ **Done when:** exactly one entry is chosen.
48
+
49
+ 3. **If that entry has `reviewRequired: true`, stop and ask.**
50
+
51
+ Prepare everything the node needs — the plan, the diff, the command you are
52
+ about to run — show it to the user, and wait for an explicit yes. Then act.
53
+
54
+ **Done when:** the user said yes. The CLI only reports the flag — nothing
55
+ enforces it. A node without the flag: skip this step.
56
+
57
+ 4. **Do that node's work.**
58
+
59
+ **Done when:** the node's `description` is satisfied — not when you started
60
+ it.
61
+
62
+ 5. **Log the node.**
63
+
64
+ ```sh
65
+ next-steps log --key <key> --node <node> --json
66
+ ```
67
+
68
+ One log per visit, after the work. Log is the only call per node; the
69
+ response already carries the new `next` list, so continue straight from it.
70
+
71
+ **Done when:** exit `0` and the response contains the new `next` list.
72
+
73
+ 6. **Repeat 2–5 until the response says `done: true`.**
74
+
75
+ **Done when:** `done` is true. Stop there; a written summary is its own node
76
+ if the graph wants one.
77
+
78
+ `next-steps next --key <key> --json` returns the same list on demand. Use it when
79
+ you resume rather than during the walk.
80
+
81
+ ## Branches
82
+
83
+ - **`END` is a legal target.** Log it like any node; the session becomes
84
+ `done`. The `next` list also labels it `finish`.
85
+ - **A node whose only move is `END`** finishes the run as soon as you log it.
86
+ The response is already `done: true`; there is no extra step.
87
+ - **Exit `4`** means the move is not legal. The error's `details.legal` is the
88
+ complete list of nodes you can move to; choose from it, or correct the work and
89
+ log the node the graph expects.
90
+ - **Exit `3`** means the key is unknown or `.next-steps/workflow.json` is
91
+ missing — run `next-steps workflow new` if the graph has never been created. A
92
+ key belongs to one task: create a fresh session for a new task.
93
+
94
+ ## Resume
95
+
96
+ A new agent, or the same one after a context reset, rebuilds the task from the
97
+ tool:
98
+
99
+ ```sh
100
+ next-steps steps --key <key> --json # audit trail: seq, node, from, edge, at
101
+ next-steps next --key <key> --json # legal moves now
102
+ ```
103
+
104
+ The `steps` record is the source of truth for what already happened.
105
+
106
+ ## Housekeeping
107
+
108
+ ```sh
109
+ next-steps keys --json # sessions on this machine
110
+ next-steps reset --key <key> --json # delete a finished or abandoned session
111
+ ```
112
+
113
+ `.next-steps/state.db` is local state and is gitignored. The graph,
114
+ `.next-steps/workflow.json`, is source code: commit it with the rest of the repo.
115
+
116
+ ## Exit codes
117
+
118
+ `0` ok · `2` usage, duplicate key, or invalid key · `3` not found ·
119
+ `4` invalid move or unknown node · `5` invalid workflow file. Errors go to
120
+ stderr as `{ "error": { "code", "message", "details" } }`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wanbicoi/next-steps",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Agent-facing workflow walker: log a step, list the next ones.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "dist",
12
12
  "viz/template.html",
13
+ "docs/AGENTS.sample.md",
13
14
  "README.md",
14
15
  "LICENSE"
15
16
  ],
package/viz/template.html CHANGED
@@ -14,6 +14,10 @@
14
14
  --accent: #2563eb;
15
15
  --accent-soft: #eff6ff;
16
16
  --code: #f1f5f9;
17
+ --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "DejaVu Sans",
18
+ sans-serif;
19
+ --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, "DejaVu Sans Mono",
20
+ monospace;
17
21
  }
18
22
  * {
19
23
  box-sizing: border-box;
@@ -24,7 +28,7 @@
24
28
  }
25
29
  body {
26
30
  margin: 0;
27
- font: 13px/1.45 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
31
+ font: 13px/1.5 var(--font-ui);
28
32
  color: var(--text);
29
33
  background: var(--bg);
30
34
  }
@@ -67,54 +71,6 @@
67
71
  color: var(--muted);
68
72
  font-size: 12px;
69
73
  }
70
- #search {
71
- width: 100%;
72
- padding: 7px 9px;
73
- border: 1px solid var(--border);
74
- border-radius: 7px;
75
- font: inherit;
76
- background: var(--bg);
77
- color: var(--text);
78
- outline: none;
79
- }
80
- #search:focus {
81
- border-color: var(--accent);
82
- box-shadow: 0 0 0 2px var(--accent-soft);
83
- }
84
- #workflow-list {
85
- flex: 1;
86
- overflow: auto;
87
- padding: 8px;
88
- }
89
- .wf {
90
- display: block;
91
- width: 100%;
92
- padding: 8px 10px;
93
- margin: 2px 0;
94
- border: 1px solid transparent;
95
- border-radius: 7px;
96
- background: transparent;
97
- text-align: left;
98
- font: inherit;
99
- color: var(--text);
100
- cursor: pointer;
101
- }
102
- .wf:hover {
103
- background: var(--bg);
104
- }
105
- .wf.active {
106
- background: var(--accent-soft);
107
- border-color: #bfdbfe;
108
- }
109
- .wf strong {
110
- display: block;
111
- font-weight: 600;
112
- }
113
- .wf small {
114
- color: var(--muted);
115
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
116
- font-size: 11px;
117
- }
118
74
  #legend {
119
75
  border-top: 1px solid var(--border);
120
76
  padding: 12px 16px 16px;
@@ -155,7 +111,7 @@
155
111
  #subtitle {
156
112
  color: var(--muted);
157
113
  font-size: 12px;
158
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
114
+ font-family: var(--font-mono);
159
115
  }
160
116
  #controls {
161
117
  display: flex;
@@ -186,12 +142,6 @@
186
142
  background: var(--accent);
187
143
  border-color: var(--accent);
188
144
  }
189
- #back {
190
- display: none;
191
- }
192
- #back.visible {
193
- display: inline-block;
194
- }
195
145
  #cy {
196
146
  flex: 1;
197
147
  min-height: 0;
@@ -226,6 +176,7 @@
226
176
  background: var(--code);
227
177
  padding: 1px 4px;
228
178
  border-radius: 4px;
179
+ font-family: var(--font-mono);
229
180
  font-size: 11px;
230
181
  }
231
182
  #details .hint {
@@ -263,25 +214,23 @@
263
214
  <header>
264
215
  <h1>next-steps <span>viewer</span></h1>
265
216
  <p id="count"></p>
266
- <input id="search" type="search" placeholder="Filter workflows" autocomplete="off" />
267
217
  </header>
268
- <nav id="workflow-list"></nav>
269
218
  <section id="legend">
270
219
  <strong>Legend</strong>
271
220
  <div><span class="swatch" style="background:#fff;border-color:#94a3b8"></span> Node</div>
272
- <div><span class="swatch" style="background:#f5f3ff;border-color:#7c3aed"></span> Subgraph</div>
221
+ <div><span class="swatch" style="background:#f5f3ff;border-color:#7c3aed"></span> Group</div>
273
222
  <div><span class="swatch" style="background:#f0fdf4;border-color:#16a34a"></span> Start</div>
223
+ <div><span class="swatch" style="background:#fff;border-color:#f59e0b"></span> Needs review</div>
274
224
  <div><span class="swatch" style="background:#0f172a;border-color:#0f172a;border-radius:50%"></span> END</div>
275
225
  <div>
276
226
  <span class="swatch" style="background:#f59e0b;border-color:#f59e0b;height:3px;border-radius:2px"></span>
277
- Conditional edge
227
+ Conditional move
278
228
  </div>
279
229
  </section>
280
230
  </aside>
281
231
  <main>
282
232
  <header id="toolbar">
283
233
  <div>
284
- <button id="back" type="button">← Back</button>
285
234
  <h2 id="title">Loading…</h2>
286
235
  <div id="subtitle"></div>
287
236
  </div>
@@ -303,10 +252,11 @@
303
252
  </main>
304
253
  <aside id="details">
305
254
  <h3>Workflow viewer</h3>
306
- <p class="muted">Click a node or an edge. Double-click a subgraph node to open it.</p>
255
+ <p class="muted">Click a node or an edge. Each box is a group; nodes marked
256
+ <strong>[review]</strong> need an explicit yes before the work starts.</p>
307
257
  <div class="hint">
308
- The data is generated from <code>test/fixtures/workflows/</code>. Run
309
- <code>bun run viz</code> after editing a graph.
258
+ The data is generated from <code>.next-steps/workflow.json</code>. Run
259
+ <code>bun run viz</code> after editing the graph.
310
260
  </div>
311
261
  </aside>
312
262
  </div>
@@ -328,14 +278,22 @@
328
278
 
329
279
  const $ = (selector) => document.querySelector(selector);
330
280
 
281
+ // Cytoscape draws labels on canvas, so it cannot inherit the page font.
282
+ // Read the same token the CSS uses to keep one source of truth.
283
+ const FONT_UI = getComputedStyle(document.documentElement)
284
+ .getPropertyValue("--font-ui")
285
+ .replace(/\s+/g, " ")
286
+ .trim();
287
+
331
288
  const COLORS = {
332
289
  nodeBg: "#ffffff",
333
290
  nodeBorder: "#94a3b8",
334
291
  nodeText: "#0f172a",
335
- subgraphBg: "#f5f3ff",
336
- subgraphBorder: "#7c3aed",
292
+ groupBg: "#f5f3ff",
293
+ groupBorder: "#7c3aed",
337
294
  startBg: "#f0fdf4",
338
295
  startBorder: "#16a34a",
296
+ reviewBorder: "#f59e0b",
339
297
  endBg: "#0f172a",
340
298
  endText: "#ffffff",
341
299
  edge: "#94a3b8",
@@ -344,7 +302,7 @@
344
302
  };
345
303
 
346
304
  // Customise the graph here. Cytoscape selectors support classes,
347
- // data attributes (`node[type = "subgraph"]`), and states (`:selected`).
305
+ // data attributes, and states (`:selected`).
348
306
  const STYLE = [
349
307
  {
350
308
  selector: "node",
@@ -357,8 +315,9 @@
357
315
  height: "label",
358
316
  padding: 10,
359
317
  label: "data(label)",
318
+ "font-family": FONT_UI,
360
319
  color: COLORS.nodeText,
361
- "font-size": 10,
320
+ "font-size": 12,
362
321
  "text-wrap": "wrap",
363
322
  "text-max-width": "150px",
364
323
  "text-valign": "center",
@@ -366,11 +325,22 @@
366
325
  },
367
326
  },
368
327
  {
369
- selector: "node.subgraph",
328
+ selector: "node.group",
370
329
  style: {
371
- "background-color": COLORS.subgraphBg,
372
- "border-color": COLORS.subgraphBorder,
373
- shape: "round-hexagon",
330
+ "background-color": COLORS.groupBg,
331
+ "background-opacity": 0.7,
332
+ "border-color": COLORS.groupBorder,
333
+ "border-width": 1,
334
+ "border-style": "dashed",
335
+ shape: "round-rectangle",
336
+ label: "data(label)",
337
+ "font-family": FONT_UI,
338
+ "font-size": 13,
339
+ "font-weight": "bold",
340
+ color: COLORS.groupBorder,
341
+ "text-valign": "top",
342
+ "text-halign": "center",
343
+ padding: 26,
374
344
  },
375
345
  },
376
346
  {
@@ -381,6 +351,13 @@
381
351
  "border-width": 3,
382
352
  },
383
353
  },
354
+ {
355
+ selector: "node.review",
356
+ style: {
357
+ "border-color": COLORS.reviewBorder,
358
+ "border-width": 3,
359
+ },
360
+ },
384
361
  {
385
362
  selector: "node.end",
386
363
  style: {
@@ -390,7 +367,8 @@
390
367
  shape: "ellipse",
391
368
  width: 52,
392
369
  height: 52,
393
- "font-size": 11,
370
+ "font-family": FONT_UI,
371
+ "font-size": 12,
394
372
  "font-weight": "bold",
395
373
  },
396
374
  },
@@ -410,7 +388,8 @@
410
388
  "target-arrow-shape": "triangle",
411
389
  "curve-style": "bezier",
412
390
  label: "data(label)",
413
- "font-size": 8,
391
+ "font-family": FONT_UI,
392
+ "font-size": 10,
414
393
  color: "#475569",
415
394
  "text-wrap": "wrap",
416
395
  "text-max-width": "140px",
@@ -437,10 +416,7 @@
437
416
  },
438
417
  },
439
418
  ];
440
-
441
419
  const state = {
442
- current: null,
443
- history: [],
444
420
  labels: true,
445
421
  conditions: true,
446
422
  };
@@ -454,106 +430,81 @@
454
430
  );
455
431
  }
456
432
 
457
- function edgeLabel(edge) {
433
+ function edgeLabel(move) {
458
434
  if (!state.labels) return "";
459
- const parts = [edge.description || ""];
460
- if (state.conditions && edge.condition) parts.push(`when: ${edge.condition}`);
435
+ const parts = [move.description || ""];
436
+ if (state.conditions && move.condition) parts.push(`when: ${move.condition}`);
461
437
  return parts.filter(Boolean).join("\n");
462
438
  }
463
439
 
464
- function renderList() {
465
- const list = $("#workflow-list");
466
- const query = $("#search").value.trim().toLowerCase();
467
- list.innerHTML = "";
468
-
469
- for (const id of DATA.order) {
470
- const workflow = DATA.workflows[id];
471
- const haystack = `${id} ${workflow.title}`.toLowerCase();
472
- if (query && !haystack.includes(query)) continue;
473
-
474
- const button = document.createElement("button");
475
- button.type = "button";
476
- button.className = `wf${id === state.current ? " active" : ""}`;
477
- button.innerHTML = `<strong>${esc(workflow.title)}</strong><small>${esc(id)}</small>`;
478
- button.addEventListener("click", () => openWorkflow(id));
479
- list.appendChild(button);
480
- }
481
-
482
- $("#count").textContent = `${DATA.order.length} workflows`;
483
- }
484
-
485
- function openWorkflow(id, push = true) {
486
- if (!DATA.workflows[id]) return;
487
- if (push && state.current && state.current !== id) state.history.push(state.current);
488
- state.current = id;
489
- render();
490
- }
491
-
492
- function goBack() {
493
- const previous = state.history.pop();
494
- if (!previous) return;
495
- state.current = previous;
496
- render();
497
- }
498
-
499
440
  function render() {
500
- const workflow = DATA.workflows[state.current];
501
- if (!workflow) return;
502
-
441
+ const workflow = DATA.workflow;
503
442
  $("#title").textContent = workflow.title;
504
443
  $("#subtitle").textContent = `${workflow.id} · start: ${workflow.start}`;
505
- $("#back").classList.toggle("visible", state.history.length > 0);
444
+ $("#count").textContent = `${workflow.nodes.length} nodes`;
506
445
  document.title = `${workflow.title} · next-steps`;
507
-
508
- renderList();
509
446
  renderGraph(workflow);
510
447
  }
511
448
 
512
449
  function renderGraph(workflow) {
513
450
  const elements = [];
451
+ const groups = new Map();
452
+ for (const node of workflow.nodes) {
453
+ if (!node.group || groups.has(node.group)) continue;
454
+ groups.set(node.group, `group-${groups.size}`);
455
+ }
456
+
457
+ for (const [label, id] of groups) {
458
+ elements.push({ data: { id, label }, classes: "group" });
459
+ }
514
460
 
515
461
  for (const node of workflow.nodes) {
516
- const classes = [node.type === "subgraph" ? "subgraph" : "node"];
462
+ const classes = ["node"];
517
463
  if (node.id === workflow.start) classes.push("start");
464
+ if (node.reviewRequired) classes.push("review");
518
465
  elements.push({
519
466
  data: {
520
467
  id: node.id,
521
- label: node.title,
468
+ label: node.reviewRequired ? `${node.title} [review]` : node.title,
522
469
  title: node.title,
523
- type: node.type,
524
470
  description: node.description,
525
- workflow: node.workflow || "",
471
+ group: node.group || "",
472
+ reviewRequired: Boolean(node.reviewRequired),
473
+ ...(node.group ? { parent: groups.get(node.group) } : {}),
526
474
  },
527
475
  classes: classes.join(" "),
528
476
  });
529
477
  }
530
478
 
531
- if (workflow.edges.some((edge) => edge.to === "END")) {
479
+ const moves = workflow.nodes.flatMap((node) =>
480
+ node.next.map((move) => ({ from: node.id, ...move })),
481
+ );
482
+
483
+ if (moves.some((move) => move.to === "END")) {
532
484
  elements.push({
533
485
  data: {
534
486
  id: "END",
535
487
  label: "END",
536
488
  title: "END",
537
- type: "end",
538
- description: "This scope is finished.",
489
+ description: "The run is finished.",
539
490
  },
540
491
  classes: "end",
541
492
  });
542
493
  }
543
494
 
544
- for (const edge of workflow.edges) {
495
+ for (const move of moves) {
545
496
  elements.push({
546
497
  data: {
547
- id: edge.id,
548
- source: edge.from,
549
- target: edge.to,
550
- label: edgeLabel(edge),
551
- from: edge.from,
552
- to: edge.to,
553
- description: edge.description,
554
- condition: edge.condition || "",
498
+ id: `${move.from}->${move.to}`,
499
+ source: move.from,
500
+ target: move.to,
501
+ label: edgeLabel(move),
502
+ from: move.from,
503
+ to: move.to,
504
+ description: move.description,
505
+ condition: move.condition || "",
555
506
  },
556
- classes: edge.condition ? "conditional" : "edge",
507
+ classes: move.condition ? "conditional" : "edge",
557
508
  });
558
509
  }
559
510
 
@@ -571,15 +522,12 @@
571
522
  maxZoom: 2.5,
572
523
  });
573
524
 
574
- cy.on("tap", "node", (event) => showNode(event.target));
525
+ cy.on("tap", "node.node", (event) => showNode(event.target));
526
+ cy.on("tap", "node.end", (event) => showNode(event.target));
575
527
  cy.on("tap", "edge", (event) => showEdge(event.target));
576
528
  cy.on("tap", (event) => {
577
529
  if (event.target === cy) showIntro();
578
530
  });
579
- cy.on("dblclick", "node", (event) => {
580
- const workflowId = event.target.data("workflow");
581
- if (workflowId) openWorkflow(workflowId);
582
- });
583
531
 
584
532
  cy.ready(() => runLayout());
585
533
  showIntro();
@@ -624,36 +572,33 @@
624
572
  function showIntro() {
625
573
  $("#details").innerHTML = `
626
574
  <h3>Workflow viewer</h3>
627
- <p class="muted">Click a node or an edge. Double-click a subgraph node to open it.</p>
575
+ <p class="muted">Click a node or an edge. Each box is a group; nodes marked
576
+ <strong>[review]</strong> need an explicit yes before the work starts.</p>
628
577
  <div class="hint">
629
- The data is generated from <code>test/fixtures/workflows/</code>. Run
630
- <code>bun run viz</code> after editing a graph.
578
+ The data is generated from <code>.next-steps/workflow.json</code>. Run
579
+ <code>bun run viz</code> after editing the graph.
631
580
  </div>
632
581
  `;
633
582
  }
634
583
 
635
584
  function showNode(node) {
636
585
  const data = node.data();
637
- const kind = data.type === "subgraph" ? "subgraph" : data.type === "end" ? "END" : "node";
586
+ const group = data.group ? `<dt>Group</dt><dd>${esc(data.group)}</dd>` : "";
587
+ const review = data.reviewRequired
588
+ ? "<dt>Review</dt><dd>Show the plan, wait for an explicit yes, then act.</dd>"
589
+ : "";
638
590
 
639
591
  $("#details").innerHTML = `
640
592
  <h3>${esc(data.title)}</h3>
641
- <div class="muted"><code>${esc(data.id)}</code> · ${esc(kind)}</div>
593
+ <div class="muted"><code>${esc(data.id)}</code>${data.id === "END" ? " · END" : ""}</div>
642
594
  <dl>
643
595
  <dt>Description</dt><dd>${esc(data.description || "—")}</dd>
596
+ ${group}
597
+ ${review}
644
598
  </dl>
645
599
  `;
646
600
 
647
- if (data.type === "subgraph" && data.workflow) {
648
- const button = document.createElement("button");
649
- button.type = "button";
650
- button.className = "primary";
651
- button.textContent = `Open ${data.workflow} →`;
652
- button.addEventListener("click", () => openWorkflow(data.workflow));
653
- $("#details").appendChild(button);
654
- }
655
-
656
- if (data.type !== "end") {
601
+ if (data.id !== "END") {
657
602
  const hint = document.createElement("div");
658
603
  hint.className = "hint";
659
604
  hint.innerHTML = `Log this step with <code>next-steps log --key &lt;key&gt; --node ${esc(
@@ -666,14 +611,13 @@
666
611
  function showEdge(edge) {
667
612
  const data = edge.data();
668
613
  $("#details").innerHTML = `
669
- <h3>Transition ${esc(data.id)}</h3>
670
- <div class="muted"><code>${esc(data.from)}</code> → <code>${esc(data.to)}</code></div>
614
+ <h3>${esc(data.from)} → ${esc(data.to)}</h3>
671
615
  <dl>
672
616
  <dt>Description</dt><dd>${esc(data.description || "—")}</dd>
673
617
  <dt>Condition</dt><dd>${esc(data.condition || "—")}</dd>
674
618
  </dl>
675
619
  <div class="hint">
676
- Conditions are prose. The agent decides; the logged edge is the audit trail.
620
+ Conditions are prose. The agent decides; the logged move is the audit trail.
677
621
  </div>
678
622
  `;
679
623
  }
@@ -682,12 +626,10 @@
682
626
  if (!cy) return;
683
627
  const link = document.createElement("a");
684
628
  link.href = cy.png({ full: true, scale: 2, bg: "#ffffff" });
685
- link.download = `${state.current}.png`;
629
+ link.download = `${DATA.workflow.id}.png`;
686
630
  link.click();
687
631
  }
688
632
 
689
- $("#search").addEventListener("input", renderList);
690
- $("#back").addEventListener("click", goBack);
691
633
  $("#fit").addEventListener("click", () => cy?.fit(undefined, 30));
692
634
  $("#relayout").addEventListener("click", runLayout);
693
635
  $("#png").addEventListener("click", exportPng);
@@ -700,7 +642,6 @@
700
642
  refreshEdgeLabels();
701
643
  });
702
644
 
703
- state.current = DATA.workflows["support-ticket"] ? "support-ticket" : DATA.order[0];
704
645
  render();
705
646
  </script>
706
647
  </body>